草庐IT

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

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

今天分享:拆分热图。

为什么要进行热图拆分

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

拆分方法

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

  • row_km
  • row_split
  • column_km
  • column_split

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

  • 基于k-均值聚类的拆分

该种拆分通过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))
本期到此为止,下期内容:热图小方格个性化修饰、提取亚集及热图信息。

有关R可视化之ComplexHeatmap【三】:拆分的更多相关文章

  1. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  2. ruby - Ruby 中的波形可视化 - 2

    我即将开始一个将录制和编辑音频文件的项目,我正在寻找一个好的库(最好是Ruby,但会考虑Java或.NET以外的任何库)以进行实时可视化波形。有人知道我应该从哪里开始搜索吗? 最佳答案 要流入浏览器的数据量很大。Flash或Flex图表可能是唯一能提高内存效率的解决方案。Javascript图表往往会因大型数据集而崩溃。 关于ruby-Ruby中的波形可视化,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c

  3. ruby - 拆分字符串并分配给不同的变量 - 2

    我从ui中得到日期范围为-approved_between"=>"2013-03-17-2013-03-18"我需要拆分此approved_start_date="2013-03-17"和approved_end_date="2013-03-18"...我希望使用它在mysql中查询,因为mysql中的日期格式是created_at:2012-07-2810:35:01.我正在做的是:approved=approved_between.split("")approved_start_date=approved[0]approved_end_date=approved[2]很确定这不是处

  4. ruby-on-rails - Ruby on Rails 将列表拆分或切片为列 - 2

    @locations=Location.all#currentlistingall@locations=Location.slice(5)orLocation.split(5)使用Ruby,我试图将我的列表分成4列,每列限制为5个;然而,切片或拆分似乎都不起作用。知道我可能做错了什么吗?任何帮助是极大的赞赏。 最佳答案 您可能想使用in_groups_of:http://railscasts.com/episodes/28-in-groups-of这是RyanBates在railscast中的示例用法:

  5. ruby - 格式化数字以每隔三位数拆分一次 - 2

    我想在格式化数字时每隔三个字符放置一个空格。根据这个规范:it"shouldformatanamount"dospaces_on(1202003).should=="1202003"end我想出了这段代码来完成这项工作defspaces_onamountthousands=amount/1000remainder=amount%1000ifthousands==0"#{remainder}"elsezero_padded_remainder='%03.f'%remainder"#{spaces_onthousands}#{zero_padded_remainder}"endend所以我

  6. ruby - 如何拆分数组? - 2

    给定一个数组:arr=[['a','1'],['b','2'],['c','3']]将它分成两个数组的最佳方法是什么?例如我想从上面的数组中得到以下两个数组:first=['a','b','c']second=['1','2','3']我可以使用collect来做到这一点吗? 最佳答案 好吧,我只是偶然发现了arr.transposearr=[['a','1'],['b','2'],['c','3']].transposefirst=arr[0]second=arr[1]与上面的答案arr.zip、arr.map、foreach相比

  7. ruby - 如何通过 "\r\n"拆分 Ruby 字符串? - 2

    给定一个字符串:s="Good\r\nDay\r\n\r\n\r\nStack\r\n\r\nOverflow\r\n"我愿意:用(\r\n)+拆分,即我想得到:["Good","Day","Stack","Overflow"]我尝试了s.split(/(\r\n)+/)但它没有给我预期的结果。为什么?我怎样才能得到预期的结果?获取数组中\r\n的个数,即预期结果为:[1,3,2]你会怎么做?我使用Ruby1.9.2。 最佳答案 差不多了,试试这个:s.split/[\r\n]+/s.scan(/[\r\n]+/).map{|e|e

  8. ruby - 如何拆分两个大写字母? - 2

    我有以下数组:a=["CH3","CH2"]我想使用正则表达式将其拆分为两个大写字母以显示:a=["C","H3","C","H2"]怎么做你这样做吗?到目前为止我已经尝试过:a.each{|array|x=array.scan(/[A-Z]*/)putsa}returns:CHCH提前致谢! 最佳答案 你可以试试这个:s.scan(/[A-Z][^A-Z]*/) 关于ruby-如何拆分两个大写字母?,我们在StackOverflow上找到一个类似的问题: h

  9. ruby - Ruby 中的特殊字符串拆分 - 2

    我正在尝试找出最好的方法...给定一个字符串s="ifsomeBool||x==1&&y!=22314"我想用Ruby来分隔语句和bool运算符..所以我想把它分成["if","someBool","||","x","==","1","&&","y","!=","22314"]我可以使用s.split(),但这只会以空格作为分隔符进行拆分..但我也希望x!=y也被拆分(它们是有效的bool语句,它们之间没有空格可读性好)。当然,最简单的方法是要求用户在bool运算符和变量之间放置空格,但是还有其他方法可以做到这一点吗? 最佳答案 按

  10. Unity数据可视化图表插件XCharts3.0发布 - 2

    Unity数据可视化图表插件XCharts3.0发布历时8个多月,业余时间,断断续续,XCharts3.0总算发布了。如果要打个满意度,我给3.0版本来个80分。对于代码框架结构设计的调整改动,基本符合预期,甚是满意。相比之前的1.0和2.0版本,我认为3.0才是一个拿得出手给广大开发者使用的版本。1.0发布的时候,很兴奋,从0.1到1.0,也磨了一年,真的等不及想给大家试用了,还特地写过一篇文章以示庆祝。那个时候,1.0虽然还还不够完善,功能也不够丰富,但它是XCharts的开始,没有1.0,也就没有后面的2.0和3.0。后面的2.0发布,做了很多改进和优化,随着版本迭代,慢慢的发现有不少硬

随机推荐