You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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轴位置:

  1. 先整理原始类别到新位置的映射表,比如你的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
    )
    
  2. 修改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和标记共享同一坐标体系:

  1. 预处理数据,添加数值型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_
      ))
    
  2. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 00:08:27