This is cross-posted on the ggplot2 google group
My situation is that I\'m working on a function that outputs an arbitrary number of plots
You're ALMOST there! The problem is that do.call
expects your args to be in a named list
object. You've put them in the list, but as character strings, not named list items.
I think this should work:
args.list <- c(plot.list, 2,2)
names(args.list) <- c("x", "y", "z", "nrow", "ncol")
as Ben and Joshua pointed out in the comments, I could have assigned names when I created the list:
args.list <- c(plot.list,list(nrow=2,ncol=2))
or
args.list <- list(x=x, y=y, z=x, nrow=2, ncol=2)
I'm answering a bit late, but stumbled on a solution at the R Graphics Cookbook that does something very similar using a custom function called multiplot
. Perhaps it will help others who find this question. I'm also adding the answer as the solution may be newer than the other answers to this question.
Multiple graphs on one page (ggplot2)
Here's the current function, though please use the above link, as the author noted that it's been updated for ggplot2 0.9.3, which indicates it may change again.
# Multiple plot function
#
# ggplot objects can be passed in ..., or to plotlist (as a list of ggplot objects)
# - cols: Number of columns in layout
# - layout: A matrix specifying the layout. If present, 'cols' is ignored.
#
# If the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE),
# then plot 1 will go in the upper left, 2 will go in the upper right, and
# 3 will go all the way across the bottom.
#
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
require(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
One creates plot objects:
p1 <- ggplot(...)
p2 <- ggplot(...)
# etc.
And then passes them to multiplot
:
multiplot(p1, p2, ..., cols = n)
Try this,
require(ggplot2)
require(gridExtra)
plots <- lapply(1:11, function(.x) qplot(1:10,rnorm(10), main=paste("plot",.x)))
params <- list(nrow=2, ncol=2)
n <- with(params, nrow*ncol)
## add one page if division is not complete
pages <- length(plots) %/% n + as.logical(length(plots) %% n)
groups <- split(seq_along(plots),
gl(pages, n, length(plots)))
pl <-
lapply(names(groups), function(g)
{
do.call(arrangeGrob, c(plots[groups[[g]]], params,
list(main=paste("page", g, "of", pages))))
})
class(pl) <- c("arrangelist", "ggplot", class(pl))
print.arrangelist = function(x, ...) lapply(x, function(.x) {
if(dev.interactive()) dev.new() else grid.newpage()
grid.draw(.x)
}, ...)
## interactive use; open new devices
pl
## non-interactive use, multipage pdf
ggsave("multipage.pdf", pl)