R语言: 从pheatmap无缝迁移至ComplexHeatmap

pheatmap是一个非常受欢迎的绘制热图的R包。ComplexHeatmap包即是受之启发而来。你可以发现Heatmap()函数中很多参数都与pheatmap()相同。在pheatmap的时代(请允许我这么说),pheatmap意思是pretty heatmap,但是随着时间推进,技术发展,各种新的数据出现,pretty is no more pretty,我们需要更加复杂和更有效率的热图可视化方法对庞大的数据进行快速并且有效的解读,因此我开发并且一直维护和改进着ComplexHeatmap包。为了使庞大并且“陈旧”的(对不起,我不应该这么说。)pheatmap用户群能够迅速并且无痛的迁移至ComplexHeatmap,从2.5.2版本开始,我在ComplexHeatmap包中加入了一个pheatmap()函数,它涵盖了pheatmap::pheatmap()所有的功能,也就是说,它提供了和pheatmap::pheatmap()一模一样的参数,并且生成的热图的样式也几乎相同。同时,ComplexHeatmap::pheatmap()函数也能使用ComplexHeatmap独有的功能,比如对行和列进行切分,加入自定义的annotation,多个热图和annotation的连接,或者创建一个互动的热图(interactive heatmap, 通过ht_shiny()函数)

ComplexHeatmap::pheatmap()包含了pheatmap::pheatmap()中所有的参数,这意味着,当你从pheatmap迁移至ComplexHeatmap时,你无需添加任何额外的步骤,你只需要载入ComplexHeatmap而不是pheatmap包,然后重新运行你原始的pheatmap代码。剩下的你只是去见证奇迹的发生。

注意如下五个pheatmap::pheatmap()的参数在ComplexHeatmap::pheatmap()中被忽视:

  • kmeans_k:在pheatmap::pheatmap()中,如果这个参数被设定,输入矩阵会进行k均值聚类,然后每个cluster使用其均值向量表示。最终的热图是k个均值向量的热图。此操作改变了原始矩阵的大小,而且每个cluster的大小信息丢失了,直接解读均值向量可能会造成对数据的误解。我不赞成此操作,因此我没有支持这个参数。在ComplexHeatmap中,row_kmcolumn_km参数可能是一个更好的选择。
  • filename:如果这个参数被设定,热图直接保存至指定的文件中。我认为这只是画蛇添足(没有贬低pheatmap的意思,只是最近在给小孩讲成语故事,然后想在这里使用一下)的一步,ComplexHeatmap::pheatmap()不支持此参数。
  • width:filename的宽度。
  • height:filename的长度。
  • silent: 是否打印信息。

pheatmap::pheatmap()中,color参数需要设置为一个长长的颜色向量(如果你想用100种颜色的话),比如:

