在这篇文章中,我将介绍在ComplexHeatmap中legend的位置是如何自动调整的。注意这些新的特性只有在版本2.5.4之后才有。
Legend在热图中看起来好像是很简单的一个部分,只要放在热图的一边就行了。其实在ComplexHeatmap中,legend的处理用了很多代码,也是最麻烦的一个部分。为了让legend的位置看起来更自然,我花了很多时间和精力在它上面。
这篇文章只介绍legend在热图中的位置,关于legend本身的设置,请见ComplexHeatmap的手册。
本文所有的关于legend位置的设置,用户都无需操作。ComplexHeatmap基本上会自动选择合适的位置放置legend。本文的主旨是向大家介绍legend的位置是如何优化的。
在下面的例子中,我使用了一个10x10的随机矩阵。
library(ComplexHeatmap)
set.seed(123)
m = matrix(rnorm(100), 10)
在旧版本中(<= 2.5.3),所有的legend放置在整张图的中间,如下图所示。如果热图下方没有列名的话,整体看起来还不错。下图中,左侧是Heatmap()
绘制的结果,右侧加上了各个viewport的位置,这样可以方便观察legend是如何放置在相应的viewport中的。
当我们用热图对特别大的矩阵进行可视化,我们会选择不显示矩阵的列名,那么legend的位置看起来还可以。但是,对于只有少数列的矩阵并且需要将列名显示出来的时候,legend的位置就会很奇怪了。比如在下面的例子中,矩阵包含很长的列名:
colnames(m) = strrep(letters[1:10], 20)
legend看起来远离了热图本身,看起来很糟糕!
从版本2.5.4开始,在draw()
函数中,我新加入了两个参数align_heatmap_legend
和align_annotation_legend
用来控制legend的位置。其中提供了三个选择:
global_center
:这和旧版本中保持一致,legend在整张图片中居中对齐。heatmap_center
:legend在热图(heatmap body)中居中对齐。heatmap_top
:legend对热图(heatmap body)的顶部对齐。
三种不同选择请见如下例子,例如设定align_heatmap_legend
:
ht = Heatmap(m, name = "mat",
column_title = "'global_center'")
draw(ht, align_heatmap_legend = "global_center")
ht = Heatmap(m, name = "mat",
column_title = "'heatmap_center'")
draw(ht, align_heatmap_legend = "heatmap_center")
ht = Heatmap(m, name = "mat",
column_title = "'heatmap_top'")
draw(ht, align_heatmap_legend = "heatmap_top")
尽管你可以手动设置align_heatmap_legend
和align_annotation_legend
参数,从版本2.5.4开始,其实ComplexHeatmap会根据热图的大小和图片的大小自动选择合适的方法去放置legend。自动选择的规则为(以align_heatmap_legend
为例):
- 如果legend的高度(如果有多个legend,那么此处为多个legend高度之和)小于热图(heatmap body)的高度,
align_heatmap_legend
会被设定为"heatmap_center"
。 - 如果legend的高度大于热图的高度,但是小于热图加上其他所有放置在热图下方的元件(例如,dendrogram,annotation, 列名)的高度之和,
align_heatmap_legend
会被设定为"heatmap_top"
。 - 其他情形下,
align_heatmap_legend
被设定为"global_center"
。
我下面通过一些例子来展示这个自动放置legend是如何进行的。
在第一个例子中,其中包含了两个热图,两个legend的高度之和小于热图的高度,因此legend对于热图居中对齐:
Heatmap(m, name = "mat1") +
Heatmap(m, name = "mat2")
我加入一个新的热图,现在有三个legend,它们的高度大于热图的高度,因此它们对热图的顶部对齐:
Heatmap(m, name = "mat1") +
Heatmap(m, name = "mat2") +
Heatmap(m, name = "mat3")
现在我加入第四个热图,四个legned的高度之和大于热图高度加列名高度,因此它们对整张图居中对齐。
Heatmap(m, name = "mat1") +
Heatmap(m, name = "mat2") +
Heatmap(m, name = "mat3") +
Heatmap(m, name = "mat4")
当我们继续添加热图和legend,并且如果legend的高度之和超过整张图片的高度了怎么办?这些legend自动被放到了两列中:
Heatmap(m, name = "mat1") +
Heatmap(m, name = "mat2") +
Heatmap(m, name = "mat3") +
Heatmap(m, name = "mat4") +
Heatmap(m, name = "mat5")
当有更多更多的legend时,它们会被自动放到多个列中,这样所有的legend都可以被看到:
Heatmap(m, name = "mat1") +
Heatmap(m, name = "mat2") +
Heatmap(m, name = "mat3") +
Heatmap(m, name = "mat4") +
Heatmap(m, name = "mat5") +
Heatmap(m, name = "mat6") +
Heatmap(m, name = "mat7") +
Heatmap(m, name = "mat8") +
Heatmap(m, name = "mat9") +
Heatmap(m, name = "mat10")
让我们试试同时加入annotation的legend:
ha = HeatmapAnnotation(foo1 = 1:10)
Heatmap(m, name = "mat", top_annotation = ha)
在下面例子中,legend被放置在了annotation name下面。
ha = HeatmapAnnotation(foo1 = 1:10, foo2 = 1:10)
Heatmap(m, name = "mat", top_annotation = ha)
但是如果legend太多的话,legend可能会和annotation的name重合,例如:
ha = HeatmapAnnotation(foo1 = 1:10,
foo2 = 1:10, foo3 = 1:10)
Heatmap(m, name = "mat", top_annotation = ha)
这个不是很好优化,因为如果将legend向右移动,让它们不和annotation name重合的话,那么annotation name下方或者legend的左方会有很大的空白区域,会显得整张图片非常不自然(或者很丑!)。一个解决办法是将annotation name移动到左侧:
ha = HeatmapAnnotation(foo1 = 1:10,
foo2 = 1:10, foo3 = 1:10,
annotation_name_side = "left")
Heatmap(m, name = "mat", top_annotation = ha)
注意这个新的功能也同样适用于放置在热图底部的水平方向的legend。
最后展示一个炫酷的功能。回想一下如果你有很多legend的话,它们的位置会根据图片的大小自动放到多个列中。那么,如果当你直接把热图生成在interactive device中,并且调整窗口大小时,legend的放置也会自动调整!见下面的动图:
可惜的是这个在interactive device中自动调整的功能在Rstudio中并不支持。你只会在Rstudio右下方的figure panel中看到正确的图(可惜那个panel太小),而当你点击“Zoom”或者“Export”时可能会见到legend在不正确的位置,我建议你直接把图片保存到文件中。当然了,如果你没有太多的legend时,你无需担心这些。
既往专辑