R pheatmap隐藏列名时自定义行名颜色报错原因及实现方法
问题背景
Windows 10系统RStudio环境下,使用R语言pheatmap包绘制热图时,参考公开实现方案可在同时展示行名、列名的热图中完成行名选择性着色;但设置参数隐藏列名、仅对指定行名设置自定义颜色时,会触发如下报错:Error in set.gpar(x$gp, grob = x) : argument must be a 'gpar' object
测试数据构造代码
构造测试用表达矩阵的代码如下:
library(pheatmap) test = matrix(rnorm(200), 20, 10) test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3 test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2 test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4 colnames(test) = paste("Test", 1:10, sep = "") rownames(test) = paste("Gene", 1:20, sep = "")
可正常运行的参考实现
同时显示行名、列名时,指定行名标红的着色代码可正常运行,代码如下:
library(grid) library(gridExtra) library(pheatmap) hm <- pheatmap(test, silent = TRUE) hm$gtable$grobs[[5]]$gp$col <- rep(c("black", "red"), each = 10) leg <- legendGrob(c("Exp1", "Exp2"), nrow = 2, pch = 15, gp = gpar(fontsize = 10, col = c("black", "red"))) hm2 <- arrangeGrob(hm$gtable, leg, ncol = 2, widths = c(5,1)) grid.draw(hm2)
报错场景复现
设置show_colnames=FALSE参数隐藏列名,运行如下代码时会触发前述gpar对象报错:
# 注:原复现代码存在笔误,漏写了hm <- 变量赋值 hm <- pheatmap(test, show_colnames=FALSE, silent=TRUE) hm$gtable$grobs[[5]]$gp$col <- rep(c("black", "red"), each = 10) leg <- legendGrob(c("Exp1", "Exp2"), nrow = 2, pch = 15, gp = gpar(fontsize = 10, col = c("black", "red"))) hm2 <- arrangeGrob(hm$gtable, leg, ncol = 2, widths = c(5,1)) grid.draw(hm2)
问题解答
1. 报错根本原因
- 参考代码硬编码了行名对应的图形对象(grob)索引为
[[5]],这个索引仅在同时显示行名、列名时成立:此时pheatmap生成的gtable组件排布顺序固定,行名文本刚好是第5个grob对象。 - 当设置
show_colnames=FALSE隐藏列名后,pheatmap不会生成列名对应的grob,gtable内所有组件的索引整体前移,此时第5位的grob不再是行名文本,而是聚类树、热图主体这类没有文本颜色属性的组件,强行修改它的gp$col参数时,就会触发「传入参数不是合法gpar对象」的报错。 - 补充:复现代码第一行漏了
hm <-赋值,直接调用pheatmap()不会把绘图结果存入hm变量,也会导致后续对象不存在的报错,但这不是gpar报错的核心诱因。
2. 隐藏列名时实现行名选择性着色的方案
核心思路是放弃硬编码grob索引,先遍历hm$gtable$grobs定位到真正对应行名的文本grob,再修改它的颜色属性即可,全程仅依赖pheatmap、grid、gridExtra包,不需要替换其他热图包。
可直接运行的代码如下:
library(grid) library(gridExtra) library(pheatmap) # 绘制热图,设置隐藏列名 hm <- pheatmap(test, show_colnames = FALSE, silent = TRUE) # 动态查找行名对应的grob:匹配text类型、标签与矩阵行名完全一致的对象 row_name_grob_idx <- which(sapply(hm$gtable$grobs, function(g){ inherits(g, "text") && identical(g$label, rownames(test)) })) # 给行名设置自定义颜色,示例为前10个行名黑色、后10个行名红色 hm$gtable$grobs[[row_name_grob_idx]]$gp$col <- rep(c("black", "red"), each = 10) # 添加分类图例并输出图像 leg <- legendGrob(c("Exp1", "Exp2"), nrow = 2, pch = 15, gp = gpar(fontsize = 10, col = c("black", "red"))) hm2 <- arrangeGrob(hm$gtable, leg, ncol = 2, widths = c(5,1)) grid.draw(hm2)
该方案不受show_colnames、是否显示聚类树等参数影响,只要行名正常显示,就能准确定位到对应组件完成颜色修改。如果需要自定义其他行的颜色,只需要调整传给gp$col的颜色向量,保证长度、顺序和行名一一对应即可。
内容的提问来源于stack exchange,提问作者Hypersphere
相关产品推荐
相关产品推荐