pheatmap::pheatmap(mat,     color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdYlBu")))(100))

ComplexHeatmap::pheatmap()中,你可以简化无需使用colorRampPalette()去扩展更多的颜色,你可以直接简化为如下,颜色会被自动插值和扩展。

ComplexHeatmap::pheatmap(mat,     color = rev(brewer.pal(n = 7, name = "RdYlBu")))

例子

我们首先创建一个随机数据,这个来自于pheatmap包中提供的例子(https://rdrr.io/cran/pheatmap/man/pheatmap.html).

test = matrix(rnorm(200), 20, 10)test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4colnames(test) = paste("Test", 1:10, sep = "")rownames(test) = paste("Gene", 1:20, sep = "")

我们载入ComplexHeatmap包,然后执行pheatmap()函数,生成一副和pheatmap::pheatmap()非常类似的热图。

library(ComplexHeatmap)# 注意这是ComplexHeatmap::pheatmappheatmap(test)
image

ComplexHeatmap::pheatmap()中,按照pheatmap::pheatmap()的样式进行了相应的配置,因此,大部分元素的样式一模一样。只有少部分不一致,比如说热图的legend。

下一个例子是在热图中加入annotation。以下代码是在pheatmap()中添加annotation。如果你是pheatmap()用户,你应该对annotation的数据格式不太陌生。

annotation_col = data.frame(    CellType = factor(rep(c("CT1", "CT2"), 5)),     Time = 1:5)rownames(annotation_col) = paste("Test", 1:10, sep = "")annotation_row = data.frame(    GeneClass = factor(rep(c("Path1", "Path2", "Path3"), c(10, 4, 6))))rownames(annotation_row) = paste("Gene", 1:20, sep = "")ann_colors = list(    Time = c("white", "firebrick"),    CellType = c(CT1 = "#1B9E77", CT2 = "#D95F02"),    GeneClass = c(Path1 = "#7570B3", Path2 = "#E7298A", Path3 = "#66A61E"))pheatmap(test,     annotation_col = annotation_col,     annotation_row = annotation_row,     annotation_colors = ann_colors)
image

看起来和pheatmap::pheatmap()还是很一致。

ComplexHeatmap::pheatmap()内部其实使用了Heatmap()函数,因此更多的参数都最终传递给了Heatmap()。我们可以在pheatmap()中使用一些Heatmap()特有的参数,比如row_splitcolumn_split来对行和列进行切分。

pheatmap(test,     annotation_col = annotation_col,     annotation_row = annotation_row,     annotation_colors = ann_colors,     row_split = annotation_row$GeneClass,    column_split = annotation_col$CellType)
image

ComplexHeatmap::pheatmap()返回一个Heatmap对象,因此它可以与其他Heatmap/HeatmapAnnotation对象连接。换句话说,你可以使用炫酷的+或者%v%对多个pheatmap水平连接或者垂直连接。

p1 = pheatmap(test, name = "mat1")p2 = rowAnnotation(foo = anno_barplot(1:nrow(test)))p3 = pheatmap(test, name = "mat2",     col = c("navy", "white", "firebrick3"))p1 + p2 + p3
image

ComplexHeatmap支持将一个热图导出为一个shiny app,这也同样适用于pheatmap(),因此你可以这样做:

ht = pheatmap(...)ht_shiny(ht) # 强烈建议试一试

还有一件重要的小事是,因为ComplexHeatmap::pheatmap()返回一个Heatmap对象,如果pheatmap()并没有在一个interactive的环境执行,比如说在一个R脚本中,或者在一个函数/for loop中,你应该显式的调用draw()函数进行画图。

for(...) {    p = pheatmap(...)    draw(p)}

最后我想说的事,这篇文章的主旨并不是鼓励用户直接使用ComplexHeatmap::pheatmap(),我只是在此展示了pheatmap完全可以用ComplexHeatmap来代替,而且ComplexHeatmap提供了工具让用户无需任何额外的操作(zero effort)就可以迁移以前旧的代码。但是我还是强烈建议用户直接使用ComplexHeatmap中的“正经函数”。

从pheatmap到ComplexHeatmap的翻译

在“阅读原文”中,你可以找到一个表格,其中详细的列出了如何将pheatmap::pheatmap()中的参数对应到Heatmap()中。

比较

这一小节我比较了相同参数下pheatmap::pheatmap()生成的热图和ComplexHeatmap::pheatmap()的相似度。我使用了pheatmap包中所有的例子(https://rdrr.io/cran/pheatmap/man/pheatmap.html)。同时我也使用了ComplexHeatmap中提供的一个简单的帮助函数ComplexHeatmap::compare_pheatmap()。它的功能就是把参数同时传递给pheatmap::pheatmap()ComplexHeatmap::pheatmap(),然后生成两幅热图,这样可以直接进行比较。因此如下代码

compare_pheatmap(test)

其实等同于:

pheatmap::pheatmap(test)ComplexHeatmap::pheatmap(test)

在往下阅读之前,我先告诉你结论:pheatmap::pheatmap()ComplexHeatmap::pheatmap()产生的热图几乎完全相同。

只提供一个矩阵:

compare_pheatmap(test)
image

对列进行z-score归一化,行聚类距离使用相关性距离:

compare_pheatmap(test,     scale = "row",     clustering_distance_rows = "correlation")
image

设定颜色:

compare_pheatmap(test,     color = colorRampPalette(c("navy", "white", "firebrick3"))(50))
image

不对行聚类:

compare_pheatmap(test,     cluster_row = FALSE)
image

不显示legend:

compare_pheatmap(test,     legend = FALSE)
image

在矩阵格子上显示数值:

compare_pheatmap(test,     display_numbers = TRUE)
image

对矩阵格子上的数值进行格式化:

compare_pheatmap(test,     display_numbers = TRUE,     number_format = "%.1e")
image

自定义矩阵格子上的文字:

compare_pheatmap(test,     display_numbers = matrix(ifelse(test > 5, "*", ""),                              nrow(test)))
image

定义legend上的label:

compare_pheatmap(test,     cluster_row = FALSE,     legend_breaks = -1:4,     legend_labels = c("0", "1e-4", "1e-3", "1e-2", "1e-1", "1"))
image

热图的标题:

compare_pheatmap(test,     cellwidth = 15,     cellheight = 12,     main = "Example heatmap")
image

添加列的annotation:

annotation_col = data.frame(    CellType = factor(rep(c("CT1", "CT2"), 5)),     Time = 1:5)rownames(annotation_col) = paste("Test", 1:10, sep = "")annotation_row = data.frame(    GeneClass = factor(rep(c("Path1", "Path2", "Path3"), c(10, 4, 6))))rownames(annotation_row) = paste("Gene", 1:20, sep = "")compare_pheatmap(test,     annotation_col = annotation_col)
image

不绘制annotation的legend:

compare_pheatmap(test,     annotation_col = annotation_col,     annotation_legend = FALSE)
image

同时添加行和列的annotation:

compare_pheatmap(test,     annotation_col = annotation_col,     annotation_row = annotation_row)
image

调整列名的旋转:

compare_pheatmap(test,     annotation_col = annotation_col,     annotation_row = annotation_row,     angle_col = "45")
image

调整列名的旋转至水平方向:

compare_pheatmap(test,     annotation_col = annotation_col,     angle_col = "0")
image

控制annotation的颜色:

ann_colors = list(    Time = c("white", "firebrick"),    CellType = c(CT1 = "#1B9E77", CT2 = "#D95F02"),    GeneClass = c(Path1 = "#7570B3", Path2 = "#E7298A", Path3 = "#66A61E"))compare_pheatmap(test,     annotation_col = annotation_col,     annotation_colors = ann_colors,     main = "Title")
image

同时控制行和列annotation的颜色:

compare_pheatmap(test,     annotation_col = annotation_col,    annotation_row = annotation_row,     annotation_colors = ann_colors)
image

只提供部分annotation的颜色,未提供颜色的annotation使用随机颜色:

compare_pheatmap(test,     annotation_col = annotation_col,     annotation_colors = ann_colors[2]) 
image

将热图分为两部分,我建议直接使用Heatmap()中的row_split或者row_km参数。

compare_pheatmap(test,     annotation_col = annotation_col,     cluster_rows = FALSE,     gaps_row = c(10, 14))
image

使用cutree()对列的dendrogram切分:

compare_pheatmap(test,     annotation_col = annotation_col,     cluster_rows = FALSE,     gaps_row = c(10, 14),     cutree_col = 2)
image

自定义行名:

labels_row = c("", "", "", "", "", "",     "", "", "", "", "", "", "", "", "",     "", "", "Il10", "Il15", "Il1b")compare_pheatmap(test,     annotation_col = annotation_col,     labels_row = labels_row)
image

自定义聚类的距离:

drows = dist(test, method = "minkowski")dcols = dist(t(test), method = "minkowski")compare_pheatmap(test,     clustering_distance_rows = drows,     clustering_distance_cols = dcols)
image

对聚类的回调处理:

library(dendsort)callback = function(hc, ...){dendsort(hc)}compare_pheatmap(test,     clustering_callback = callback)
image

文章转载自:【https://mp.weixin.qq.com/s?__biz=MzUzMzMwNjgzNA==&mid=2247488608&idx=1&sn=34e4b3fbb7584016976a2762ec249005&chksm=faa758ddcdd0d1cba062c1619e69d60bb9ff35e0d5086e2e7e08b30593bbaaf1c0344c650e4f&mpshare=1&scene=1&srcid=1129QpMCXENZ5MGFhgJp0bb2&sharer_sharetime=1606639806017&sharer_shareid=5e26caa3a2ed75e9d7c29e213ad5207a&key=41897554b8f6847e25c08aa02e9b63c319268bb40a0e7fdc3c06ca0da729b7d1e2bfc8aff56e1b0f07660939647bfc3e52ca7f14db0a45435025627cba4aaeee66e9050af3adb28fc9c4ad7531bbb03057e348b12ec5882c68d569eba055923fe3bdb30db82dd40972d3f7ccfd5c3f22c31fb5ffb2d811a9715a6ce440e7f36e&ascene=1&uin=MjY2MjY3OTUzMw%3D%3D&devicetype=Windows+8+x64&version=6300002f&lang=zh_CN&exportkey=A0bW8nRpQ9CIxwAto8jHEsk%3D&pass_ticket=9O5%2FRZux9VSyxlHx2C5QWqp5tCm4%2F7SLjOJEiKH56nP9PVovBrBu7uHVgb%2F9fBh%2B&wx_header=0

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容