Search code examples
rggplot2patchwork

How to get patchwork to set different widths of a faceted ggplot


I can't get patchwork to set different widths of a faceted ggplot()

library(tidyverse)
library(patchwork)

mtcars$grp <- LETTERS[1:8] %>% 
  rep(each = 4)

mtcars$let_grp <- 1:3 %>% 
  rep(c(12, 12, 8))

p1 <- mtcars %>% 
  filter(
    let_grp == 1
    ) %>% 
  ggplot(
    aes(wt, mpg)
  ) +
  geom_point() +
  facet_wrap(~grp, nrow = 1)

p2 <- mtcars %>% 
  filter(
    let_grp == 2
  ) %>% 
  ggplot(
    aes(wt, mpg)
  ) +
  geom_point() +
  facet_wrap(~grp, nrow = 1)

p3 <- mtcars %>% 
  filter(
    let_grp == 3
  ) %>% 
  ggplot(
    aes(wt, mpg)
  ) +
  geom_point() +
  facet_wrap(~grp, nrow = 1)

plot_layout() works to make the subplots different heights

p1 / p2 / p3 +
  plot_layout(
    heights = c(2, 2, .5)
    )

enter image description here

But if I want the third plot to be less wide, the same strategy fails:

p1 / p2 / p3 +
  plot_layout(
    widths = c(2, 2, .5)
    )

enter image description here

How can I make the third plot half as wide as the preceding plots in a patchwork?


Solution

  • The widths= argument sets the relative width per column. And as your patchwork has only one column all three plots will have the same width.

    One option which allows for more flexibility to place the plots and/or to set the width or height would be to use the design= argument of plot_layout or wrap_plots.

    In the code below I use the design= argument to specify a "two-column" grid-layout, where the first (=A) and second plot (=B) should span both columns or the full row whereas the third plot should only span one column, where the # serves as a placeholder filled with an empty plot.

    In the code below I simplified a bit by putting the three plots in a list which allows to use wrap_plot. But the same approach works with plot_layout).

    library(tidyverse)
    library(patchwork)
    
    mtcars$grp <- LETTERS[1:8] %>%
      rep(each = 4)
    
    mtcars$let_grp <- 1:3 %>%
      rep(c(12, 12, 8))
    
    p_list <- mtcars %>%
      split(.$let_grp) %>%
      lapply(\(x)
      ggplot(
        x,
        aes(wt, mpg)
      ) +
        geom_point() +
        facet_wrap(~grp, nrow = 1))
    
    design <- "
    AA
    BB
    C#
    "
    
    p_list %>% 
      wrap_plots(ncol = 1, design = design)