rggplot2gridextra

List of plots arranged in a particular layout in a multipage PDF not working


Suppose that out of a loop I am getting a particular set of plots that I am saving in a list of plots like in my reproducible example.

plot_list = list()

for (i in 1:5){

dummy1 = ggplot(iris, aes(x = Petal.Length)) +
  geom_histogram()

dummy2 = ggplot(iris, aes(x = Petal.Length, color=Species)) +
  geom_boxplot()

dummy3 = ggplot(iris, aes(x = Petal.Length, y=Petal.Width, color=Species)) +
  geom_point()

plot_list[[length(plot_list)+1]] = list(dummy1,dummy2,dummy3) 

}

After the iteration, once I have the plot list ready, I want to create a single pdf page with a particular layout matrix passed into every page. Following different posts I´ve tried this code:

lay = rbind (c(1,1,2,2),
             c(1,1,3,3),
             c(1,1,3,3))


grDevices::cairo_pdf("plots.pdf", onefile = TRUE)
for (i in seq(length(plot_list))) {
  do.call('marrangeGrob',list(plot_list[[i]], layout_matrix=lay))  
}
dev.off()

Unfortunately it only returns a blank pdf with a single page. Any help is appreciated.

UPDATE: Very importantly, my example serves as a reproducible example but its structure cannot be modified. The reason it comes out of a for is because in my original code comes from a foreach so the answer requires to be compatible with the structure I am proposing.


Solution

  • To plot ggplot's or other grid graphics then an explicit print is required: use grid::grid.draw (see FAQ 7.22).

    Additionally, using marrangeGrob can add an extra newpage; this fix unfortunately has an empty page at the start but this still works. Or you could move the marrangeGrob outside of the pdf call ... if this fits with our workflow.

    library(ggplot2)
    library(gridExtra)
    library(grid)
    
    # Baptiste's fix
    # if your example in your question represents your real example then you 
    # could use `arrangeGrob` and avoid some of the newpage tweaks
    grid.draw.arrangelist <- function(x, ...) {
      for(ii in seq_along(x)){
        if(ii>1) grid.newpage() 
         grid.draw(x[[ii]])
    }
    }
    
    # Output plot
    grDevices::cairo_pdf("plots.pdf", onefile = TRUE)
    
    for (i in seq_along(plot_list)) {
      
      p <- marrangeGrob(grobs=plot_list[[i]], 
                        layout_matrix=lay, 
                        top = quote(paste("page", i, "of", length(plot_list))))
      grid::grid.draw(p) # need to be explicitly drawn 
      
      if(i < length(plot_list)) grid.newpage() # so plots are not drawn over each other
    }
    
    dev.off()