如何将if/else循环生成的ggplot图形存入列表并通过ggarrange排版
问题描述
背景
通过大量if/else循环用ggplot2生成图形,每个图形按固定规则命名为唯一对象,示例命名如下:
graph_log_bar_blue <- graph_log_violin_blue <- graph_log_bar_red <- graph_log_violin_red <- graph_log_bar_green <- graph_log_violin_green <-
希望将满足循环条件生成的图形存入列表,以便用ggpubr包的ggarrange或gridExtra进行面板排版。但目前用ls(pattern = "graph_")仅能得到图形名称字符串,无法直接用于排版:
graph_list <- ls(pattern = "graph_") # 仅列出图形名称,未存储图形对象 library("ggpubr") ggarrange(graph_list, nrow = 1, ncol = 3) # 或使用gridExtra library("gridExtra") # 加载gridExtra包 do.call("grid.arrange", c(plot_list, ncol = 3))
具体疑问
- 是否可以创建ggplot生成的图形列表?
- 如何在if/else循环内筛选或创建图形列表?
- 如何调用生成的图形并使用
ggarrange(ggpubr包)等工具排版为面板图?
数据示例代码
使用iris数据集模拟实际代码结构(逻辑无需深究):
library(ggplot2) iris <- iris #数据集1 kt <- kruskal.test(Petal.Width ~ Species, data = iris) kt$p.value if(kt$p.value > 0.05){ pt <- pairwise.wilcox.test(iris$Petal.Width, g=iris$Species, p.adjust.method = "BH") }else if(kt$p.value < 0.05){ graph_log_bar_blue <- ggplot(data = iris, aes(y=Petal.Width, x=Species, fill = Species)) + stat_summary(fun = median, show.legend = FALSE, geom="crossbar") + geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5) + labs(x=NULL, y= "Petal Width (cm)") }else{ graph_log_violin_blue <- ggplot(data = iris, aes(y=Petal.Width, x=Species, fill = Species)) + geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6) + labs(x=NULL, y= "Petal Width (cm)") } #数据集2 kt_sep <- kruskal.test(Sepal.Width ~ Species, data = iris) kt_sep$p.value if(kt_sep$p.value > 0.05){ pt_sep <- pairwise.wilcox.test(iris$Sepal.Width, g=iris$Species, p.adjust.method = "BH") }else if(kt_sep$p.value > 0.05){ graph_log_bar_red <- ggplot(data = iris, aes(y=Sepal.Width, x=Species, fill = Species)) + stat_summary(fun = median, show.legend = FALSE, geom="crossbar") + geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5) + labs(x=NULL, y= "Sepal Width (cm)") }else{ graph_log_violin_red <- ggplot(data = iris, aes(y=Sepal.Width, x=Species, fill = Species)) + geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6) + labs(x=NULL, y= "Sepal Width (cm)") } graph_list <- ls(pattern="graph_")
解决方案
方法一:在循环/条件语句中直接构建图形列表(推荐)
避免单独创建大量全局环境变量,生成图形时直接添加到列表,更高效且条理清晰:
library(ggplot2) library(ggpubr) # 初始化空列表 graph_list <- list() # 数据集1处理 kt <- kruskal.test(Petal.Width ~ Species, data = iris) if(kt$p.value > 0.05){ pt <- pairwise.wilcox.test(iris$Petal.Width, g=iris$Species, p.adjust.method = "BH") }else if(kt$p.value < 0.05){ p <- ggplot(data = iris, aes(y=Petal.Width, x=Species, fill = Species)) + stat_summary(fun = median, show.legend = FALSE, geom="crossbar") + geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5) + labs(x=NULL, y= "Petal Width (cm)") # 添加到列表并指定名称 graph_list[["graph_log_bar_blue"]] <- p }else{ p <- ggplot(data = iris, aes(y=Petal.Width, x=Species, fill = Species)) + geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6) + labs(x=NULL, y= "Petal Width (cm)") graph_list[["graph_log_violin_blue"]] <- p } # 数据集2处理(修正原代码重复条件问题) kt_sep <- kruskal.test(Sepal.Width ~ Species, data = iris) if(kt_sep$p.value > 0.05){ pt_sep <- pairwise.wilcox.test(iris$Sepal.Width, g=iris$Species, p.adjust.method = "BH") }else if(kt_sep$p.value < 0.05){ p <- ggplot(data = iris, aes(y=Sepal.Width, x=Species, fill = Species)) + stat_summary(fun = median, show.legend = FALSE, geom="crossbar") + geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5) + labs(x=NULL, y= "Sepal Width (cm)") graph_list[["graph_log_bar_red"]] <- p }else{ p <- ggplot(data = iris, aes(y=Sepal.Width, x=Species, fill = Species)) + geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6) + labs(x=NULL, y= "Sepal Width (cm)") graph_list[["graph_log_violin_red"]] <- p } # 直接用列表排版 ggarrange(plotlist = graph_list, nrow = 1, ncol = length(graph_list))
方法二:从全局环境提取已有图形对象到列表
如果已经生成了单独的图形对象,用mget()函数将名称字符串转换为实际图形对象:
# 提取所有以graph_开头的对象到列表 graph_list <- mget(ls(pattern = "^graph_")) # 用ggarrange排版(需指定plotlist参数) ggarrange(plotlist = graph_list, nrow = 1, ncol = 2) # 或用gridExtra包 library(gridExtra) do.call(grid.arrange, c(graph_list, ncol = 2))
关键说明
- ggplot对象本质是R列表,完全可以存入列表,方法一从源头构建列表更高效,还能避免全局环境变量混乱。
mget()是解决“只有名称无对象”问题的核心,它能根据变量名称字符串从环境中提取对应对象。ggarrange需要通过plotlist参数接收图形列表,不能直接传入字符串列表;gridExtra的grid.arrange可通过do.call将列表元素作为参数传入。
内容的提问来源于stack exchange,提问作者MM1
相关产品推荐
相关产品推荐

