今天分享:拆分热图。
为什么要进行热图拆分
很多时候我们进行热图拆分的目的无非不在于将我们想研究的feature进行“分组”,或者通过热图的拆分来突出显示不同的pattern,总之热图的拆分在有些时候能帮助我们更有结构地去了解数据,能从中更容易提取出我们想要的信息。
拆分方法
首先直接抛出控制热图拆分的参数:
row_kmrow_splitcolumn_kmcolumn_split我们有多种不同的拆分方法,下面依次来进行介绍。
该种拆分通过row_km和column_km参数来实现,这很好记,km就是k-means。至于什么是k-均值聚类,这是一种无监督学习的方法,在machine learning中应用广泛,有机会在后面会进行进一步的分享。那么怎么使用呢?
简单来说,你想把行和列分成几类,就把row_km和column_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)

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

先来看段代码:
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_km和column_km指定为相应的数值来将热图分割成几个部分,那么相似的原理,基于聚类树的拆分只需要把row_km和column_km换成row_split和column_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))

我正在为一个项目制作一个简单的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"
我即将开始一个将录制和编辑音频文件的项目,我正在寻找一个好的库(最好是Ruby,但会考虑Java或.NET以外的任何库)以进行实时可视化波形。有人知道我应该从哪里开始搜索吗? 最佳答案 要流入浏览器的数据量很大。Flash或Flex图表可能是唯一能提高内存效率的解决方案。Javascript图表往往会因大型数据集而崩溃。 关于ruby-Ruby中的波形可视化,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c
我从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]很确定这不是处
@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中的示例用法:
我想在格式化数字时每隔三个字符放置一个空格。根据这个规范: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所以我
给定一个数组: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相比
给定一个字符串: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
我有以下数组: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
我正在尝试找出最好的方法...给定一个字符串s="ifsomeBool||x==1&&y!=22314"我想用Ruby来分隔语句和bool运算符..所以我想把它分成["if","someBool","||","x","==","1","&&","y","!=","22314"]我可以使用s.split(),但这只会以空格作为分隔符进行拆分..但我也希望x!=y也被拆分(它们是有效的bool语句,它们之间没有空格可读性好)。当然,最简单的方法是要求用户在bool运算符和变量之间放置空格,但是还有其他方法可以做到这一点吗? 最佳答案 按
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发布,做了很多改进和优化,随着版本迭代,慢慢的发现有不少硬