R语言ComplexHeatmap热图P值显著性星号错位及NA处理求助
星号标注错位的原因与解决方法
核心原因
你遇到的标注错位问题由两个常见触发点导致:
- ComplexHeatmap的
Heatmap函数默认会对行、列执行层次聚类并重排顺序,你在cell_fun中调用的sx_syn_p[i,j]取的是原始P值表的第i行第j列,但热图渲染时的第i行第j列已经是聚类重排后的位置,和原始P值表的行列顺序无法对应 - 读入P值CSV时如果没有指定行名参数,读入的
data.frame第一列为行名字符串,实际数值列的数量和热图输入矩阵sx_syn的列数不匹配,也会导致索引错位
修复方案
分两种场景选择适配方案:
场景1:不需要保留行/列聚类,直接用原始顺序展示
在Heatmap参数中显式关闭聚类,强制行、列和原始P值表顺序对齐即可,修改代码如下:
library(circlize) library(ComplexHeatmap) library(Hmisc) # 读入P值表时指定行名,转为和sx_syn维度完全匹配的数值矩阵 sx_syn_p <- read.csv('spear_synx1_p.csv', header=TRUE, row.names = 1) |> as.matrix() Shime1x_syn_spearman1 <- Heatmap(sx_syn, circlize::colorRamp2(c(-1, -0.5, 0, 0.5, 1), c('#d7191c', '#fdae61', '#FFFFFF', '#abd9e9', '#2c7bb6')), # 显式关闭行、列聚类,保持原始顺序 cluster_rows = FALSE, cluster_columns = FALSE, column_names_gp=grid::gpar(fontsize=20, col=c(rep('#4daf4a', 8), rep('#984ea3',7))), row_names_gp=grid::gpar(fontsize=20, col=c(rep('#4daf4a', 8), rep('#984ea3',7))), heatmap_legend_param=list(title="Spearman's rho", direction='horizontal', at = c(-1, -0.5, 0, 0.5, 1)), cell_fun = function(j, i, x, y, w, h, fill){ if(sx_syn_p[i, j] < 0.05) { # 可自行调整字号避免和热图内容重叠 grid.text('*', x, y, gp = gpar(fontsize = 16)) } }) sx_syn1_spear <- draw(Shime1x_syn_spearman1, heatmap_legend_side='top')
场景2:需要保留行/列聚类效果
先预构建热图对象拿到聚类后的行列顺序,再把P值表按该顺序重排后再用于标注,代码如下:
library(circlize) library(ComplexHeatmap) library(Hmisc) sx_syn_p <- read.csv('spear_synx1_p.csv', header=TRUE, row.names = 1) |> as.matrix() # 预构建热图,获取聚类后的行列顺序,不需要绘制 ht_temp <- Heatmap(sx_syn, circlize::colorRamp2(c(-1, -0.5, 0, 0.5, 1), c('#d7191c', '#fdae61','#FFFFFF', '#abd9e9', '#2c7bb6')), column_names_gp=grid::gpar(fontsize=20,col=c(rep('#4daf4a', 8), rep('#984ea3',7))), row_names_gp=grid::gpar(fontsize=20, col=c(rep('#4daf4a', 8), rep('#984ea3',7))), heatmap_legend_param=list(title="Spearman's rho", direction='horizontal',at = c(-1, -0.5, 0, 0.5, 1)) ) # 按聚类后的顺序重排P值矩阵 sx_syn_p_ordered <- sx_syn_p[ht_temp@row_order, ht_temp@column_order] # 用重排后的P值矩阵生成带标注的最终热图 Shime1x_syn_spearman1 <- Heatmap(sx_syn, circlize::colorRamp2(c(-1, -0.5, 0, 0.5, 1), c('#d7191c', '#fdae61','#FFFFFF', '#abd9e9', '#2c7bb6')), column_names_gp=grid::gpar(fontsize=20,col=c(rep('#4daf4a', 8), rep('#984ea3',7))), row_names_gp=grid::gpar(fontsize=20, col=c(rep('#4daf4a', 8), rep('#984ea3',7))), heatmap_legend_param=list(title="Spearman's rho", direction='horizontal',at = c(-1, -0.5, 0, 0.5, 1)), cell_fun = function(j, i, x, y, w, h, fill){ if(sx_syn_p_ordered[i, j] < 0.05) { grid.text('*', x, y, gp = gpar(fontsize = 16)) } }) sx_syn1_spear <- draw(Shime1x_syn_spearman1, heatmap_legend_side='top')
更优的P值NA处理方案
你当前把NA替换为1的方案可以实现需求,但会修改原始P值数据,更推荐在cell_fun中直接增加NA判断,不需要提前修改原始数据:
cell_fun = function(j, i, x, y, w, h, fill){ p_val <- sx_syn_p_ordered[i, j] # 跳过NA值,仅对有效P值做阈值判断 if(!is.na(p_val) && p_val < 0.05) { grid.text('*', x, y, gp = gpar(fontsize = 16)) } }
如果需要区分显著性等级,也可以直接在该逻辑中扩展:比如p<0.01标**,p<0.001标***。
内容的提问来源于stack exchange,提问作者Coldgrad
相关产品推荐
相关产品推荐

