利用par()或layout()函数,如何绘制ggplot2的组合图表(不在一个单一的图表中)?

24

我一直在考虑使用par()或layout()函数来组合ggplot。能否使用这些函数呢?

假设我想为散点图绘制ggplot,并为直方图绘制ggplot。并且我想将这两个绘图组合起来(不是在一个图中)。这可行吗?

我在R中尝试了简单的绘图,而没有使用ggplot函数。实际上它可以工作。

这里有一个来自Quick-R的示例,链接:http://www.statmethods.net/advgraphs/layout.html

# 4 figures arranged in 2 rows and 2 columns
attach(mtcars)
par(mfrow=c(2,2))
plot(wt,mpg, main="Scatterplot of wt vs. mpg")
plot(wt,disp, main="Scatterplot of wt vs disp")
hist(wt, main="Histogram of wt")
boxplot(wt, main="Boxplot of wt")

# One figure in row 1 and two figures in row 2
attach(mtcars)
layout(matrix(c(1,1,2,3), 2, 2, byrow = TRUE))
hist(wt)
hist(mpg)
hist(disp)

但是,当我尝试使用ggplot并结合绘图时,我没有得到输出结果。


ggplot2不是基础图形,因此您不能将ggplot2与layout或par(mfrow)组合。您需要在gridExtra中使用plot.arrange等功能。或者,您可以在网格系统中使用viewport进行调整。 - kohske
既然您要求类似于layout()的东西,那么您可能需要像kohske提到的那样使用grid.arrange()这篇链接的帖子(特别是Ben Bolker的回答)将为您提供一个很好的起点。 - Josh O'Brien
3个回答

32
library(ggplot2)
library(grid)


vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y)


plot1 <- qplot(mtcars,x=wt,y=mpg,geom="point",main="Scatterplot of wt vs. mpg")
plot2 <- qplot(mtcars,x=wt,y=disp,geom="point",main="Scatterplot of wt vs disp")
plot3 <- qplot(wt,data=mtcars)
plot4 <- qplot(wt,mpg,data=mtcars,geom="boxplot")
plot5 <- qplot(wt,data=mtcars)
plot6 <- qplot(mpg,data=mtcars)
plot7 <- qplot(disp,data=mtcars)

# 4 figures arranged in 2 rows and 2 columns
grid.newpage()
pushViewport(viewport(layout = grid.layout(2, 2)))
print(plot1, vp = vplayout(1, 1))
print(plot2, vp = vplayout(1, 2))
print(plot3, vp = vplayout(2, 1))
print(plot4, vp = vplayout(2, 2))


# One figure in row 1 and two figures in row 2
grid.newpage()
pushViewport(viewport(layout = grid.layout(2, 2)))
print(plot5, vp = vplayout(1, 1:2))
print(plot6, vp = vplayout(2, 1))
print(plot7, vp = vplayout(2, 2))

1
给Maiasaura,感谢您提供的脚本/代码。但是,当我打印plot1和plot2时,出现了一个错误,提示“在eval(expr, envir, enclos)中出错:找不到对象'wt'”。然而,我通过重新排列plot1和plot2中的参数来解决了这个问题。plot1 <- qplot(x=wt,y=mpg,data = mtcars,geom = "point",main="Scatterplot of wt vs. mpg")和 plot2 <- qplot(x=wt,y=disp, data = mtcars,geom="point",main="Scatterplot of wt vs disp")再次感谢您的快速回复。 - Al-Ahmadgaid Asaad
@Maiasaura 感谢您提供的好答案。我该如何将一个标题添加到整个网格作为主标题。我看到了grid.text选项,但在2x4网格中,它不会很好地显示在顶部和中间。 - add-semi-colons
2
这个解决方案应该被标记为过时的,因为grid包最近已经从CRAN中删除了。 - ahs85

