我想使用ggplot2包并排放置两个图,即执行par(mfrow=c(1,2))的等效操作。

例如,我想让下面两个图以相同的比例并排显示。

x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)

我需要把它们放到同一个数据帧里吗?

qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()

当前回答

如果您希望使用循环绘制多个ggplot图(例如:使用循环在ggplot中创建具有不同y轴值的多个图),上述解决方案可能不太有效,这是分析未知(或大型)数据集的理想步骤(例如,当您希望绘制数据集中所有变量的计数时)。

下面的代码展示了如何使用上面提到的“multiplot()”来实现这一点,其源代码在这里:http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2):

plotAllCounts <- function (dt){   
  plots <- list();
  for(i in 1:ncol(dt)) {
    strX = names(dt)[i]
    print(sprintf("%i: strX = %s", i, strX))
    plots[[i]] <- ggplot(dt) + xlab(strX) +
      geom_point(aes_string(strX),stat="count")
  }

  columnsToPlot <- floor(sqrt(ncol(dt)))
  multiplot(plotlist = plots, cols = columnsToPlot)
}

现在运行函数-以获取在一页上使用ggplot打印的所有变量的Counts

dt = ggplot2::diamonds
plotAllCounts(dt)

需要注意的一点是: 在上面的代码中使用aes(get(strX)),而不是aes_string(strX)将不会绘制所需的图形,这是在处理ggplot时通常在循环中使用的。相反,它会多次绘制最后一个图形。我还没有弄清楚为什么-它可能必须做aes和aes_string在ggplot中被调用。

除此之外,希望你会发现这个函数有用。

其他回答

使用补丁包,你可以简单地使用+运算符:

library(ggplot2)
library(patchwork)

p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))


p1 + p2

其他操作符包括/,用于堆叠图,并排放置图,以及(),用于对元素进行分组。例如,你可以用(p1 | p2 | p3) /p来配置上面一行的3个地块和下面一行的一个地块。有关更多示例,请参阅包文档。

基于网格的解决方案的一个缺点。他们的一个缺点是很难像大多数期刊要求的那样用字母(A, B等)来标记这些图。

我写了cowplot包来解决这个(和其他一些)问题,特别是函数plot_grid():

library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot() + theme_bw()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) + theme_bw() +
  theme(legend.position = c(0.8, 0.8))

plot_grid(iris1, iris2, labels = "AUTO")

plot_grid()返回的对象是另一个ggplot2对象,你可以像往常一样用ggsave()保存它:

p <- plot_grid(iris1, iris2, labels = "AUTO")
ggsave("plot.pdf", p)

或者,你可以使用cowplot函数save_plot(),它是ggsave()的一个薄包装,可以很容易地获得组合图的正确尺寸,例如:

p <- plot_grid(iris1, iris2, labels = "AUTO")
save_plot("plot.pdf", p, ncol = 2)

(ncol = 2参数告诉save_plot()有两个并排的图像,而save_plot()使保存的图像宽度增加一倍。)

有关如何在网格中安排图的更深入描述,请参阅此小插图。还有一个小插图解释如何用一个共享的传说来制作情节。

一个常见的混淆点是cowplot包更改了默认的ggplot2主题。这个包之所以这样做,是因为它最初是为内部实验室使用而编写的,我们从不使用默认主题。如果这导致问题,您可以使用以下三种方法之一来解决它们:

1. 为每个情节手动设置主题。我认为始终为每个情节指定一个特定的主题是一个很好的实践,就像我在上面的示例中对+ theme_bw()所做的那样。如果您指定了一个特定的主题,那么默认主题并不重要。

2. 将默认主题恢复为ggplot2默认。你可以用一行代码做到这一点:

theme_set(theme_gray())

3.调用cowplot函数而不附加包。你也可以不调用library(cowplot)或require(cowplot),而是通过前置cowplot::来调用cowplot函数。例如,上面使用ggplot2默认主题的示例将变成:

## Commented out, we don't call this
# library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) +
  theme(legend.position = c(0.8, 0.8))

cowplot::plot_grid(iris1, iris2, labels = "AUTO")

更新:

从cowplot 1.0开始,默认的ggplot2主题不再更改。 从ggplot2 3.0.0开始,可以直接对图进行标记,参见这里的示例。

更新:这个答案非常古老。gridExtra::grid.arrange()现在是推荐的方法。 我把这个留在这里,也许有用。


Stephen Turner在Getting Genetics Done博客上发布了arrange()函数(参见文章中的应用说明)

vp.layout <- function(x, y) viewport(layout.pos.row=x, layout.pos.col=y)
arrange <- function(..., nrow=NULL, ncol=NULL, as.table=FALSE) {
 dots <- list(...)
 n <- length(dots)
 if(is.null(nrow) & is.null(ncol)) { nrow = floor(n/2) ; ncol = ceiling(n/nrow)}
 if(is.null(nrow)) { nrow = ceiling(n/ncol)}
 if(is.null(ncol)) { ncol = ceiling(n/nrow)}
        ## NOTE see n2mfrow in grDevices for possible alternative
grid.newpage()
pushViewport(viewport(layout=grid.layout(nrow,ncol) ) )
 ii.p <- 1
 for(ii.row in seq(1, nrow)){
 ii.table.row <- ii.row 
 if(as.table) {ii.table.row <- nrow - ii.table.row + 1}
  for(ii.col in seq(1, ncol)){
   ii.table <- ii.p
   if(ii.p > n) break
   print(dots[[ii.table]], vp=vp.layout(ii.table.row, ii.col))
   ii.p <- ii.p + 1
  }
 }
}

如果您希望使用循环绘制多个ggplot图(例如:使用循环在ggplot中创建具有不同y轴值的多个图),上述解决方案可能不太有效,这是分析未知(或大型)数据集的理想步骤(例如,当您希望绘制数据集中所有变量的计数时)。

下面的代码展示了如何使用上面提到的“multiplot()”来实现这一点,其源代码在这里:http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2):

plotAllCounts <- function (dt){   
  plots <- list();
  for(i in 1:ncol(dt)) {
    strX = names(dt)[i]
    print(sprintf("%i: strX = %s", i, strX))
    plots[[i]] <- ggplot(dt) + xlab(strX) +
      geom_point(aes_string(strX),stat="count")
  }

  columnsToPlot <- floor(sqrt(ncol(dt)))
  multiplot(plotlist = plots, cols = columnsToPlot)
}

现在运行函数-以获取在一页上使用ggplot打印的所有变量的Counts

dt = ggplot2::diamonds
plotAllCounts(dt)

需要注意的一点是: 在上面的代码中使用aes(get(strX)),而不是aes_string(strX)将不会绘制所需的图形,这是在处理ggplot时通常在循环中使用的。相反,它会多次绘制最后一个图形。我还没有弄清楚为什么-它可能必须做aes和aes_string在ggplot中被调用。

除此之外,希望你会发现这个函数有用。

还有一个多面板图形包是值得一提的。看看这个答案。

library(ggplot2)
theme_set(theme_bw())

q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
q4 <- ggplot(mtcars) + geom_bar(aes(carb))

library(magrittr)
library(multipanelfigure)
figure1 <- multi_panel_figure(columns = 2, rows = 2, panel_label_type = "none")
# show the layout
figure1

figure1 %<>%
  fill_panel(q1, column = 1, row = 1) %<>%
  fill_panel(q2, column = 2, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2, row = 2)
figure1

# complex layout
figure2 <- multi_panel_figure(columns = 3, rows = 3, panel_label_type = "upper-roman")
figure2

figure2 %<>%
  fill_panel(q1, column = 1:2, row = 1) %<>%
  fill_panel(q2, column = 3, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2:3, row = 2:3)
figure2

由reprex包(v0.2.0.9000)于2018-07-06创建。