Reputation: 379
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.
Upvotes: 2
Views: 240
Reputation: 25904
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()
Upvotes: 1
Reputation: 125438
Here is an approach using lapply
instead of a for
loop and patchwork
to combine your plots:
library(patchwork)
library(ggplot2)
plot_list <- lapply(
1:5,
\(x) {
list(
ggplot(iris, aes(x = Petal.Length)) +
geom_histogram(),
ggplot(iris, aes(x = Petal.Length, color = Species)) +
geom_boxplot(),
ggplot(iris, aes(x = Petal.Length, y = Petal.Width, color = Species)) +
geom_point()
)
}
)
lay <-
"
1122
1133
1133
"
grDevices::cairo_pdf("plots.pdf", onefile = TRUE)
lapply(
plot_list, patchwork::wrap_plots,
design = lay
)
#> [[1]]
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#>
#> [[2]]
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#>
#> [[3]]
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#>
#> [[4]]
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#>
#> [[5]]
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
dev.off()
#> quartz_off_screen
#> 2
And a second option would be to use grid.arrange
:
grDevices::cairo_pdf("plots.pdf", onefile = TRUE)
for (i in seq(length(plot_list))) {
grid.arrange(plot_list[[i]], layout_matrix = lay)
}
dev.off()
Upvotes: 1