CNS级别的热图都在这里
你确定不看看吗?
Hi,大家好,我是晨曦,
最近同学们的问题如潮水般向我这里涌来,晨曦感觉自身的知识体系受到了严重的冲击,本以为扎实的基础貌似也只是一个假象而已,所以趁着可以跟同学们交流的机会,也是总结了好多身边小伙伴们共性的需求,在这里,借着这个机会和大家分享一下。
这期依旧是晨曦碎碎念,这期的中心我们聚焦在热图的可视化上。
热图,可以说是我们在日常分析过程中看到过最多的图之一了,如何更加方便、酷炫的展示热图成为了很多小伙伴们关心的重点。
其实在晨曦的学习过程中热图的绘制一直是依靠着pheatmap包,但是前段时间无意中接触到了ComplexHeatmap包,尤其是这个包中最后的几个例子,真的是可以绘制出很精美的热图。
所以这期也算是晨曦对于ComplexHeatmap包的一个学习笔记,希望可以和大家一起学会这个绘制热图的R包。
Ps:这个R包的帮助文档真的是巨详细~,有一共15个章节,一开始晨曦打算做成连载的形式,但是考虑到可能很多小伙伴不感兴趣这种纯纯的知识讲解,所以这里我尽量把R包的一些细节穿插在例子中,好增加小伙伴们阅读的兴趣

