【R画图学习24.1】ComplexHeatmap绘制复杂热图(1)

热图(Heatmap)是矩阵类型数据最为常用的可视化方法,在生物学领域常用于各种组学数据的可视化,例如基因表达量数据、物种丰度分布、表观遗传信号数据等,我们前面也介绍过普通的热图绘制方法,例如pheatmap以及环形热图gheatmap等。但是,现如今多组学数据不断涌现, 现有的R语言包例如 gplots、pheatmap、ggplot2绘制热图的功能较为单一,已无法满足大家从多个维度、对多类型数据更加充分可视化的需求,例如下面的图。ComplexHeatmap 由德国国家肿瘤疾病中心顾顾祖光博士开发,该R包正如其名一样复杂,但是其绘制热图功能却堪称全面。所以我们也陆续学习一下这个包的功能和应用。

=========安装=======

library(devtools)

# 检查热图包,没有则通过github安装最新版

if (!require("ComplexHeatmap"))

install_github("jokergoo/ComplexHeatmap")

# ComplexHeatmap依赖关系

if (!require("circlize"))

install_github("jokergoo/circlize")

# 用于绘制矩阵列方向上的层次聚类结果

if (!require("dendextend"))

install.packages('dendextend')

# 加载包

library(ComplexHeatmap)

library(circlize)

library(dendextend)

=========测试==========

生成一组测试数据:

nr1 = 4; nr2 = 8; nr3 = 6; nr = nr1 + nr2 + nr3

nc1 = 6; nc2 = 8; nc3 = 10; nc = nc1 + nc2 + nc3


mat = cbind(rbind(matrix(rnorm(nr1*nc1, mean = 1,  sd = 0.5), nr = nr1),

matrix(rnorm(nr2*nc1, mean = 0,  sd = 0.5), nr = nr2),

matrix(rnorm(nr3*nc1, mean = 0,  sd = 0.5), nr = nr3)),

rbind(matrix(rnorm(nr1*nc2, mean = 0,  sd = 0.5), nr = nr1),

matrix(rnorm(nr2*nc2, mean = 1,  sd = 0.5), nr = nr2),

matrix(rnorm(nr3*nc2, mean = 0,  sd = 0.5), nr = nr3)),

rbind(matrix(rnorm(nr1*nc3, mean = 0.5, sd = 0.5), nr = nr1),

matrix(rnorm(nr2*nc3, mean = 0.5, sd = 0.5), nr = nr2),

matrix(rnorm(nr3*nc3, mean = 1,  sd = 0.5), nr = nr3))

)


mat = mat[sample(nr, nr), sample(nc, nc)] # 打乱数据

rownames(mat) = paste0("row", seq_len(nr)) # 行命名

colnames(mat) = paste0("column", seq_len(nc)) # 列命名

这样子一组简单的测试数据就准备好了:

Heatmap(mat)   #生成一个最基本的heatmap

从默认结果来看:这个包中最重要的函数Heatmap()绘制一张简单的热图,默认参数下,会生成图例、行列名并对行列分别聚类,聚类方法用complete层次聚类方法。


下面我们开始美化,比如控制着色。


比如我们相对列的聚类树按cluster着色,首先需要分成不同的cluster。

# 层次聚类

column_dend = as.dendrogram(hclust(dist(t(mat))))    #获得列进化树信息

# 分支着色

column_dend = color_branches(column_dend, k = 3)  #分成3个分支,进行不同颜色着色


Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3  # 列分割数

        )

依据前面我们的列指定信息,可以看出列的聚类树分成了3个颜色。column_split则把整个图按列分成了3个部分。

对于长度的控制,由于ComplexHeatmap基于grid绘图框架,所以凡是量化长度的参数都需要用unit()函数制定,例如下面的row_dend_width,可以看出在对行聚类树的宽度的控制。

p1<-Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        #column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3,  # 列分割数

        row_dend_width = unit(2, "cm"), # 行聚类树的宽度

        )

p1

p2<-Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        #column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3,  # 列分割数

        row_dend_width = unit(10, "cm"), # 行聚类树的宽度

        )

p2

另外,ComplexHeatmap包的一个主要优点是它支持按行和列拆分热图以更好地对特征进行分组,便于突出显示各组的信息。以下参数控制拆分:row_km, row_split, column_km, column_split。比如上面我们用column_split就是把列分成了3个部分。row_km和column_km是按照 k-means方法分割,就如我们上述指定的column方法是按距离分割,这是两个不一样的分割算法。而row_split或者column_split可以设置为分类向量或数据框,从分割算法来看是和默认的距离算法是一致的。


Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3,  # 列分割数

        row_dend_width = unit(2, "cm"), # 行聚类树的宽度

        row_km = 2 # 行k-means聚类的类别数

        )

下图就是把行按kmeans分成了2类。

Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 2,  # 列分割数

        row_dend_width = unit(2, "cm"), # 行聚类树的宽度

        row_split = rep(c("A", "B"), 9), # 行分割后的命名

        #row_km = 2 # 行k-means聚类的类别数

        )

这个是用row_split的方式,rep(c("A", "B"), 9)相当于生成了ABAB...这样子的数据框,然后A的列放在一起,B的列放在一起。从而把row分成了2个部分。

Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3,  # 列分割数

        row_dend_width = unit(2, "cm"), # 行聚类树的宽度

        #row_split = rep(c("A", "B"), 9), # 行分割后的命名

        #row_km = 2 # 行k-means聚类的类别数

        row_split = data.frame(rep(c("A", "B"), 9), rep(c("C", "D"), each = 9))

        )

