基于ggplot2实现嵌套Y轴与facet_wrap分面的测量可视化需求
按物种对齐的样本测量缺失可视化方案
需求说明
现有样本时间序列测量数据集,需可视化各样本在不同时间点的已完成/缺失测量。当前实现使用ggplot2的facet_wrap按处理组(Treatment)分面,但需优化以下两点:
- Y轴按物种(Species)嵌套分组,实现不同处理组间同一物种的视觉对齐
- 同一物种在不同处理组的Y轴行数统一为该物种的最大样本数(如Amu物种在Treatment A有4个样本,Treatment B仅2个,则B组对应位置保留2个空行,保证样本间距一致)
解决方案步骤
1. 数据预处理
首先生成包含所有可能样本-处理-物种组合的完整数据集,为缺失样本占位,确保Y轴行数统一。使用dplyr和tidyr完成预处理:
# 加载必要包 library(ggplot2) library(dplyr) library(tidyr) library(forcats) # 原始数据集 data <- read.table(text = "Sample_ID Species Time Treatment Amu1 Amu 1 A Amu1 Amu 2 A Amu1 Amu 3 A Amu5 Amu 1 B Amu5 Amu 2 B Amu2 Amu 1 A Amu2 Amu 2 A Amu2 Amu 3 A Amu3 Amu 1 A Amu3 Amu 2 A Amu4 Amu 1 A Amu4 Amu 2 A Amu4 Amu 3 A Amu6 Amu 1 B Amu6 Amu 3 B Spi1 Spi 1 A Spi1 Spi 2 A Spi1 Spi 3 A Spi4 Spi 1 B Spi4 Spi 2 B Spi4 Spi 3 B Spi2 Spi 2 A Spi2 Spi 3 A Spi3 Spi 1 A Spi3 Spi 2 A Spi3 Spi 3 A Spi5 Spi 2 B Spi5 Spi 3 B Gfa5 Gfa 1 B Gfa5 Gfa 2 B Gfa5 Gfa 3 B ", header = TRUE) # 预处理:生成完整样本网格 full_grid <- data %>% # 获取每个物种的所有唯一样本ID group_by(Species) %>% summarize(all_samples = list(unique(Sample_ID)), .groups = "drop") %>% # 获取每个物种的最大样本数(所有处理组中的最大值) mutate(max_samples = lengths(all_samples)) %>% # 为每个处理组生成该物种的所有样本(包括占位空样本) crossing(Treatment = unique(data$Treatment)) %>% unnest(all_samples) %>% rename(Sample_ID = all_samples) %>% # 按物种和样本ID排序,保证嵌套结构 arrange(Species, Sample_ID) %>% # 为每个处理组-物种组合的样本分配Y轴位置(保证同一物种位置对齐) group_by(Treatment, Species) %>% mutate(y_pos = row_number()) %>% ungroup() %>% # 左连接原始数据,标记是否有测量数据 left_join(data, by = c("Sample_ID", "Species", "Treatment")) %>% # 转换Time为因子,方便绘图 mutate(Time = as.factor(Time)) # 调整Y轴标签的嵌套显示:将物种名添加到样本ID前 full_grid <- full_grid %>% mutate(Sample_with_Species = paste(Species, Sample_ID, sep = " - ")) %>% # 按物种和y_pos排序,确保同一物种的样本在Y轴上连续 mutate(Sample_with_Species = fct_reorder(Sample_with_Species, y_pos))
2. 可视化代码
使用预处理后的完整数据集绘图,实现物种对齐和空行占位:
ggplot(full_grid, aes(x = Time, y = Sample_with_Species, color = Species)) + # 绘制已完成测量的点 geom_point(data = filter(full_grid, !is.na(Time)), size = 3, show.legend = FALSE) + # 为缺失测量的位置添加灰色占位点(可根据需求移除) geom_point(data = filter(full_grid, is.na(Time)), size = 3, color = "lightgray", alpha = 0.3) + # X轴标签替换 scale_x_discrete(labels = c("t1", "t2", "t3"), drop = FALSE) + # 颜色方案 scale_color_brewer(palette = "Dark2") + # 按处理组分面,Y轴自由缩放但因预处理已对齐 facet_wrap(~Treatment, scales = "free_y", strip.position = "top", ncol = 3) + # 主题调整 theme_bw() + theme( strip.background = element_rect(color = "transparent", fill = "white"), axis.title.y = element_blank(), # 可选:Y轴标签按物种分组添加分隔线 panel.grid.major.y = element_line(color = "lightgray", linetype = "dashed") )
效果说明
- 不同处理组(Treatment A/B)中,同一物种的样本Y轴位置完全对齐,比如Amu物种在A组有4行样本,B组有2行有效样本+2行灰色占位空行,间距一致
- Y轴标签显示物种+样本ID,清晰区分嵌套结构
- 已完成测量用彩色点显示,缺失测量用灰色占位点(可根据需求移除)
内容的提问来源于stack exchange,提问作者Erik
相关产品推荐
相关产品推荐

