如何解决指定group美学后geom_ridgeline_gradient绘图异常问题
问题背景
我需要绘制左侧为系统发育树、右侧为脊线图的组合图,脊线图用于可视化不同DNA基序的存在情况,每个序列与系统发育树的叶节点对应,目标是实现类似图9.4的效果,使用自定义数据与geom_ridgeline_gradient完成。但指定group美学映射后,geom_ridgeline_gradient的渲染出现异常;不指定group时绘图正常,但为了兼容ggtree必须使用group参数。以下是复现问题的最小示例代码:
library(ggridges) library(ggtree) library(data.table) library(ggplot2) minimal_data1 <- data.table( seq = rep("seq1", 20), id = rep(1, 20), pos = rep(seq(1, 10), 2), height = c(c(0, 0, 0, 1, 1, 1, 1, 0, 0, 0), c(0, 0, 0, 0, 0, 1, 1, 1, 1, 0)), # 重叠基序 annotation = c(c(NA, NA, NA, "A", "A", "A", "A", NA, NA, NA), c(NA, NA, NA, NA, NA, "C", "C", "C", "C", NA)) ) minimal_data2 <- data.table( seq = rep("seq_2", 10), id = rep(2, 10), pos = seq(1, 10), height = c(0, 0, 0, 0, 1, 1, 1, 1, 0, 0), annotation = c(NA, NA, NA, NA, "B", "B", "B", "B", NA, NA) ) minimal_data3 <- data.table( seq = rep("seq_3", 10), id = rep(2, 10), pos = seq(1, 10), height = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), # 无任何基序的序列 annotation = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA) ) minimal_data <- rbindlist(list(minimal_data1, minimal_data2, minimal_data3)) # 正常渲染的代码 ggplot(minimal_data, aes(x=pos, y=seq, height=height, fill=annotation)) + geom_ridgeline_gradient(scale=0.3) + scale_fill_discrete(na.translate=FALSE) # 渲染异常的代码 ggplot(minimal_data, aes(x=pos, y=seq, group=seq, height=height, fill=annotation)) + geom_ridgeline_gradient(scale=0.3) + scale_fill_discrete(na.translate=FALSE)
异常原因
当指定group=seq时,geom_ridgeline_gradient会将同一seq下的所有数据点视为一个连续的组进行绘制。以seq1为例,它包含20行数据(对应两个重叠的基序,存在重复的pos值),这会导致绘图时线条在重复的x位置出现交叉、填充区域混乱——因为函数默认按数据顺序连接所有点,重复的x值打破了脊线图需要的连续单调x序列逻辑。
而不指定group时,ggplot会自动根据fill=annotation进行分组,将不同的基序(包括NA对应的空白区域)拆分为独立的组分别绘制,因此能正常展示重叠的基序。
修复方案
需要使用更精细的分组逻辑,将同一序列下的不同基序(包括无基序的情况)拆分为独立的组,同时满足ggtree对group参数的要求。具体做法是用interaction(seq, ifelse(is.na(annotation), "none", annotation))作为分组变量,把NA替换为占位符"none"(避免NA无法作为分组键的问题),确保每个基序块都是独立的绘制单元。
修复后的代码示例:
# 修复后的绘图代码 ggplot(minimal_data, aes(x=pos, y=seq, group=interaction(seq, ifelse(is.na(annotation), "none", annotation)), height=height, fill=annotation)) + geom_ridgeline_gradient(scale=0.3) + scale_fill_discrete(na.translate=FALSE)
如果需要兼容ggtree的布局,还可以进一步调整分组逻辑,确保分组与系统发育树的叶节点映射一致,同时保留脊线图的正确渲染。
内容的提问来源于stack exchange,提问作者Kqwer

