作图R语言可视化

R可视化之ComplexHeatmap【三】:拆分

2022-07-05  本文已影响0人  Bio_Infor
特别声明:本部分(系列)内容均来自顾祖光博士对ComplexHeatmap的介绍,仅为学习交流,尊重原创。
热图系列我们已经有:

今天分享:拆分热图。

为什么要进行热图拆分

很多时候我们进行热图拆分的目的无非不在于将我们想研究的feature进行“分组”,或者通过热图的拆分来突出显示不同的pattern,总之热图的拆分在有些时候能帮助我们更有结构地去了解数据,能从中更容易提取出我们想要的信息。

拆分方法

首先直接抛出控制热图拆分的参数:

我们有多种不同的拆分方法,下面依次来进行介绍。

该种拆分通过row_kmcolumn_km参数来实现,这很好记,km就是k-means。至于什么是k-均值聚类,这是一种无监督学习的方法,在machine learning中应用广泛,有机会在后面会进行进一步的分享。那么怎么使用呢?

简单来说,你想把行和列分成几类,就把row_kmcolumn_km指定为相应的数值即可:

mat <- matrix(rnorm(15*15), ncol = 15)
rownames(mat) <- paste('row', 1:15, sep = "_")
colnames(mat) <- paste('col', 1:15, sep = "_")
Heatmap(matrix = mat,
        name = 'mat',
        column_km = 2,
        row_km = 3)

但是k均值聚类本身是一个随机的过程(初始类的选择),所以你把上面的代码重新运行一遍,你会发现结果就不一样了:

Heatmap(matrix = mat,
        name = 'mat',
        column_km = 2,
        row_km = 3)

解决的办法就是进行多次聚类,取最稳定的聚类结果,例如进行100次:
Heatmap(matrix = mat,
        name = 'mat',
        column_km_repeats = 100,
        row_km_repeats = 100,
        column_km = 2,
        row_km = 3)

这个时候你再重复这段代码,你就会发现结果是可重复的了,当然啦,repeat次数越多,结果越稳定

先来看段代码:

Heatmap(matrix = mat,
        name = 'mat',
        column_split = c(rep(c('A', 'B'), 7), 'A'),
        row_split = c(rep(c('A', 'B'), 7), 'B'))

怎么理解这个结果呢?

注意到这部分代码:

c(rep(c('A', 'B'), 7), 'A')
# [1] "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A"
c(rep(c('A', 'B'), 7), 'B')
# [1] "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "B"

实际上这段代码是给每一行(列)赋给了一个“类”,这个类就是A或者B,那么我们在绘图时就会根据这个类来进行热图的拆分,拆分后的结果或分别作为进一步聚类的单位。

除了以向量的形式来进行分类的指定,我们还可以通过因子数据框来进行。
因子很简单:

Heatmap(matrix = mat,
        name = 'mat',
        column_split = factor(rep(c('A', 'B'), 7), 'A'),
        row_split = factor(rep(c('A', 'B'), 7), 'B'))

而基于数据框:

Heatmap(matrix = mat,
        name = 'mat',
        column_split = data.frame(c(rep(c('A', 'B'), 7), 'A'),
                                  c(rep(c('C', 'D'), each = 7), 'D')))

其实也很好理解,你自己运行一下这部分代码就理解了:

data.frame(c(rep(c('A', 'B'), 7), 'A'),
           c(rep(c('C', 'D'), each = 7), 'D'))

为了更加个性化一点,我们甚至可以完全关闭默认的聚类功能,这也是通过cluster_column来实现的

Heatmap(matrix = mat,
        name = 'mat',
        column_split = data.frame(c(rep(c('A', 'B'), 7), 'A'),
                                  c(rep(c('C', 'D'), each = 7), 'D')),
        cluster_columns = F)

总结来说就是,这部分是妥妥的个性化。

此外你会注意到图上会有一些虚线,这些虚线实际上表征了热图拆分所依据的聚类层级,那么如何对其进行隐藏呢?只需要添加show_parent_dend_line = FALSE即可。

