我想使用ggplot2 包并排放置两个图,即相当于par(mfrow=c(1,2))
.
例如,我想让以下两个图以相同的比例并排显示。
x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)
我需要把它们放在同一个data.frame中吗?
qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()
我想使用ggplot2 包并排放置两个图,即相当于par(mfrow=c(1,2))
.
例如,我想让以下两个图以相同的比例并排显示。
x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)
我需要把它们放在同一个data.frame中吗?
qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()
grid.arrange()
包中的函数gridExtra
将组合多个图;这就是你如何将两个并排放置。
require(gridExtra)
plot1 <- qplot(1)
plot2 <- qplot(1)
grid.arrange(plot1, plot2, ncol=2)
当两个图不是基于相同的数据时,这很有用,例如,如果您想在不使用 reshape() 的情况下绘制不同的变量。
这会将输出绘制为副作用。要将副作用打印到文件中,请指定设备驱动程序(例如pdf
、png
等),例如
pdf("foo.pdf")
grid.arrange(plot1, plot2)
dev.off()
或者,arrangeGrob()
结合使用ggsave()
,
ggsave("foo.pdf", arrangeGrob(plot1, plot2))
这相当于使用 . 绘制两个不同的图par(mfrow = c(1,2))
。这不仅节省了排列数据的时间,而且当您想要两个不同的图时,这是必要的。
分面有助于为不同的组制作类似的图。在下面的许多答案中都指出了这一点,但我想通过与上述图表等效的示例来强调这种方法。
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)
中的plot_grid
功能cowplot
值得一试作为grid.arrange
. 请参阅下面@claus-wilke的答案和此小插图以获取等效方法;但该功能允许基于此小插图对绘图位置和大小进行更精细的控制。
所基于的解决方案的一个缺点grid.arrange
是它们很难像大多数期刊所要求的那样用字母(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")
更新:
使用patchwork包,您可以简单地使用+
运算符:
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
p1 + p2
其他运算符包括/
堆叠绘图以并排放置绘图以及()
对元素进行分组。例如,您可以使用 配置 3 个图的顶行和一个图的底行(p1 | p2 | p3) /p
。有关更多示例,请参阅包文档。
您可以使用Winston Chang 的 R 食谱中的以下multiplot
功能
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 ))
}
}
是的,我认为您需要适当地安排数据。一种方法是:
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 或 reshape 有更好的技巧——我仍然没有真正了解 Hadley 的所有这些强大的软件包。
使用 reshape 包你可以做这样的事情。
library(ggplot2)
wide <- data.frame(x = rnorm(100), eps = rnorm(100, 0, .2))
wide$first <- with(wide, 3 * x + eps)
wide$second <- with(wide, 2 * x + eps)
long <- melt(wide, id.vars = c("x", "eps"))
ggplot(long, aes(x = x, y = value)) + geom_smooth() + geom_point() + facet_grid(.~ variable)
还有值得一提的multipanelfigure 包。另请参阅此答案。
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 年 7 月 6 日创建。
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)
此小插图中详细介绍了更多选项。
一个常见的抱怨是绘图不一定对齐,例如当它们具有不同大小的轴标签时,但这是设计使然:grid.arrange
不尝试特殊情况 ggplot2 对象,并将它们与其他 grobs 同等对待(例如格子图)。它只是将 grobs 放置在矩形布局中。
对于 ggplot2 对象的特殊情况,我编写了另一个函数 ,ggarrange
具有类似的界面,它尝试对齐绘图面板(包括多面图)并尝试在用户定义时尊重纵横比。
library(egg)
ggarrange(p1, p2, ncol = 2)
这两个功能都兼容ggsave()
. 有关不同选项的一般概述和一些历史背景,此小插图提供了更多信息。
更新:这个答案很老了。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 打印所有变量的计数
dt = ggplot2::diamonds
plotAllCounts(dt)
需要注意的一件事是:在上面的代码中
使用 aes(get(strX))
,您通常在使用 时在循环中使用,而不是不会绘制所需的图。相反,它将多次绘制最后一个情节。我还没有弄清楚为什么 - 它可能必须这样做并且被调用。ggplot
aes_string(strX)
aes
aes_string
ggplot
否则,希望您会发现该功能很有用。
也ggarrange
从ggpubr
包装考虑。它有很多好处,包括在绘图之间对齐轴和将常见图例合并为一个的选项。
plot_grid 和 grid_arrange 都不适合我。这很奇怪。当我尝试单独绘制两个图时,我得到了正确的图,尽管当我使用前面提到的其中一个函数时,我得到了相同的图重复两次而不是两个不同的图。
vv <- 1
# dump the data for this variable into a new data frame:
df1 <- data.frame(x<-sharkMeanFitX[vv,], y<-sharkMeanFit[vv,], err<-
sharkSDFit[vv,])
# Plot mean fit with error bars of 1 sd for each predictor:
#
#-->When ready to output to a file, uncomment the png and dev.off lines <---
#--> Don't forget to change the file name when you switch variables <--
#png(filenameList[vv],width=10,height=7,res=300,units="cm") #uncomment to print to file!
ggplot(df1, aes(x=x,y=y))+
geom_ribbon(aes(ymin=y-(1.96*err),ymax=y+(1.96*err),alpha=0.1),show.legend=FALSE) +
geom_line(colour="blue", size=1) +
theme(text = element_text(size = 18)) +
xlab("TagID") +
ylab(ylabList[vv])
# pick which variable to plot:
vv <- 2
# dump the data for this variable into a new data frame:
df1 <- data.frame(x<-sharkMeanFitX[vv,], y<-sharkMeanFit[vv,], err<-sharkSDFit[vv,])
# Plot mean fit with error bars of 1 sd for each predictor:
#
#-->When ready to output to a file, uncomment the png and dev.off lines <---
#--> Don't forget to change the file name when you switch variables <--
#png(filenameList[vv],width=10,height=7,res=300,units="cm") #uncomment to print to file!
ggplot(df1, aes(x=x,y=y))+
geom_ribbon(aes(ymin=y-(1.96*err),ymax=y+(1.96*err),alpha=0.1),show.legend=FALSE) +
geom_line(colour="blue", size=1) +
theme(text = element_text(size = 18)) +
xlab("Chl (mg m^-3)") +
ylab(ylabList[vv])
如果有人有任何想法,那就太棒了!提前致谢。
以我的经验,如果您尝试在循环中生成图,那么 gridExtra:grid.arrange 可以完美地工作。
短代码片段:
gridExtra::grid.arrange(plot1, plot2, ncol = 2)
** 更新此评论以显示如何grid.arrange()
在 for 循环中使用为分类变量的不同因子生成图。
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 类别生成多个图。
如果您希望更全面地使用grid.arrange()
内for
循环,请查看https://rpubs.com/Mayank7j_2020/olympic_data_2000_2016