rggplot2patchwork

patchwork's operations on the legend position of a subgraph during merging


In the most straightforward case, the patchwork does a good job of pairing its two panels, but it also seems to ignore the subdiagram's specification of the location of the legend legend.box.spacing:

library(ggplot2)

p <- ggplot(mtcars, aes(wt, mpg))
p + geom_point(aes(colour = factor(cyl)))


p1 <- p + geom_point(aes(colour = cyl))+
  theme(legend.box.spacing = unit(20, 'pt'))

p2 <- p + geom_point(aes(colour = cyl*100))+
  theme(legend.box.spacing = unit(20, 'pt'))

patchwork::wrap_plots(p1, p2, ncol = 1)

enter image description here

This should align the overall width of the two figures (use free):

At this time the legend and panel should be positioned according to their respective settings.

patchwork::wrap_plots(free(p1), free(p2), ncol = 1)

enter image description here

The result with collect is very close to the expected result. But it doesn't align with the respective subgraphs, which is also not appropriate.

patchwork::wrap_plots(p1, p2, ncol = 1, guides = 'collect')

enter image description here

So is there a way to be able to align the panels and at the same time make sure that the legend of each subfigure is fixed to its own panel position as specified?

#Edit1:

Problems arise when there are multiple levels of wrap_plots.

In my practical use, it is the merging process of multiple raster data that is not aligned, should I avoid using wrap_plots multiple times?

The following code is my reproduction of the process:

library(ggplot)
library(terra)
library(tidyterra)
library(patchwork)
# raster data
r1 <- rast(nrow = 10, ncol = 10)
values(r1) <- 1:ncell(r1)
r2 <- r1 * r1

rr <- c(r1, r2) |>
  `names<-`(c("r1", "r2"))

p1 <- ggplot() +
  geom_spatraster(data = rr) +
  facet_wrap(~lyr)

p2 <- ggplot() +
  geom_spatraster(data = r1) +
  facet_wrap(~lyr)

p3 <- ggplot() +
  geom_spatraster(data = rr / 10) +
  facet_wrap(~lyr)

p4 <- ggplot() +
  geom_spatraster(data = r2) +
  facet_wrap(~lyr)

design = 'aab
          ccd'

patchwork::wrap_plots(p1, p2, p3, p4, ncol = 2, design = design) &
  theme(
    legend.box.background = element_rect(color = 'red'),
    legend.justification = 'left'
  )

Everything is fine, left aligned as expected. enter image description here

BUT: Even & not * fails to work on all subgraphs.

sub1 <- wrap_plots(p1, p2, design = 'aab')
sub2 <- wrap_plots(p3, p4, design = 'aab')

wrap_plots(sub1, sub2, ncol = 1) &
  theme(
    legend.box.background = element_rect(color = 'blue'),
    legend.justification = 'left'
  )

enter image description here


Solution

  • One option to achieve your desired result would be to set the justification of both legends to "left":

    Note: Just for the reprex I added a red outline around the legend boxes.

    library(ggplot2)
    library(patchwork)
    
    p <- ggplot(mtcars, aes(wt, mpg))
    
    p1 <- p + geom_point(aes(colour = cyl))
    p2 <- p + geom_point(aes(colour = cyl * 100))
    
    patchwork::wrap_plots(p1, p2, ncol = 1) &
      theme(
        legend.box.background = element_rect(color = "red"),
        legend.box.spacing = unit(20, "pt"),
        legend.justification.right = "left"
      )