这样子就是生成了一个更复杂的数据框,生成了两列,但是unique的数据的话有A.C A.D B.C B.D所以按unique的属性分成了4不部分。

Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3,  # 列分割数

        row_dend_width = unit(2, "cm"), # 行聚类树的宽度

        row_split = rep(c("A", "B"), 9), # 行分割后的命名

        row_km = 2 # 行k-means聚类的类别数

        )

通过两种分割方法一起用,就相当于有了2个属性,一个是AB属性框的分割,一个是kmeans的分割。所以2*2就是4个属性,分成了4个部分。

Heatmap(mat, name = "mat",

        cluster_columns = column_dend, # 列聚类方法指定为前面设置的dendrogram对象

        column_title = "(A) A heatmap with column annotations", # 标题

        show_column_names = FALSE, # 不显示列名

        column_split = 3,  # 列分割数

        row_dend_width = unit(2, "cm"), # 行聚类树的宽度

        row_split = rep(c("A", "B"), 9), # 行分割后的命名

        row_km = 2, # 行k-means聚类的类别数

        row_order = 1:18

        )

如果设置了row_order或column_order,在每一行/列分割切片中,它仍然是有序的。

还可以对于聚类树显示的顺序进行控制。当row_split/column_split或row_km/column_km设置为分类变量(向量或数据框)时,默认情况下,会对切片的均值应用额外的聚类以显示切片级别的层次结构。在这种情况下,您无法精确控制切片的顺序,因为它是由切片的聚类控制的。

不过,你可以设置cluster_row_slices或cluster_column_slices为 FALSE进而关闭聚类上切片,现在你可以精确地控制切片的顺序。

当没有切片聚类时,每个切片的顺序可以由levels中row_split/column_split 的每个变量的控制(在这种情况下,每个变量都应该是一个因子)。如果所有变量都是字符,则默认顺序为unique(row_split)orunique(column_split) 。

比如下面的结果:

Heatmap(mat, name = "mat",

  row_split = factor(rep(LETTERS[1:3], 6), levels = LETTERS[3:1]),

    column_split = factor(rep(letters[1:6], 4), levels = letters[6:1]),

    cluster_row_slices = FALSE,

    cluster_column_slices = FALSE)

我们通过设置cluster_row_slices或cluster_column_slices为 FALSE进而关闭聚类上切片。所以就严格按照我们设置的因子顺序来显示了。但是由于高一层级的聚类树打乱了,所以就没有办法显示了。

Heatmap(mat, name = "mat",

  row_split = factor(rep(LETTERS[1:3], 6), levels = LETTERS[3:1]),

    column_split = factor(rep(letters[1:6], 4), levels = letters[6:1]),

    cluster_row_slices = FALSE,

    cluster_column_slices = FALSE,

    row_title_rot = 0)

#行标题默认旋转,您可以设置row_title_rot = 0为水平,这个类似于gggplot里面对于文字角度的控制。

还可以通过row_title,column_title指定标题。当指定为单个字符串长度,则它就像所有切片的单个标题。当指定向量的时候,则是每个切片一个标题。

Heatmap(mat, name = "mat",

  row_split = factor(rep(LETTERS[1:3], 6), levels = LETTERS[3:1]),

    column_split = factor(rep(letters[1:6], 4), levels = letters[6:1]),

    cluster_row_slices = FALSE,

    cluster_column_slices = FALSE,

    row_title_rot = 0,

    #row_title = "(A) A heatmap with column annotations",

    row_title = c("t1","t2","t3")

)

在行/列上应用拆分时,可以将行/列标题和行/列名称的图形参数指定为与切片数相同的长度。

比如row_title_gp 和column_title_gp用来修改title的一些参数。row_names_gp 和column_names_gp用来修改names的一些图形参数。

Heatmap(mat, name = "mat",

    row_km = 2, row_title_gp = gpar(col = c("red", "blue"), font = 1:2),

    row_names_gp = gpar(col = c("green", "orange"), fontsize = c(10, 14)),

    column_km = 3, column_title_gp = gpar(fill = c("red", "blue", "green"), font = 1:3),

    column_names_gp = gpar(col = c("green", "orange", "purple"), fontsize = c(10, 14, 8)))

行/列切片之间的间隙空间可以通过row_gap/ column_gap控制。该值可以是单个单位或单位向量。

可以设置一致的缝隙:row_gap=unit(5,"mm"),也可以分别设置,例如:row_gap=unit(c(2,4),"mm")

Heatmap(mat, name = "mat",

    row_km = 2, row_title_gp = gpar(col = c("red", "blue"), font = 1:2),

    row_names_gp = gpar(col = c("green", "orange"), fontsize = c(10, 14)),

    column_km = 3, column_title_gp = gpar(fill = c("red", "blue", "green"), font = 1:3),

    column_names_gp = gpar(col = c("green", "orange", "purple"), fontsize = c(10, 14, 8)),

    row_gap = unit(5, "mm")

)

通过border=TRUE来设置边框。

这次是complexheatmap基本热图的一些画法,下面的帖子我们学习如果添加各种annotation。


通过设置添加热图边框时,会添加border = TRUE每个切片的边框。

通过设置添加热图边框时,会添加border = TRUE每个切片的边框。

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

推荐阅读更多精彩内容