我想使用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()

当前回答

是的,我认为你需要适当地安排你的数据。一种方法是:

X <- data.frame(x=rep(x,2),
                y=c(3*x+eps, 2*x+eps),
                case=rep(c("first","second"), each=100))

qplot(x, y, data=X, facets = . ~ case) + geom_smooth()

我相信在plyr或重塑中有更好的技巧——我仍然没有真正跟上速度 哈德利设计的这些强大的软件包。

其他回答

根据我的经验,网格。如果您试图在循环中生成情节,那么Arrange工作得很好。

简短代码片段:

gridExtra::grid.arrange(plot1, plot2, ncol = 2)

**更新此注释以展示如何在for循环中使用grid.arrange()为类别变量的不同因素生成图表。

for (bin_i in levels(athlete_clean$BMI_cat)) {

plot_BMI <- athlete_clean %>% filter(BMI_cat == bin_i) %>% group_by(BMI_cat,Team) %>% summarize(count_BMI_team = n()) %>% 
          mutate(percentage_cbmiT = round(count_BMI_team/sum(count_BMI_team) * 100,2)) %>% 
          arrange(-count_BMI_team) %>% top_n(10,count_BMI_team) %>% 
          ggplot(aes(x = reorder(Team,count_BMI_team), y = count_BMI_team, fill = Team)) +
            geom_bar(stat = "identity") +
            theme_bw() +
            # facet_wrap(~Medal) +
            labs(title = paste("Top 10 Participating Teams with \n",bin_i," BMI",sep=""), y = "Number of Athletes", 
                 x = paste("Teams - ",bin_i," BMI Category", sep="")) +
            geom_text(aes(label = paste(percentage_cbmiT,"%",sep = "")), 
                      size = 3, check_overlap = T,  position = position_stack(vjust = 0.7) ) +
            theme(axis.text.x = element_text(angle = 00, vjust = 0.5), plot.title = element_text(hjust = 0.5), legend.position = "none") +
            coord_flip()

plot_BMI_Medal <- athlete_clean %>% 
          filter(!is.na(Medal), BMI_cat == bin_i) %>% 
          group_by(BMI_cat,Team) %>% 
          summarize(count_BMI_team = n()) %>% 
          mutate(percentage_cbmiT = round(count_BMI_team/sum(count_BMI_team) * 100,2)) %>% 
          arrange(-count_BMI_team) %>% top_n(10,count_BMI_team) %>% 
          ggplot(aes(x = reorder(Team,count_BMI_team), y = count_BMI_team, fill = Team)) +
            geom_bar(stat = "identity") +
            theme_bw() +
            # facet_wrap(~Medal) +
            labs(title = paste("Top 10 Winning Teams with \n",bin_i," BMI",sep=""), y = "Number of Athletes", 
                 x = paste("Teams - ",bin_i," BMI Category", sep="")) +
            geom_text(aes(label = paste(percentage_cbmiT,"%",sep = "")), 
                      size = 3, check_overlap = T,  position = position_stack(vjust = 0.7) ) +
            theme(axis.text.x = element_text(angle = 00, vjust = 0.5), plot.title = element_text(hjust = 0.5), legend.position = "none") +
            coord_flip()

gridExtra::grid.arrange(plot_BMI, plot_BMI_Medal, ncol = 2)

}

下面包含了上面for循环中的一个样例图。 上述循环将为BMI类别的所有级别生成多个图。

样本图像

如果您希望在for循环中看到grid.arrange()的更全面的使用,请访问https://rpubs.com/Mayank7j_2020/olympic_data_2000_2016

并排的任意ggplot(或网格上的n个plot)

gridExtra包中的grid.arrange()函数将组合多个图;这就是把两个放在一起的方法。

require(gridExtra)
plot1 <- qplot(1)
plot2 <- qplot(1)
grid.arrange(plot1, plot2, ncol=2)

当两个图不是基于相同的数据时,这很有用,例如,如果您想在不使用重塑()的情况下绘制不同的变量。

这将把输出作为副作用绘制出来。要将副作用打印到文件中,请指定一个设备驱动程序(如pdf、png等)。

pdf("foo.pdf")
grid.arrange(plot1, plot2)
dev.off()

或者,将arrangeGrob()与ggsave()结合使用,

ggsave("foo.pdf", arrangeGrob(plot1, plot2))

这相当于使用par(mfrow = c(1,2))绘制两个不同的图。这不仅节省了整理数据的时间,而且当你想要两个不同的图时,这是必要的。


附录:facet的使用

切面有助于为不同的群体制作相似的图。下面的许多回答都指出了这一点,但我想用与上面的图等效的例子来强调这种方法。

mydata <- data.frame(myGroup = c('a', 'b'), myX = c(1,1))

qplot(data = mydata, 
    x = myX, 
    facets = ~myGroup)

ggplot(data = mydata) + 
    geom_bar(aes(myX)) + 
    facet_wrap(~myGroup)

更新

cowplot中的plot_grid函数值得作为grid.arrange的替代。参见下面@claus-wilke的回答和这个小插图,了解等效的方法;但该功能允许基于此小插图对地块位置和大小进行更精细的控制。

基于网格的解决方案的一个缺点。他们的一个缺点是很难像大多数期刊要求的那样用字母(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开始,可以直接对图进行标记,参见这里的示例。

Ggplot2基于网格图形,网格图形提供了在页面上安排图形的不同系统。par(mfrow…)命令并没有直接的对等物,因为网格对象(称为grobs)不一定是立即绘制的,但在转换为图形输出之前,可以作为常规R对象存储和操作。这比现在绘制基础图形的模型具有更大的灵活性,但策略必然略有不同。

我编写grid.arrange()是为了提供一个尽可能接近par(mfrow)的简单接口。在其最简单的形式中,代码看起来像:

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

library(gridExtra)
grid.arrange(p1, p2, ncol = 2)

在这个小插图中详细介绍了更多的选项。

一个常见的抱怨是,图不一定是对齐的,例如,当它们有不同大小的轴标签时,但这是通过设计:网格。Arrange没有尝试处理特殊情况下的ggplot2对象,并将它们与其他grobs(例如,晶格图)同等对待。它只是将抓取放在矩形布局中。

对于ggplot2对象的特殊情况,我编写了另一个函数ggarrange,该函数具有类似的接口,它尝试对齐绘图面板(包括分面图),并尝试尊重用户定义的纵横比。

library(egg)
ggarrange(p1, p2, ncol = 2)

这两个函数都与ggsave()兼容。对于不同选项的一般概述和一些历史背景,本小插图提供了额外的信息。

您可以使用温斯顿张的R食谱下面的多绘图函数

multiplot(plot1, plot2, cols=2)

multiplot <- function(..., plotlist=NULL, cols) {
    require(grid)

    # Make a list from the ... arguments and plotlist
    plots <- c(list(...), plotlist)

    numPlots = length(plots)

    # Make the panel
    plotCols = cols                          # Number of columns of plots
    plotRows = ceiling(numPlots/plotCols) # Number of rows needed, calculated from # of cols

    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(plotRows, plotCols)))
    vplayout <- function(x, y)
        viewport(layout.pos.row = x, layout.pos.col = y)

    # Make each plot, in the correct location
    for (i in 1:numPlots) {
        curRow = ceiling(i/plotCols)
        curCol = (i-1) %% plotCols + 1
        print(plots[[i]], vp = vplayout(curRow, curCol ))
    }

}