如何使用grid.arrange来安排任意数量的ggplots?

这是交叉发布在ggplot2谷歌组

我的情况是,我正在处理一个输出任意数量的图的函数 (取决于用户提供的input数据)。 函数返回一个n个地块的列表,我想把这些地块放在2 x 2的地层中。 我正在同时遇到以下问题:

  1. 我怎样才能让灵活性交给任意数量的地块呢?
  2. 我怎样才能指定我想要他们摆放2 x 2

我目前的策略使用gridExtra包中的gridExtra 。 这可能不是最佳的,特别是因为,这是关键, 它完全不起作用 。 这是我评论的示例代码,试验了三个图:

 library(ggplot2) library(gridExtra) x <- qplot(mpg, disp, data = mtcars) y <- qplot(hp, wt, data = mtcars) z <- qplot(qsec, wt, data = mtcars) # A normal, plain-jane call to grid.arrange is fine for displaying all my plots grid.arrange(x, y, z) # But, for my purposes, I need a 2 x 2 layout. So the command below works acceptably. grid.arrange(x, y, z, nrow = 2, ncol = 2) # The problem is that the function I'm developing outputs a LIST of an arbitrary # number plots, and I'd like to be able to plot every plot in the list on a 2 x 2 # laid-out page. I can at least plot a list of plots by constructing a do.call() # expression, below. (Note: it totally even surprises me that this do.call expression # DOES work. I'm astounded.) plot.list <- list(x, y, z) do.call(grid.arrange, plot.list) # But now I need 2 x 2 pages. No problem, right? Since do.call() is taking a list of # arguments, I'll just add my grid.layout arguments to the list. Since grid.arrange is # supposed to pass layout arguments along to grid.layout anyway, this should work. args.list <- c(plot.list, "nrow = 2", "ncol = 2") # Except that the line below is going to fail, producing an "input must be grobs!" # error do.call(grid.arrange, args.list) 

正如我所愿意做的那样,我虚心地蜷缩在angular落里,热切地等待着一个比我更聪明的社区的明智反馈。尤其是如果我比这更难做。

你几乎在那里! 问题是, do.call期望您的参数在一个命名的list对象。 你已经把它们放在列表中,但作为string,而不是命名列表项。

我认为这应该工作:

 args.list <- c(plot.list, 2,2) names(args.list) <- c("x", "y", "z", "nrow", "ncol") 

正如Ben和Joshua在评论中指出的那样,我可以在创build列表时指定名称:

 args.list <- c(plot.list,list(nrow=2,ncol=2)) 

要么

 args.list <- list(x=x, y=y, z=x, nrow=2, ncol=2) 

尝试这个,

 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) 

我回答迟了一点,但偶然发现R Graphics Cookbook上的一个解决scheme,它使用称为多multiplot的自定义函数做了非常相似的事情。 也许这会帮助其他人find这个问题。 我也加了答案,因为解决scheme可能比这个问题的其他答案更新。

一页上多个graphics(ggplot2)

这里是当前的函数,虽然请使用上面的链接,因为作者指出它已经更新为ggplot2 0.9.3,这表明它可能会再次改变。

 # 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)) } } } 

一个创build阴谋对象:

 p1 <- ggplot(...) p2 <- ggplot(...) # etc. 

然后将它们传递给多multiplot

 multiplot(p1, p2, ..., cols = n)