如何在for循环中绘制并排列多幅ggplot散点图
批量绘制散点图并合并为单张图片的解决方案
数据集
现有数据集filtered_el如下:
filtered_el <- structure(list(Site = c("Cave", "Cave", "Cave", "Cave", "Cave", "Cave", "Open_air", "Open_air", "Cave", "Cave"), Sample = c("s13", "s16", "s20", "s57", "s58", "s59", "s105", "s106", "s110", "s112"), Ca = c(233483.7, 332549.4, 163451.6, 122560.3, 137458, 130964.9, 145151.6, 182335.1, 287127.3, 346025.4), P = c(6653.86, 24779.57, 4747.33, 5875.81, 6670.85, 4770.85, 5607.23, 4101.98, 31762.59, 121520.34), Si = c(85458.49, 53839.66, 91317.05, 166865.47, 107911.59, 113553.15, 151926.88, 123296.37, 79184.64, 20302.76), Mg = c("6822.14", "6446.35", "< LOD", "8755.55", "11751.76", "11785.28", "5124", "7797.72", "7702.34", "< LOD"), Sr = c(236.12, 194.78, 169.51, 98.73, 98.94, 89.14, 315.54, 506.27, 160.78, 247.24), Fe = c(25002.51, 18383.66, 31466.12, 56692.94, 42549.91, 41131.11, 28692.23, 24175.82, 24570.66, 6798.99), K = c(9914.3, 7091.86, 7770.19, 7945.62, 5910.46, 5646.92, 6454.71, 6372.62, 7442.22, 1972.5), Al = c(16847.06, 12103.81, 17776.28, 38946.29, 28895.68, 30437.12, 20931.17, 13815.11, 20492.54, 6099.5)), class = "data.frame", row.names = c(NA, -10L))
需求说明
需要为Ca、P、Si、Mg、Sr、Fe、K、Al8个变量分别绘制散点图(x轴为Sample,y轴为对应变量,按Site区分点的颜色),并将所有图合并为一张图片。现有循环代码仅能逐个输出图片,无法完成合并。
解决方案
前置处理:清理数据
数据中存在< LOD字符值,需先转换为NA并将数值列转为数值类型,否则会导致绘图失败:
library(dplyr) filtered_el <- filtered_el %>% mutate(across(c(Ca, P, Si, Mg, Sr, Fe, K, Al), ~as.numeric(ifelse(. == "< LOD", NA, .))))
方案一:循环生成图存列表,用ggarrange合并
使用ggpubr包的ggarrange函数,先通过循环将每个子图存入列表,再一次性合并:
library(ggplot2) library(ggpubr) # 定义变量列表 variables <- c('Ca', 'P', 'Si', 'Mg', 'Sr', 'Fe', 'K', 'Al') # 创建空列表存储子图 plot_list <- list() # 循环生成每个变量的散点图 for (var in variables) { p <- ggplot(filtered_el, aes(x = Sample, y = .data[[var]], color = Site)) + geom_point(size = 2, show.legend = FALSE) + ylab(var) + theme_bw() plot_list[[var]] <- p } # 合并所有子图,设置为2行4列布局 combined_plot <- ggarrange(plotlist = plot_list, nrow = 2, ncol = 4) print(combined_plot)
说明:
- 用
.data[[var]]是ggplot2推荐的动态引用变量的方式,比直接取列更规范。 - 可通过
ggarrange的nrow和ncol参数调整布局,比如4行2列。
方案二:宽转长数据+分面绘制(更简洁)
利用tidyr将宽格式数据转为长格式,再用facet_wrap一次性生成所有子图,无需循环:
library(ggplot2) library(tidyr) library(dplyr) # 宽格式转长格式 filtered_el_long <- filtered_el %>% pivot_longer(cols = all_of(variables), names_to = "Variable", values_to = "Value") # 绘制分面散点图 combined_plot <- ggplot(filtered_el_long, aes(x = Sample, y = Value, color = Site)) + geom_point(size = 2, show.legend = FALSE) + facet_wrap(~Variable, nrow = 2, ncol = 4, scales = "free_y") + # y轴自由缩放适配不同变量范围 theme_bw() print(combined_plot)
说明:
scales = "free_y"参数让每个子图的y轴根据自身数据范围调整,避免因变量数值差异过大导致部分图显示异常。- 这种方法更符合tidyverse的数据分析流程,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Valentina
相关产品推荐
相关产品推荐

