使用ggplot2的scale_x_manual调整小提琴图间距后统计标记错位问题
问题描述
使用scale_x_manual函数成功为ggplot2中的小提琴图添加了间距,但图上方的统计显著性标记并未随之移动,出现位置错位的情况,请问该如何修复?
代码片段
# violin plot with noise if(i != gene[length(gene)]){ if (any(i == gene[seq(1, length(gene),by=7)])){ plot_list_vln_df[[i]] <- vln_df[[i]] %>% ggplot(mapping=aes(x=Subset, y=Expression)) + geom_violin(mapping=aes(x=Subset, y=Expression, fill= Subset), scale = "width", width= 0.8)+ scale_x_manual(as.double(c(1:3, 5:7 , 9:11, 13:16))) +scale_fill_manual(values = alpha((mycolors),0.9))+ geom_boxplot(outlier.size = 0.01, width=0.3, size=0.5, alpha=0.4) + theme_bw()+ xlab("") + ggtitle(label=i) + stat_pvalue_manual(pwc[[i]], hide.ns = F, y.position = y.position, label = "FDR.signif", size = p.val.size, tip.length = 0) + labs(subtitle = get_test_label(vln_df[[i]] %>% kruskal_test(Expression ~ Subset) %>% mutate(KW_FDR = p.adjust (p, method='BH')) %>% add_significance(p.col = "KW_FDR"), p.col = "KW_FDR.signif", detailed=F, description = "KW (FDR)"))+ylim + theme(panel.grid = element_blank(),axis.title.y = element_text(size = 12), axis.text.y = element_text(size=12), axis.text.x = element_blank(), axis.ticks.x = element_blank(), plot.title = element_text(hjust = 0.5, size=plot.title.size, face = "bold"), plot.subtitle = element_text(size = 9))+ylab("Expression")+ theme(legend.position = "none" , aspect.ratio = 1) }
问题图示

修复方案
核心问题是:stat_pvalue_manual默认基于原始x轴类别位置计算标记坐标,而你用scale_x_manual手动修改了x轴数值位置,两者没有同步。下面是两种直接可行的解决方法:
方法一:手动同步显著性标记的x轴位置
给stat_pvalue_manual指定和小提琴图一致的新x轴位置:
- 先整理原始类别到新位置的映射表,比如你的
scale_x_manual用了c(1:3,5:7,9:11,13:16),对应所有Subset类别:x_pos_map <- c( "类别A" = 1, "类别B" = 2, "类别C" = 3, "类别D" = 5, "类别E" = 6, "类别F" = 7, "类别G" = 9, "类别H" = 10, "类别I" = 11, "类别J" = 13, "类别K" = 14, "类别L" = 15, "类别M" = 16 ) - 修改
stat_pvalue_manual参数,用映射表调整标记的起始和结束位置:
如果是单个组的标记而非组间连线,只需要指定stat_pvalue_manual(pwc[[i]], hide.ns = F, y.position = y.position, label = "FDR.signif", size = p.val.size, tip.length = 0, x = ~x_pos_map[group1], xend = ~x_pos_map[group2])x参数即可。
方法二:先转x轴为数值型(更推荐)
放弃scale_x_manual,提前把Subset转换成带间距的数值,让ggplot和标记共享同一坐标体系:
- 预处理数据,添加数值型x列:
vln_df[[i]] <- vln_df[[i]] %>% mutate(Subset_num = case_when( Subset == "类别A" ~ 1, Subset == "类别B" ~ 2, Subset == "类别C" ~ 3, Subset == "类别D" ~ 5, Subset == "类别E" ~ 6, # 依次对应所有Subset到你想要的数值位置 TRUE ~ NA_real_ )) - 修改ggplot的x映射为
Subset_num,并设置刻度标签保持原类别名:
这种方法从根源上避免了坐标错位,后续调整也更灵活。ggplot(mapping=aes(x=Subset_num, y=Expression)) + geom_violin(mapping=aes(fill= Subset), scale = "width", width= 0.8)+ scale_x_continuous( breaks = c(1:3,5:7,9:11,13:16), labels = c("类别A","类别B","类别C","类别D","类别E",...) # 对应所有Subset名称 ) + # 同步调整stat_pvalue_manual的x位置 stat_pvalue_manual(pwc[[i]], hide.ns = F, y.position = y.position, label = "FDR.signif", size = p.val.size, tip.length = 0, x = ~case_when(group1 == "类别A"~1, group1=="类别B"~2, ...), xend = ~case_when(group2 == "类别A"~1, group2=="类别B"~2, ...))
额外提示
- 确保
pwc[[i]]数据框里的group1和group2列能准确对应你的Subset类别,否则映射会出错。 - 可以先拿单个基因的图做测试,确认位置正确后再批量处理。
内容的提问来源于stack exchange,提问作者Eli
相关产品推荐
相关产品推荐

