Search code examples
rggplot2patchwork

extracting plots from list and add them together to use in patchwork library


I would like to use the patchwork library to combine plots. but my plots are saved in a list. Consider the code below:

library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))

plots_list <- list(p1, p2)

if I use

patchwork::wrap_plots(plots_list )

The following figure will be generated in which I won't have any control over the space between plots

enter image description here

However, if I want to add space between plots, I need to run the code below:

  p1 + plot_spacer() + p2  + plot_layout(widths = c(6, -1 ,6))

Therefore, I looking for a way to extract plots from the list (plots_list) and then add "+" them and combine them in the form above


Solution

  • A second option would be to use the design argument, e.g. design="A#B" will add a spacer between your plots and of course could you do something like paste(LETTERS[seq(length(plots_list))], collapse = "#") to create the design string programatically.

    library(ggplot2)
    library(patchwork)
    p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
    p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
    
    plots_list <- list(p1, p2)
    
    design <- "A#B"
    
    patchwork::wrap_plots(plots_list) + plot_layout(widths = c(6, -1, 6), design = design)
    

    UPDATE Already guessed that you want more than two plots. Especially with multiple rows this a bit tricky and requires some work. The following is a basic approach using a custom function to create the design string based on the desired number of rows.

    library(ggplot2)
    library(patchwork)
    p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
    p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
    
    plots_list <- list(p1, p2, p1, p2, p1)
    
    make_design <- function(x, nrows) {
      np <- length(x)
        
      ncols <- ceiling(np / nrows)
    
      design <- LETTERS[seq(np)]
      if (np %% 2 == 1) design <- c(design, rep("#", nrows * ncols - np))
      
      design <- split(design, rep(seq(nrows), each = ncols))
      design <- vapply(design, paste, collapse = "#", FUN.VALUE = character(1))
      design <- paste(design, collapse = "\n")
      
      return(design)
    }
    
    design <- make_design(plots_list, 3)
    
    patchwork::wrap_plots(plots_list) + plot_layout(widths = c(6, -1, 6), design = design)
    

    
    design <- make_design(plots_list, 2)
    
    patchwork::wrap_plots(plots_list) + plot_layout(widths = c(6, -1, 6, -1, 6), design = design)