13
一个我认为应该得到更多关注的实用工具是layOut,它曾经属于wq包(请注意大写字母“O”)。由于已从wq包中删除,因此我将代码放在下面并将其重命名为lay_out以匹配典型的ggplot样式。与base::layout类似,它可以布置大小不同、行列有序的图像。每个传递给lay_out的参数都是3元素列表,包含绘图、要在其中绘制它的行索引和列索引。

例如,使用@Paul McMurdie的图:

lay_out(list(plot1, 1, 1),
        list(plot2, 1, 2),
        list(plot3, 2, 1),
        list(plot4, 2, 2),
        list(plot5, 3, 1:2),
        list(plot6, 4, 1:2),
        list(plot7, 1:2, 3))

enter image description here

lay_out = function(...) {    
    x <- list(...)
    n <- max(sapply(x, function(x) max(x[[2]])))
    p <- max(sapply(x, function(x) max(x[[3]])))
    grid::pushViewport(grid::viewport(layout = grid::grid.layout(n, p)))    

    for (i in seq_len(length(x))) {
        print(x[[i]][[1]], vp = grid::viewport(layout.pos.row = x[[i]][[2]], 
            layout.pos.col = x[[i]][[3]]))
    }
} 

(这段代码来源于之前版本的wq包,来自于非官方Github CRAN镜像上的提交历史。)


我真的很喜欢这个解决方案。grid.arrange不能提供漂亮的图形放置。 - ahs85
@Grego。包wq(水质)似乎不再具有layOut()函数。这是正确的吗? - lawyeR
1
@lawyeR 看起来是这样。我已经在我的答案中添加了代码。 - Gregor Thomas
我该如何安装必要的软件包?我尝试了 install.packages("layOut")install.packages("lay_out"),但都没有成功。 - Mark K Cowan
啊,抱歉,我从你的 Github 链接中获取了它,我没有意识到你已经链接到了函数源代码 :) - Mark K Cowan

7
涉及到grid.layout的解答是可行的,我已经使用过它并点赞了。然而,我通常觉得这个解决方案太繁琐且容易出错,我认为大多数经常这样做的ggplot2爱好者都已经把它包装成了一个函数。我以前在搜索中找到了几个这样的包装函数,但我目前的解决方案是在一个名为gridExtra 的格子附加包中。它有一些有用的参数,但默认的行/列设置通常就是你想要的:
library("ggplot2")
# Generate list of arbitrary ggplots
plot1 <- qplot(data = mtcars, x=wt, y=mpg, geom="point",main="Scatterplot of wt vs. mpg")
plot2 <- qplot(data = mtcars, x=wt, y=disp, geom="point",main="Scatterplot of wt vs disp")
plot3 <- qplot(wt,data=mtcars)
plot4 <- qplot(wt,mpg,data=mtcars,geom="boxplot")
plot5 <- qplot(wt,data=mtcars)
plot6 <- qplot(mpg,data=mtcars)
plot7 <- qplot(disp,data=mtcars)
# You might have produced myPlotList using instead lapply, mc.lapply, plyr::dlply, etc 
myPlotList = list(plot1, plot2, plot3, plot4, plot5, plot6, plot7)
library("gridExtra")
do.call(grid.arrange,  myPlotList)

请注意,实际的“将我的图形合并为一个图形”的代码只有一行(在加载gridExtra之后)。您可能会认为将图形放入列表中是多余的一行,但实际上我可以选择使用

grid.arrange(plot1, plot2, plot3, plot4, plot5, plot6, plot7)

对于小数量的ggplots来说,这可能更可取。但是,对于n_plots > 4,你将开始厌恶不得不为它们命名和输入类型。


如果你想要两列,例如从grid.arrange得到的结果,最后一行会包含什么?我已经尝试了args = list(ncol = 2)的不同变化。 - lawyeR
5
这里是一行代码:do.call(grid.arrange, c(myPlotList, list(ncol = 2))),意思是将列表 myPlotList 中的所有图形以 2 列的形式排列。 - Paul 'Joey' McMurdie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接