前面已经讲到ComplexHeatmap会默认进行对行和列的聚类,那我们当然也能根据聚类的结果来进行热图的拆分,还记得基于k均值聚类的拆分吗?我们可以通过把row_kmcolumn_km指定为相应的数值来将热图分割成几个部分,那么相似的原理,基于聚类树的拆分只需要把row_kmcolumn_km换成row_splitcolumn_split就行了。

Heatmap(matrix = mat,
        name = 'mat',
        column_split = 3,
        row_split = 2)

进一步的,我们想将不同部分的热图对应的聚类树标识成不同的颜色:

library(dendextend)
dend = as.dendrogram(hclust(dist(mat)))
dend = color_branches(dend, 
                      k = 2, 
                      col = c('red', 'blue'))
Heatmap(mat, name = "mat", cluster_rows = dend, row_split = 2)

这里我将两部分的树分别标识成红色和蓝色。你想做类似的工作只需要借鉴这段代码就可以了。


你可能会问了,那怎么对列进行分别上色呢?很简单哦,dist()函数是计算矩阵行之间的距离,那我们把矩阵转置一下就实现了对列之间的距离的计算:
dend = as.dendrogram(hclust(dist(t(mat))))
dend = color_branches(dend, 
                      k = 2, 
                      col = c('red', 'blue'))
Heatmap(mat, name = "mat", cluster_columns = dend, column_split = 2)

显然,上面两个组合起来你就实现了同时对行和列分割的染色。

分割美化

实际上前面的上色过程本身就已经是一个美化的过程了,更进一步,我们还有其它的美化,下面进行一一介绍:

这个部分,如果你是追更到这里的,实际上就很简单了,就是一个gpar()函数:

Heatmap(mat, 
        name = 'mat', 
        row_split = 2,
        row_title_gp = gpar(col = c("red", "blue")),
        row_names_gp = gpar(col = c("green", "orange"), fontsize = c(10, 14)),
        column_split = 3,
        column_title_gp = gpar(fill = c("red", "blue", "green")),
        column_names_gp = gpar(col = c("green", "orange", "purple"), fontsize = c(10, 14, 8)))

这里一个问题就是,行列标题是一些数字,当然了,我们也可以个性化一下,只要将其改成一个等长的向量就行了:

Heatmap(mat, 
        name = 'mat', 
        row_split = 2,
        row_title_gp = gpar(col = c("red", "blue")),
        row_names_gp = gpar(col = c("green", "orange"), fontsize = c(10, 14)),
        column_split = 3,
        column_title = c('one', 'two', 'three'),
        column_title_gp = gpar(fill = c("red", "blue", "green")),
        column_names_gp = gpar(col = c("green", "orange", "purple"), fontsize = c(10, 14, 8)))

最后一个问题,我们怎么样给列标题添加一个大标题呢?显然column_title参数不可行,它已经被占用了,给大家一个方法:
map <- Heatmap(mat, 
               name = 'mat', 
               row_split = 2,
               row_title_gp = gpar(col = c("red", "blue")),
               row_names_gp = gpar(col = c("green", "orange"), fontsize = c(10, 14)),
               column_split = 3,
               column_title = c('one', 'two', 'three'),
               column_title_gp = gpar(fill = c("red", "blue", "green")),
               column_names_gp = gpar(col = c("green", "orange", "purple"), fontsize = c(10, 14, 8)))
draw(map, column_title = 'I am a column title')

用一个draw()函数就可以了。

距离距离,就是“gap”,这就很简单了,看看下面这段代码就清楚了:

Heatmap(matrix = mat,
        name = 'mat',
        column_split = 3,
        row_split = 2,
        column_gap = unit(3, 'mm'),
        row_gap = unit(5, 'mm'))

同时也可以通过添加border=TRUE参数来把分割出来的方块加上黑色边框:
Heatmap(matrix = mat,
        name = 'mat',
        column_split = 3,
        row_split = 2,
        column_gap = unit(3, 'mm'),
        row_gap = unit(5, 'mm'),
        border = T,
        border_gp = gpar(col = 'orange', lwd = 5))
本期到此为止,下期内容:热图小方格个性化修饰、提取亚集及热图信息。
上一篇下一篇

猜你喜欢

热点阅读