Saving Multiple graphs in 1 pdf page from a for loop in R

2.4k views Asked by At

Please assume any dataset. Situation: I am running a for loop on the all independent variables to create a relationship(scatter) plot with the dependent variable. And want to save the plots as a pdf but in 1 or 2 pages of pdf for 1 file, instead of every graph in 1 individual page(that I already achieved). I am using following cases

1st Try using dev option

library(ggplot2)
library(gridExtra)

pdf("one.pdf", onefile = TRUE)
for (i in 1:length(dataset)) 
{
new_plot[[i]]=print(ggplot(data=dataset, aes(x=dataset[[i]], y=loss))+geom_point(size=1, alpha=0.3)+ 
      geom_smooth(method = lm)+
      xlab(paste0(colnames(int[i]), '\n', 'R-Squared: ',round(cor(int[[i]],int$loss, use = 'complete.obs'), 2)))+
      ylab("log(loss)") + theme_light())
plot_list = c(new_plot[[i]])
grid.arrange(plot_list)
}
dev.off()

2nd Try using ggsave

    for (i in 1:length(dataset)) 
    {
    new_plot[[i]]=print(ggplot(data=dataset, aes(x=dataset[[i]], y=loss))+geom_point(size=1, alpha=0.3)+ 
          geom_smooth(method = lm)+
          xlab(paste0(colnames(int[i]), '\n', 'R-Squared: ',round(cor(int[[i]],int$loss, use = 'complete.obs'), 2)))+
          ylab("log(loss)") + theme_light())
    m=marrangeGrob(new_plot[[i]],nrow=2, ncol=2)
    }

    ggsave("one.pdf",m)

Both of the time I received an error

Error in gList(data = list(list(x = c(2213.18, 1283.6, 3005.09, 939.85,  : 
only 'grobs' allowed in "gList"

Also if possible then share how the graphs can be posted in 2*2(example) on every page. I do appreciate all the help.Thanks in Advance!

1

There are 1 answers

2
Mark Peterson On BEST ANSWER

One simple approach might be to convert the data to long form (using gather from tidyr) then just use facet_wrap to do the arranging for you. This also saves on some of the difficult looping and automates the inclusion of any legends you may need/want.

Because you didn't give any reproducible data, here ia an example with the builtin iris data.

iris %>%
  gather(Response, Value, -Sepal.Width, -Species) %>%
  ggplot(aes(x = Value
             , y = Sepal.Width
             , col = Species)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_wrap(~Response
             , scale = "free_x")

gives:

enter image description here

If, for some reason, you really want to loop through the plots instead, you can use the package cowplot to stitch things together. One of the issues in your approach above is that you seem to be over-writing the plot list each time, when you may be better off constructing all of the plots, then handling them.

Here, I am using lapply instead of for as it tends to work much more smoothly. I am also using aes_string instead of passing a vector to aes as that makes it more clear what is happening where.

myPlots <- lapply(names(iris)[c(1,3,4)], function(thisPredictor){
  iris %>%
    ggplot(aes_string(x = thisPredictor
                      , y = "Sepal.Width"
                      , col = "Species")) +
    geom_point() +
    geom_smooth(method = "lm")
})

Then, you can use plot_grid to put them together like so

plot_grid(plotlist = myPlots)

gives:

enter image description here

which would work if not for the legends. Luckily, those can be easily handled as well

plot_grid(
  plot_grid(plotlist = lapply(myPlots, function(x){x + theme(legend.position = "none")})
            , nrow = 1)
  , get_legend(myPlots[[1]] + theme(legend.direction = "horizontal"))
  , nrow = 2
  , rel_heights = c(9,1) )

gives

enter image description here