树状图通常表示为二叉树,其中两个分支的顺序在某个节点上的次序是任意的。旋转某个节点上的两个分支并不会改变其数学表示,但会影响 dendrogram 中元素的全局排序。因此,选择一个旋转 dendrogram 分支的合适的方法,或者换句话说,重新排序 dendrogram ,有助于在热图中将具有相似模式的矩阵行或列彼此靠近,以此提高可视化的效果。在默认情况下, Heatmap() 使用 reorder.dendrogram() 函数根据 dendrogram 分支的子矩阵的平均值对 dendrogram 重新排序,例如,在 dendrogram 的每个节点上,一个平均值较小的分支总是放在该节点的左侧。Heatmap() 也支持 dendrogram 对象,因此,其他 dendrogram 重新排序的方法可以很容易地集成其中。用户可以首先生成一个 dendrogram 对象,然后应用特定的 dendrogram 重新排序方法,例如来自 dendsort 包 [22],最后将它们集成到 Heatmap() 中。
注意层次聚类只是对热图的行和列进行重新排序的一种特殊方法。当然也可以使用计算矩阵的行和列顺序的其他方法。Heatmap() 允许用户设置数字索引或字符索引来重新排序热图。用于排序矩阵的流行软件包有 seriation [23] 和 biclust [24]。
⬤ 热图切分
热图切分是突出显示分组模式的一种有效方法。由于在层次聚类过程中,当向当前 dendrogram 中添加新的叶(leaf)或子树(sub-dendrogram)时,计算只是基于dendrogram中已经存在的元素,而不是矩阵中的所有所有元素。如果某些数据集中分组只有中等水平的差异,那么这会削弱它们的可视化的效果。热图切分可以极大地提高分组模式的可区分性。ComplexHeatmap 提供了多种方式将热图切分为行和列上的“切片”(slice)(图 2A-B):1. 设置 k均值聚类,其中支持重复运行 k均值聚类若干次以获得一个一致性k均值聚类结果,以减少随机性的影响;2. 设置一个包含预定义分组信息的分类变量。变量可以是一个向量或一个数据框,然后热图被分类变量中所有水平的组合切分;3. 如果在热图上已经应用了层次聚类,则可以指定单个数字,然后 cutree() 函数被用来来切割 dendrogram 。对于前两种拆分方法,如果启用了聚类,则首先在每个热图切片内执行层次聚类,然后根据它们的平均值对热图切片应用第二次聚类,用以显示切片级别的层次关系。
例如,图 2C 中的热图显示了在具有四个组别的胶质母细胞瘤数据集 [25] 中具有显着差异表达的基因(作为顶部注释)。这四个组别是通过一致性聚类(consensus clustering)预测的,分析表示分类的结果非常稳定 [26]。稳定的分类结果也得到了 t-SNE 分析的支持,其中四组别能够被很好地分开(图 S1)。但是,如果通过对所有样本直接应用层次聚类,那么四个组别并没有像预期的那样很好地分离,其中组别 3(蓝色)和 4(紫色)中的一些样本混合在一起。在图 2D 中,使用相同的矩阵,首先按照分类结果对热图进行拆分,然后在每个列切片中分别应用层次聚类。作为比较,它确实提高了分组模式的效果。此外,在图 2D 中,行还通过 k均值聚类进行切分。现在能够很容易的观察到组别特异性基因的表达模式。
⬤ 渲染热图为栅格图像
当我们制作所谓的“高质量图形”时,我们通常将图形保存为矢量图形,例如以格式 pdf 或 svg保存。矢量图形存储了每个图形元素的详细信息,因此,如果将由巨大矩阵生成的热图保存为矢量图形,那么文件将会非常大。完整的图像将需要很长时间才能被图像查看器渲染。由于图形设备的尺寸和分辨率有限,对于大型热图来说,热图中的相邻网格实际上会被合并为单个像素。因此,需要一种有效减少原始图像的方法,而不必保留巨大热图的所有细节。
栅格化是一种将图像转换为红-绿-蓝 (RGB) 值的颜色矩阵的方法。假设热图矩阵有 nr 行和 nc 列。当它在某个图形设备(例如屏幕设备)上绘制时,相应的热图主体分别使用 pr 和 pc 像素作为行和列。当 nr > pr 和/或 nc > pc 时,矩阵中的多个值被映射到单个像素上,其中 nr 和/或 nc 可以通过某种方法缩减为 pr 和/或 pc。ComplexHeatmap 提供了三种方法通过栅格化来缩减热图中的图形:1. 首先将热图写入一个分辨率为 pr × pc 的临时 png 图像,然后将临时图像读取为栅格对象并填充回热图。这种方法其实在 png 设备上进行了图像缩减。2. 首先将原始矩阵缩减为 pr × pc 的大小,那么缩减之后的矩阵中的单个值可以对应一个不同的像素。可以使用一些特定方法对矩阵进行缩减,例如从子矩阵中取平均值或随机值。3.首先生成一个分辨率为 nr × nc 的临时图像,然后使用 magick 包将图像缩小到 pr × pc 大小,最后将缩小后的图像作为栅格对象读取并填充到热图中。magick 包提供了大量调整图像大小的方法,并且ComplexHeatmap 都支持这些方法。在 ComplexHeatmap 一书的“Section 2.8 Heatmap as raster image”中,读者可以找到不同图像缩减方法的详细视觉比较。
⬤ 热图个性化
默认情况下,热图主体是由具有不同颜色的单元格组成。ComplexHeatmap 允许用户通过添加新的图层来个性化热图。Heatmap() 中的参数 cell_fun 和 layer_fun 可用于在绘制热图时将自定义的图形添加到热图单元格上(图 2A)。这两个参数的功能基本相同,但是 layer_fun 可以看做是 cell_fun 的矢量化版本。如果热图很大,使用 layer_fun 会使绘制速度更快。ComplexHeatmap 还提供了decorate_*() 系列函数,例如 decorate_annotation(),这些函数可以在热图绘制后将图形添加到任何热图组件中。在 ComplexHeatmap 中,每个热图组件都有自己的绘图区域,热图绘制结束后仍会记录它们。decorate_*() 可以返回到特定的绘图区域,然后在其中添加自定义图形。
正如后面部分将介绍的,3D 热图、oncoPrint 和 UpSet plot 都使用了 layer_fun 进行实现。而密度分布热图和富集热图则使用了 decorate_heatmap_body() 来部分增强其可视化效果。
⬤ 灵活地设置颜色和图例
热图中,颜色是主要用来映射到数据上的元素。ComplexHeatmap 允许通过设置一个颜色映射函数,指定断点和相应颜色来对矩阵中的值和颜色之间进行精确的映射。例如,用户可以定义一个对称于零的颜色映射函数,这有助于识别上调和下调基因的表达,或者用户可以为不同的热图定义相同的颜色映射函数,以使颜色在热图之间具有可比性。ComplexHeatmap 还允许对热图图例进行灵活的配置,例如多配色方案图例和具有自定义图形的图例。读者请参考 ComplexHeatmap 书中的“Chapter 5. Legends”以获得更多信息。