3

I am trying to generate a multi-page pdf of a grid of ggplots from a list of ggplots. I have tried very many ways to do this and have not succeeded. Here is a reproducible equivalent to what I have been working with:

library(ggplot2)

# generate a data frame w same structure as the one I'm working with
time <- c(1:10)
veclist <- list()
veclist[[1]] <- time

for (i in 2:25){
  veclist[[i]] <- as.vector(c(runif(10,-2,2)))
}

d <- as.data.frame(do.call(rbind, veclist))
d <- as.data.frame(t(d))

colnames(d)[1] <- "time"
for (i in 2:length(d)){
  colnames(d)[i] <- paste("name",i,sep=" ")
}

# for a common axis
numericvalues <- d[,2:length(d)]

# generate plot(s)

name_list = paste("`",names(d),"`",sep="")

plot_list = list()
for (i in 2:length(d)) {
  p = ggplot(d, aes_string(x=name_list[[1]], y=name_list[[i]])) +
    geom_point() +
    labs(x="time",title=paste(strwrap(names(d[i]), width = 30),collapse = "\n")) +
    theme(plot.title = element_text(size=10,hjust = 0.5),axis.text.x=element_text(size=6)) +
    coord_cartesian(ylim = c(min(numericvalues, na.rm = TRUE), max(numericvalues, na.rm = TRUE)))
  plot_list[[i]] = p
}

What I am looking for would generate a multi-page pdf grid of the plots in plot_list (ideally with 3 columns, 4 rows of plots per page).

A few things I have tried:

pdf("test.pdf")
do.call("marrangeGrob",c(plot_list,ncol=3,nrow=2))

produces an unreadable pdf file.

pdf("test.pdf")
do.call("grid.arrange",c(plot_list))

returns only 'grobs' allowed in "gList" error.

jlotus
  • 41
  • 1
  • 3

3 Answers3

3

This one produces a multipage layout:

library(gridExtra)
...
plot_list = list()
for (i in 2:length(d)) {
  p = ggplot(...)
  plot_list[[i]] = ggplotGrob(p)
}
class(plot_list) <- c("arrangelist", class(plot_list))
ggsave("multipage.pdf", plot_list)
akond
  • 15,865
  • 4
  • 35
  • 55
3

your plot list seems to have a missing item. Here's a minimal example

library(ggplot2)

pl <- replicate(13, ggplot(), simplify = FALSE)

ggsave("mp.pdf", gridExtra::marrangeGrob(grobs = pl, nrow=3, ncol=2))

Notes:

  • you were missing dev.off() hence the invalid pdf
  • do.call is no longer necessary in (m)arrangeGrob, use the grobs argument
baptiste
  • 75,767
  • 19
  • 198
  • 294
  • Of course, the way I generated the list of plots meant that the first item in the list was NULL. I can't believe I missed that – thank you! – jlotus Oct 30 '17 at 13:45
2

Here's a solution with gridExtra and tidyr

(i) transform the wide data to long-format, and split into a list of data.frame based on each name:

library(tidyr)
df <- d %>% gather(var, val, -time)
df_list <- split(df, df$var)

(ii) plot for each name with lapply function

plots <- lapply(names(df_list), function(x){
               ggplot(df_list[[x]], aes(time, val)) + 
               geom_point() + 
               labs(x="time", title=x)
               })

(iii) using gridExtra to print 12 plots each on two pages of the pdf:

library(gridExtra)
pdf("something.pdf")
do.call(grid.arrange, c(plots[1:12], nrow=4))
do.call(grid.arrange, c(plots[13:24], nrow=4))
dev.off()
Adam Quek
  • 6,973
  • 1
  • 17
  • 23