晨曦碎碎念系列传送门
复杂热图示例
下面这个热图的示例就是尽可能的增加了更多的信息在同一张热图之中,示例图片如下:
晨曦解读
最大的热图可视化了基因的相对表达的情况(对每个基因的表达式进行缩放),在右边我们把基因的绝对表达水平作为单列热图。基因长度和基因类型(即蛋白质编码或lincRNA)也被作为热图注释或热图
#加载R包library(ComplexHeatmap)library(circlize)#准备基因的表达矩阵expr = readRDS(system.file(package = "ComplexHeatmap", "extdata", "gene_expression.rds"))
晨曦解读
首先我们来看一下这个内置的数据集
可以很清楚的看到,这个就是一个标准的基因表达矩阵
但是这个数据集的最后几个变量确实储存着这个数据集的"特征信息",如下:
在我们带入到自己的数据绘图时,可以考虑把type以及一些与Gene相关的结果保存在我们的矩阵中,整理成示例数据的样式即可。
灵活使用filter、select以及mutate函数等可以帮助我们更好的整理数据
#单纯提取表达信息(舍弃特征信息)mat = as.matrix(expr[, grep("cell", colnames(expr))])#获取Gene的平均表达量base_mean = rowMeans(mat)#对表达数据进行标准化#这是因为这个R包并不会对数据自动进行标准化,为了防止数据彼此离群太大,所以我们需要标准化mat_scaled = t(apply(mat, 1, scale))#解释一下这里为什么要转置#apply函数作用完数据集标准化后会生成一个变量名为行名(gene symbol)的矩阵,所以我们需要转置让其恢复到最以前的输入数据的格式#更改样本IDtype = gsub("s\\d+_", "", colnames(mat))#[1] "cell01" "cell02" "cell03" "cell01" "cell02" "cell03" "cell01" "cell02"......
晨曦解读
至此我们就完成了对输入数据的整理,我们来看一下我们的环境内都生成了哪些变量
#绘制热图注释ha = HeatmapAnnotation(type = type, annotation_name_side = "left")#A HeatmapAnnotation object with 1 annotationname: heatmap_annotation_0 position: column items: 24 width: 1npc height: 5mm thisobject is subsetable 9.001mm extension on the left nameannotation_type color_mapping heighttypediscrete vector random 5mm
晨曦解读
这里我们解释一下HeatmapAnnotation函数
热图注释是热图的重要组成部分,它显示了与热图中的行或列相关联的附加信息
ComplexHeatmap包为设置注释和定义新的注释图形提供了非常灵活的支持。注释可以通过top_annotation、bottom_annotation、left_annotation和right_annotation参数放在热图的四个侧面。
这四个参数的值应该在HeatmapAnnotation类中,并且应该由HeatmapAnnotation()函数构造,如果它是行注释,则由rowAnnotation()函数构造。rowAnnotation()只是一个辅助函数,它与HeatmapAnnotation函数的功能是相同的
这里我们的这句代码的注释信息就是样本ID(组建形式为向量)然后放置在左侧~
如果传递的值是向量,则绘制的图形是简单注释,而如果想绘制图形注释这种称为复杂注释,我们需要我们的输入数据为向量的同时另外设置形状参数,参考代码如下:
#输入数据set.seed(123)mat <- matrix(rnorm(100), 10)rownames(mat) <- paste0("R", 1:10)colnames(mat) <- paste0("C"1:10)#设置注释column_ha <- HeatmapAnnotation(foo1 = runif(10), bar1 = anno_barplot(runif(10)))#绘图Heatmap(mat, name = "mat", top_annotation = column_ha)#绘制热图ht_list = Heatmap(mat_scaled, name = "expression", row_km = 5, col = colorRamp2(c(-2, 0, 2), c("green", "white", "red")), top_annotation = ha, show_column_names = FALSE, row_title = NULL, show_row_dend = FALSE) +Heatmap(base_mean, name = "base mean", top_annotation = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:6), height = unit(2, "cm"))), width = unit(15, "mm")) +rowAnnotation(length = anno_points(expr$length, pch = 16, size = unit(1, "mm"), axis_param = list(at = c(0, 2e5, 4e5, 6e5), labels = c("0kb", "200kb", "400kb", "600kb")), width = unit(2, "cm"))) +Heatmap(expr$type, name = "gene type", top_annotation = HeatmapAnnotation(summary = anno_summary(height = unit(2, "cm"))), width = unit(15, "mm"))
晨曦解读
这里我们把这块的代码分成四部分讲解(每一部分都是代码讲解+可视化)
#第一部分Heatmap(mat_scaled, name = "expression", row_km = 5, col = colorRamp2(c(-2, 0, 2), c("green", "white", "red")), top_annotation = ha, show_column_names = FALSE, row_title = NULL, show_row_dend = FALSE)#绘制主热图(左边做大的热图)#输入数据为表达矩阵#主热图的legend命名为“expression”#row_km参数为对行应用k-means聚类。如果值大于1,则根据k-means聚类将热图按行分割,这里设置为5,则分割5次#colorRamp函数为颜色映射函数,colorRamp2的两个参数是断点值向量和对应颜色向量,colorRamp2在每个间隔中线性插值颜色#top_annotation参数为选择热图注释出现的位置,这里为顶部#show_column_names = FALSE, row_title = NULL, show_row_dend = FALSE这些参数则是设置是否出现观测、变量信息
晨曦解读
这里的对于观测标注的问题在后面会得到修正~
#第二部分Heatmap(base_mean, name = "base mean", top_annotation = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:6), height = unit(2, "cm"))), width = unit(15, "mm"))#绘制主热图旁边的基因表达图#输入数据为每一个基因的平均表达量#name参数为图例的标志,也可以称呼为图例的名称#这里我们重点解释一下热图注释里面代码的含义,我们单独把这句代码拎出来进行讲解top_annotation = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:6), height = unit(2, "cm"))), width = unit(15, "mm"))#anno_summary函数是一个特殊的注释函数,它只适用于单列或单行热图,它显示了热图中值的摘要。如果热图中的值是离散的,则将每个级别的比例(求和归一化为1)可视化为堆叠的条形图。如果热图被分割成多个片,那么注释中就会放入多个条。如果值是连续的,则 使用箱线图,在柱状图中,颜色模式和热图一样使用,而在箱状图中,颜色需要由gp控制#所以我们可以很清楚的知道gp参数所对应的为箱线图的颜色#height参数为箱线图的高度#width参数为箱线图的宽度
#第三部分rowAnnotation(length = anno_points(expr$length, pch = 16, size = unit(1, "mm"), axis_param = list(at = c(0, 2e5, 4e5, 6e5), labels = c("0kb", "200kb", "400kb", "600kb")), width = unit(2, "cm")))#这一步骤就是获取行的注释信息,里面规定了一些注释注释信息的细节~#A HeatmapAnnotation object with 1 annotation# name: heatmap_annotation_5 # position: row # items: 155 # width: 20mm # height: 1npc # this object is subsetable#  13.7272666666667mm extension on the bottom # name annotation_type color_mapping width# length anno_points() 20mm
晨曦解读
从上面的信息中我们也可以知道,这个注释信息组要是针对第二列注释信息的~
#第四部分Heatmap(expr$type, name = "gene type", top_annotation = HeatmapAnnotation(summary = anno_summary(height = unit(2, "cm"))), width = unit(15, "mm"))#绘制最右边的基因类型注释图#输入数据为表达矩阵中的Gene type#这里因为不是连续型数据而是离散型数据,所以注释上面的图就不是箱线图而是柱状图#参数基本上都在前面介绍过
晨曦解读
大家如果直接运行这段代码会发现一个很有意思的现象,我下面分别把上面这个代码运行两次,大家可以看一下结果的区别
运行第一次
运行第二次
晨曦解读
大家可以很清楚的看到,同样的代码运行两次后得到的结果整体是一致的,但是配色确是不一样的,这里就涉及到ComplexHeatmap包中的一个逻辑了,这个包内置的颜色是蓝-白-红,也就是说不管你的输入数据是字符型还是数值型,如果没有指定col参数那么其默认都是这三种颜色
这里我们就有疑问了,为什么我的颜色会改变呢?
其实通过图例可以看到,我们这里的分组是四个分组,又因为我们没有指定col参数,所以颜色是随机的
那么我们又该如何设置我们的颜色呢?
首先,针对ComplexHeatmap包其设置颜色的函数最常用的是colorRamp2函数,但是这个函数的输入数据为数值型,如果我们把字符型当作输入数据,就会报下面的错误
大概意思就是,我这里进行计算的是数值型,你把字符型放进来,我这两种数据类型无法放在一起
那么我们这里就只能考虑最朴素的方式了,就是直接进行颜色的赋值
#第四部分(修改后代码)Heatmap(expr$type, name = "gene type", col = rev(rainbow(4)), top_annotation = HeatmapAnnotation(summary = anno_summary(height = unit(2, "cm"))), width = unit(15, "mm"))
晨曦解读
可以很清楚的看到我这里设置col参数后,我的颜色就被固定下来了,当然我们如果通过向量的方式组建和分组数量相同的颜色,不管是字符型的颜色,如“red”、“blue”等,还是16进制的编码颜色,比如“#00FF00FF”等都是可以的
ComplexHeatmap包针对16进制的颜色编码采取了统一的后缀,也就是加了两个F,所以我们如果相知道颜色编码代表了什么颜色,去掉后面两位(FF)然后上网站上查询即可
#第五部分ht_list = rowAnnotation(block = anno_block(gp = gpar(fill = 2:6, col = NA)), width = unit(2, "mm")) + ht_list#这一步骤是添加观测的注释信息#块注释用于表示表达量的分步#简单来说就是我们把观测进行简单聚类以后的标志
晨曦解读
至此,我们这幅图就可以完美的复现出来了,包括代码各种细节的讲解,以及每一个步骤的输入数据就给大家介绍完毕,我们下面直接运行全代码来给大家看一下我们复现后的结果
#纯代码library(ComplexHeatmap)library(circlize)expr = readRDS(system.file(package = "ComplexHeatmap", "extdata", "gene_expression.rds"))mat = as.matrix(expr[, grep("cell", colnames(expr))])base_mean = rowMeans(mat)mat_scaled = t(apply(mat, 1, scale))type = gsub("s\\d+_", "", colnames(mat))ha = HeatmapAnnotation(type = type, annotation_name_side = "left")ht_list = Heatmap(mat_scaled, name = "expression", row_km = 5, col = colorRamp2(c(-2, 0, 2), c("green", "white", "red")), top_annotation = ha, show_column_names = FALSE, row_title = NULL, show_row_dend = FALSE) +Heatmap(base_mean, name = "base mean", top_annotation = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:6), height = unit(2, "cm"))), width = unit(15, "mm")) +rowAnnotation(length = anno_points(expr$length, pch = 16, size = unit(1, "mm"), axis_param = list(at = c(0, 2e5, 4e5, 6e5), labels = c("0kb", "200kb", "400kb", "600kb")), width = unit(2, "cm"))) +Heatmap(expr$type, name = "gene type", top_annotation = HeatmapAnnotation(summary = anno_summary(height = unit(2, "cm"))),   width = unit(15, "mm"))ht_list = rowAnnotation(block = anno_block(gp = gpar(fill = 2:6, col = NA)),    width = unit(2, "mm")) + ht_listdraw(ht_list)
至此,本期的晨曦碎碎念就结束了~
本来另外写了一篇关于complexHeatmap包的一个整体的学习帮助,但是字数太长了,所以换成这种例子的讲解。
更多的学习内容,大家可以去看这个R包的帮助文档,真的是十分的全面,跟一本书一样了~
大家如果要用这个R包绘图,别忘了引用下面这篇文献哦~
参考资料:Gu, Z. (2016) Complex heatmaps reveal patterns and correlations in multidimensional genomic data. DOI: 10.1093/bioinformatics/btw313
我是晨曦,我们下期再见~
晨曦单细胞笔记系列传送门
晨曦从零开始学画图系列传送门
晨曦单细胞数据库系列传送门

END

撰文丨晨   曦
排版丨四金兄
主编丨小雪球
欢迎大家关注解螺旋生信频道-挑圈联靠公号~
继续阅读
阅读原文