ComplexHeatmap复杂热图绘制学习——5.图例

图例

默认情况下,热图和简单注释会自动生成图例,生成的图例放在热图的右侧。复杂注释没有图例,但可以手动构建和添加它们。所有图例都是由构造函数Legend()内部构造的 。在后面的部分中,我们首先介绍了连续图例和离散图例的设置,然后我们将讨论如何配置与热图和注释关联的图例,以及如何将新图例添加到图中。

所有的图例(无论是单个图例还是一组图例)都属于Legends类。该类只有一个槽位grob,它是真实 grid::grob对象或grid::gTree记录如何绘制图形的对象。Legends类的包装和类设计的方法使图例成为单个对象,并且可以像点一样绘制在指定视图上的一个位置。

热图和注释的图例可以由 Heatmap()中的heatmap_legend_param参数或HeatmapAnnotation()中的annotation_legend_param 参数控制。函数Legend()中的大部分参数都可以直接设置在参数名称相同的两个参数中。设置热图图例和注释图例参数的详细信息在第5.4节中介绍。

5.1连续图例

由于大多数热图包含连续值,我们首先介绍连续图例的设置。

连续图例需要一个颜色映射函数,它应该由 circlize::colorRamp2(). 在自动生成的热图图例和注释图例中, 从Heatmap()HeatmapAnnotation()函数通过col参数传递颜色映射函数 ,而如果您构建自定义图例,则需要提供颜色映射函数。

颜色映射函数中提供的中断值(例如 c(0, 0.5, 1) 在以下示例中)将与图例中的中断值不完全相同)。图例中显示的最终中断值经过内部调整,使标签数量接近 5 或 6。

首先我们展示一个垂直连续图例的默认样式:

library(circlize)
col_fun = colorRamp2(c(0, 0.5, 1), c("blue", "white", "red"))
lgd = Legend(col_fun = col_fun, title = "foo")
image

lgd是一个Legends类对象。图例的大小可以通过ComplexHeatmap:::width()ComplexHeatmap:::height()函数获得 。

ComplexHeatmap:::width(lgd)
## [1] 9.90361111111111mm
ComplexHeatmap:::height(lgd)
## [1] 30.2744052165491mm

图例实际上是一个由矩形、线条和文本组成的图形对象。它可以通过draw()函数添加到绘图中。在 ComplexHeatmap包中,您不需要直接在图例对象上使用draw(),但如果您在其他地方使用图例对象,它可能会很有用。

pushViewport(viewport(width = 0.9, height = 0.9))
grid.rect()  # border
draw(lgd, x = unit(1, "cm"), y = unit(1, "cm"), just = c("left", "bottom"))
draw(lgd, x = unit(0.5, "npc"), y = unit(0.5, "npc"))
draw(lgd, x = unit(1, "npc"), y = unit(1, "npc"), just = c("right", "top"))
popViewport()
image

如果您只想配置热图或注释生成的图例,则无需Legends自行构建对象。 后面介绍的参数可以直接通过Heatmap()中的参数heatmap_legend_param和 自定义图例HeatmapAnnotation()中的参数annotation_legend_param5.4节介绍 )。在以下示例中看到这些参数如何改变图例的样式后效果依然很好。以下是一个简单的示例,展示了如何在热图和热图注释中配置图例。

Heatmap(matrix(rnorm(100), 10), 
    heatmap_legend_param = list(
        title = "rnorm", at = c(-2, 0, 2), 
        labels = c("neg_two", "zero", "pos_two")
    ),
    top_annotation = HeatmapAnnotation(
        foo = 1:10,
        annotation_legend_param = list(foo = list(title = "foo_top_anno"))
    ))
image

在下面的例子中,我们只展示了如何构造图例对象,而不展示绘制图例的代码。只记得你可以在Legends对象上使用draw() 函数在图上绘制单个图例。

对于连续图例,您可以通过设置手动调整图例中的中断值at。注意高度是自动调整的。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.25, 0.5, 0.75, 1))
image

中断值对应的标签由labels设置。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.5, 1), 
    labels = c("low", "median", "high"))
image

垂直连续图例的高度由legend_height设置。 legend_height只能为垂直连续图例设置,值为图例主体的高度(不包括图例标题)。

lgd = Legend(col_fun = col_fun, title = "foo", legend_height = unit(6, "cm"))
image

如果是垂直图例,则grid_width控制图例主体的宽度。grid_width最初是为离散图例设计的,其中图例中的每个级别都是一个网格,但在这里我们对控制图例宽度的参数使用相同的名称。

lgd = Legend(col_fun = col_fun, title = "foo", grid_width = unit(1, "cm"))
image

标签的图形参数由labels_gp控制。

lgd = Legend(col_fun = col_fun, title = "foo", labels_gp = gpar(col = "red", font = 3))
image

图例的边框以及中断值的刻度由border控制border的值可以是逻辑值或颜色字符串。

lgd = Legend(col_fun = col_fun, title = "foo", border = "red")
image

title_position控制标题的位置。对于垂直的图例,这个值应该是一个toplefttopcenterlefttop-rotleftcenter-rot。以下两张图显示了lefttop-rot标题和leftcenter-rot标题的效果。

lgd = Legend(col_fun = col_fun, title = "foooooooo", title_position = "lefttop-rot",
    legend_height = unit(4, "cm"))
image
lgd = Legend(col_fun = col_fun, title = "foooooooo", title_position = "leftcenter-rot",
    legend_height = unit(4, "cm"))
image

图例标题和标签可以设置为数学公式。

lgd = Legend(col_fun = col_fun, title = expression(hat(beta) == (X^t * X)^{-1} * X^t * y), 
    at = c(0, 0.25, 0.5, 0.75, 1), labels = expression(alpha, beta, gamma, delta, epsilon))
image

可以使用gridtext包(gridtext)添加更复杂的文本。

lgd = Legend(col_fun = col_fun, 
    title = gt_render("<span style='color:orange'>**Legend title**</span>"), 
    title_gp = gpar(box_fill = "grey"),
    at = c(-3, 0, 3), 
    labels = gt_render(c("<span style='color:blue'>*negative*</span> three", "zero", 
                         "<span style='color:red'>*positive*</span> three"))
)
image

用于水平连续图例设置是几乎相同的垂直图例,所不同的是现在控制图例的宽度,legend_width和标题位置只能topcentertopleftlefttopleftcenter之一。

水平图例的默认样式:

lgd = Legend(col_fun = col_fun, title = "foo", direction = "horizontal")
image

手动设置at

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.25, 0.5, 0.75, 1), 
    direction = "horizontal")
image

手动设置labels

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.5, 1), 
    labels = c("low", "median", "high"), direction = "horizontal")
image

设置legend_width

lgd = Legend(col_fun = col_fun, title = "foo", legend_width = unit(6, "cm"), 
    direction = "horizontal")
image

设置标签的图形参数:

lgd = Legend(col_fun = col_fun, title = "foo", labels_gp = gpar(col = "red", font = 3), 
    direction = "horizontal")
image

设置标签的旋转。

lgd = Legend(col_fun = col_fun, title = "foo", labels_rot = 45, 
    direction = "horizontal")
image

标题可以设置为topleft,topcenterlefttopleftcenter

lgd = Legend(col_fun = col_fun, title = "foooooooo", direction = "horizontal", 
    title_position = "topcenter")
image
lgd = Legend(col_fun = col_fun, title = "foooooooo", direction = "horizontal", 
    title_position = "lefttop")
image

在我们上面展示的例子中,每两个中断值之间的间隔是相等的。实际上at也可以设置为间隔不等的中断值。在这种情况下,图例上的刻度仍然在原始位置,而相应的文本被移动以消除重叠。然后,有连接刻度线和标签的线。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.1, 0.15, 0.5, 0.9, 0.95, 1))
image

如果标签不需要调整,它们仍然在原来的地方。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.3, 1), 
    legend_height = unit(4, "cm"))
image

水平图例类似:

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.1, 0.15, 0.5, 0.9, 0.95, 1),
    direction = "horizontal")
image

将标签的旋转设置为 90 度。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.1, 0.15, 0.5, 0.9, 0.95, 1),
    direction = "horizontal", title_position = "lefttop", labels_rot = 90)
image

当标题位置设置为lefttop时,在计算标签调整位置时也会考虑标题下方的区域。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.1, 0.5, 0.75, 1),
    labels = c("mininal", "q10", "median", "q75", "maximal"),
    direction = "horizontal", title_position = "lefttop")
image

如果按降序设置at,则图例反转,即 最小值 在图例的顶部。

lgd = Legend(col_fun = col_fun, title = "foo", at = c(1, 0.8, 0.6, 0.4, 0.2, 0))
image

大多数连续的图例都有等距的图例中断, 例如,第一次和第二次中断之间的距离与第二次和第三次中断之间的距离相同。但是,仍然存在一些特殊情况,如何设置不等距的图例中断呢?

在以下示例中,颜色映射函数col_fun_prop将比例值可视化为c(0, 0.05, 0.1, 0.5, 1)中的中断。距离不等的图例中断可能反映了c(0, 1)中值的不同重要性。例如,也许我们想在c(0, 0.1)中查看更多详细信息。

以下是图例的默认样式,其中从 0 到 1 以相等的距离选择中断。

col_fun_prop = colorRamp2(c(0, 0.05, 0.1, 0.5, 1), 
    c("green", "white", "red", "black", "blue"))
lgd = Legend(col_fun = col_fun_prop, title = "Prop")
image

你看不到c(0, 0.1)间隔中的细节,因为设置中断colorRamp2()仅定义了颜色映射,而不能确定图例中的中断。

如果我们手动选择中断值,颜色条保持不变。标签被移动,线将它们连接到原始位置。在这种情况下,颜色条中的距离仍然与中断值的实际差异成正比, 0.5-1 之间的距离是 0-0.1 的五倍。

col_fun_prop = colorRamp2(c(0, 0.05, 0.1, 0.5, 1), 
    c("green", "white", "red", "black", "blue"))
lgd = Legend(col_fun = col_fun_prop, title = "Prop",
    at = c(0, 0.05, 0.1, 0.5, 1))
image

从版本 2.7.1 开始,Legend()函数有一个新参数break_dist,用于控制图例中两个相邻中断值之间的距离。 可能会令人困惑,但从这里开始,当提到“中断距离”时,它总是指图例中的视觉距离。

break_dist的值的长度应为 1,这意味着所有中断值在图例中的距离相等,或者length(at) - 1.

lgd = Legend(col_fun = col_fun_prop, title = "Prop", break_dist = 1)
image

在下面的示例中,顶部的两个中断间隔比底部的两个间隔长三倍。

lgd = Legend(col_fun = col_fun_prop, title = "Prop", break_dist = c(1, 1, 3, 3))
image

如果我们通过legend_height参数增加图例高度,标签将有足够的空间,它们的位置不再调整。

lgd = Legend(col_fun = col_fun_prop, title = "Prop", break_dist = c(1, 1, 3, 3),
    legend_height = unit(4, "cm"))
image

想象以下用户案例,我们想对c(0, 0.1)中的值使用一种颜色方案,对c(0.1, 1)中的值使用第二种颜色方案,进而强调这两个区间非常不同。颜色映射可以定义为:

col_fun2 = colorRamp2(c(0, 0.1, 0.1+1e-6, 1), c("white", "red", "yellow", "blue"))

所以在这里我只是在(1e-6)到 0.1 上添加了一个微小的偏移,并将其设置为第二个配色方案的下限。图例如下:

lgd = Legend(col_fun = col_fun2, title = "Prop", at = c(0, 0.05, 0.1, 0.5, 1),
    break_dist = c(1, 1, 3, 3), legend_height = unit(4, "cm"))
image

现在您可以看到颜色从 0 到 1 并没有平滑地变化,并且有两种不同的配色方案。

5.2 离散图例

离散图例用于离散颜色映射。通过仅提供颜色和中断值,连续颜色映射也可以变化为离散颜色映射。

您可以指定atlabels,但最有可能指定 labels。颜色应由legend_gp指定。

lgd = Legend(at = 1:6, title = "foo", legend_gp = gpar(fill = 1:6))
image
lgd = Legend(labels = month.name[1:6], title = "foo", legend_gp = gpar(fill = 1:6))
image

连续颜色映射的离散图例:

at = seq(0, 1, by = 0.2)
lgd = Legend(at = at, title = "foo", legend_gp = gpar(fill = col_fun(at)))
image

标题位置:

lgd = Legend(labels = month.name[1:6], title = "foo", legend_gp = gpar(fill = 1:6),
    title_position = "lefttop")
image
lgd = Legend(labels = month.name[1:6], title = "foo", legend_gp = gpar(fill = 1:6),
    title_position = "leftcenter-rot")
image

网格的大小由grid_widthgrid_height控制。

lgd = Legend(at = 1:6, legend_gp = gpar(fill = 1:6), title = "foo", 
    grid_height = unit(1, "cm"), grid_width = unit(5, "mm"))
image

标签的图形参数由labels_gp控制。

lgd = Legend(labels = month.name[1:6], legend_gp = gpar(fill = 1:6), title = "foo", 
    labels_gp = gpar(col = "red", fontsize = 14))
image

标题的图形参数由title_gp控制。

lgd = Legend(labels = month.name[1:6], legend_gp = gpar(fill = 1:6), title = "foo", 
    title_gp = gpar(col = "red", fontsize = 14))
image

通过结合gridtext包,标题和标签可以是复杂的文本(拓展知识):

lgd = Legend(
    title = gt_render("<span style='color:orange'>**Legend title**</span>"), 
    title_gp = gpar(box_fill = "grey"),
    at = c(-3, 0, 3), 
    labels = gt_render(c("**negative** three", "*zero*", "**positive** three")),
    legend_gp = gpar(fill = 1:3)
)
image

网格的边界由border控制。

lgd = Legend(labels = month.name[1:6], legend_gp = gpar(fill = 1:6), title = "foo", 
    border = "red")
image

您可以将离散图例的网格排列成多行或者多列。如果ncol设置为数字,则网格按ncol列排列。

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), 
    title = "foo", ncol = 3)
image

仍然根据多列图例计算标题位置。

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), title = "foo", 
    ncol = 3, title_position = "topcenter")
image

您可以通过设置by_row = TRUE来选择按行列出图例级别。

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), title = "foo", 
    ncol = 3, by_row = TRUE)
image

两列之间的间隙由gapcolumn_gap控制。这两个参数的处理方式相同。

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), title = "foo", 
    ncol = 3, gap = unit(1, "cm"))
image

行之间的间隙由row_gap控制。

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), title = "foo", 
    ncol = 3, row_gap = unit(5, "mm"))
image

您还可以通过nrow指定布局代替ncol。但请注意,不能同时使用ncolnrow

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), 
    title = "foo", nrow = 3)
image

一种极端情况是所有级别都放在一排并且标题旋转 90 度。图例的高度将是旋转标题的高度。

lgd = Legend(labels = month.name[1:6], legend_gp = gpar(fill = 1:6), title = "foooooo", 
    nrow = 1, title_position = "lefttop-rot")
image

很多人可能会喜欢以下风格:

lgd = Legend(labels = month.name[1:6], legend_gp = gpar(fill = 1:6), title = "foooooo", 
    nrow = 1, title_position = "leftcenter")
image

Legend()还支持使用简单的图形(例如点、线、箱线图)作为图例。type参数可以指定为points或者p,可以使用数字或单字母作为pch

lgd = Legend(labels = month.name[1:6], title = "foo", type = "points", 
    pch = 1:6, legend_gp = gpar(col = 1:6), background = "#FF8080")
image
lgd = Legend(labels = month.name[1:6], title = "foo", type = "points", 
    pch = letters[1:6], legend_gp = gpar(col = 1:6), background = "white")
image

设置type = "lines"/type = "l"使用线条作为图例:

lgd = Legend(labels = month.name[1:6], title = "foo", type = "lines", 
    legend_gp = gpar(col = 1:6, lty = 1:6), grid_width = unit(1, "cm"))
image

设置type = "boxplot"/type = "box"使用箱线图作为图例:

lgd = Legend(labels = month.name[1:6], title = "foo", type = "boxplot",
    legend_gp = gpar(fill = 1:6))
image

pch是整数时,其中的数字26:28对应以下符号:

lgd = Legend(labels = paste0("pch = ", 26:28), type = "points", pch = 26:28)
image

在上面显示的所有示例中,标签都是单行。还支持多行标签。如以下示例所示,多线标签的图例网格会自动延长。

lgd = Legend(labels = c("aaaaa\naaaaa", "bbbbb\nbbbbb", "c", "d"),
    legend_gp = gpar(fill = 1:4))
image

如果图例排列成多行或多列,则图例网格的大小将调整为行数最多的标签。

lgd = Legend(labels = c("aaaaa\naaaaa", "c", "d", "bbbbb\nbbbbb"),
    legend_gp = gpar(fill = 1:4), nrow = 2)
image

最后一个有用的参数graphics可用于自定义图例图形。graphics的值是一个带有四个参数的函数列表:xy:图例网格的中心,wh:图例网格的宽度和高度。of 的长度graphics应与atlabels相同。如果graphics名称对应命名列表 labels,则graphics自动调整列表的顺序。

lgd = Legend(labels = letters[1:4],
    graphics = list(
        function(x, y, w, h) grid.rect(x, y, w*0.33, h, gp = gpar(fill = "red")),
        function(x, y, w, h) grid.rect(x, y, w, h*0.33, gp = gpar(fill = "blue")),
        function(x, y, w, h) grid.text("A", x, y, gp = gpar(col = "darkgreen")),
        function(x, y, w, h) grid.points(x, y, gp = gpar(col = "orange"), pch = 16)
    ))
image

5.3 图例列表

图例列表可以构建或打包为一个Legends对象,其中各个图例在特定布局内排列。图例列表可以单独发送packLegend()或作为列表发送。图例可以垂直或水平排列。在**ComplexHeatmap **内部使用packLegend() 来排列多个图例。通常您不需要手动控制多个图例的排列,但如果您想手动构建图例列表并应用于其他图,以下部分将非常有用。

lgd1 = Legend(at = 1:6, legend_gp = gpar(fill = 1:6), title = "legend1")
lgd2 = Legend(col_fun = col_fun, title = "legend2", at = c(0, 0.25, 0.5, 0.75, 1))
lgd3 = Legend(labels = month.name[1:3], legend_gp = gpar(fill = 7:9), title = "legend3")

pd = packLegend(lgd1, lgd2, lgd3)
# which is same as 
pd = packLegend(list = list(lgd1, lgd2, lgd3))
image

与单个图例类似,您可以按draw() 功能绘制打包图例。您还可以获得pdbyComplexHeatmap:::width()和 的大小ComplexHeatmap:::height()

ComplexHeatmap:::width(pd)
## [1] 19.1675555555556mm
ComplexHeatmap:::height(pd)
## [1] 78.6988333333334mm

通过设置水平排列图例,只需direction = "horizontal"

pd = packLegend(lgd1, lgd2, lgd3, direction = "horizontal")
image

packLegend()的一个特点是,例如,如果包装是垂直的并且包装图例的总和超过了指定的高度max_height,它将被重新排列为多列布局。在以下示例中,最大高度为10cm

当所有图例放入多列时,column_gap控制两列之间的空间。

pd = packLegend(lgd1, lgd3, lgd2, lgd3, lgd2, lgd1, max_height = unit(10, "cm"), 
    column_gap = unit(1, "cm"))
image

类似于水平包装:

lgd1 = Legend(at = 1:6, legend_gp = gpar(fill = 1:6), title = "legend1",
    nr = 1)
lgd2 = Legend(col_fun = col_fun, title = "legend2", at = c(0, 0.25, 0.5, 0.75, 1),
    direction = "horizontal")

pd = packLegend(lgd1, lgd2, lgd3, lgd1, lgd2, lgd3, max_width = unit(10, "cm"), 
    direction = "horizontal", column_gap = unit(5, "mm"), row_gap = unit(1, "cm"))
image

打包的图例pd也是一个Legends对象,这意味着您可以通过指定位置来绘制draw()它。

pd = packLegend(lgd1, lgd2, lgd3, direction = "horizontal")
pushViewport(viewport(width = 0.8, height = 0.8))
grid.rect()
draw(pd, x = unit(1, "cm"), y = unit(1, "cm"), just = c("left", "bottom"))
draw(pd, x = unit(1, "npc"), y = unit(1, "npc"), just = c("right", "top"))
popViewport()
image

再次重申,packLegend()在内部用于管理热图和注释图例列表。

5.4 热图和注释图例

热图图例的设置由Heatmap()中的heatmap_legend_param参数控制。Legend()的值是支持的参数列表heatmap_legend_param

m = matrix(rnorm(100), 10)
Heatmap(m, name = "mat", heatmap_legend_param = list(
    at = c(-2, 0, 2),
    labels = c("low", "zero", "high"),
    title = "Some values",
    legend_height = unit(4, "cm"),
    title_position = "lefttop-rot"
))
image

annotation_legend_param控制注释的图例。由于一个 HeatmapAnnotation可能包含多个注释,因此annotation_legend_param的值是每个注释的配置列表。

ha = HeatmapAnnotation(foo = runif(10), bar = sample(c("f", "m"), 10, replace = TRUE),
    annotation_legend_param = list(
        foo = list(
                title = "Fooooooh",
                at = c(0, 0.5, 1),
                labels = c("zero", "median", "one")
            ),
        bar = list(
                title = "Baaaaaaar",
                at = c("f", "m"),
                labels = c("Female", "Male")
            )
))
Heatmap(m, name = "mat", top_annotation = ha)
image

如果热图是水平连接的,则所有热图和行注释图例都被分组,所有列注释图例都被分组。我们假设水平方向作为主要信息,而垂直方向提供次要信息。

ha1 = HeatmapAnnotation(foo1 = runif(10), bar1 = sample(c("f", "m"), 10, replace = TRUE))
ha2 = HeatmapAnnotation(foo2 = runif(10), bar2 = sample(c("f", "m"), 10, replace = TRUE))
Heatmap(m, name = "mat1", top_annotation = ha1) +
rowAnnotation(sth = runif(10)) +
Heatmap(m, name = "mat2", top_annotation = ha2)
image

类似地,如果热图垂直连接,则所有热图的列注释都被分组,所有行注释的图例也被分组。

ha1 = HeatmapAnnotation(foo1 = runif(10), bar1 = sample(c("f", "m"), 10, replace = TRUE), 
    annotation_name_side = "left")
ha2 = HeatmapAnnotation(foo2 = runif(10), bar2 = sample(c("f", "m"), 10, replace = TRUE))
Heatmap(m, name = "mat1", top_annotation = ha1) %v%
Heatmap(m, name = "mat2", top_annotation = ha2, 
    right_annotation = rowAnnotation(sth = 1:10))
image

show_legendHeatmapAnnotation()中 和show_heatmap_legendHeatmap()中控制是否显示图例。注意:show_legend可以是单个逻辑值、逻辑向量或控制注释子集的命名向量。

ha = HeatmapAnnotation(foo = runif(10), 
    bar = sample(c("f", "m"), 10, replace = TRUE),
    show_legend = c(TRUE, FALSE), # it can also be show_legend = c(bar = FALSE)
    annotation_name_side = "left")
Heatmap(m, name = "mat1", top_annotation = ha) +
Heatmap(m, name = "mat2", show_heatmap_legend = FALSE)
image

draw()中的merge_legend函数控制是否将所有图例合并为一个组。通常,当注释和热图很多时,图例的数量总是很大。在这种情况下,图例会自动排列成多列(或多行,如果它们放在热图的底部)以摆脱图形页面。如果热图有热图注释,放置图例的顺序是:左注释的图例,顶部注释的图例,热图的图例,底部注释的图例和右注释的图例。

ha1 = HeatmapAnnotation(foo1 = runif(10), 
    bar1 = sample(c("f", "m"), 10, replace = TRUE))
ha2 = rowAnnotation(foo2 = runif(10), 
    bar2 = sample(letters[1:3], 10, replace = TRUE))
ha3 = rowAnnotation(foo3 = runif(10), 
    bar3 = sample(month.name[1:3], 10, replace = TRUE))
ht_list = Heatmap(m, name = "mat1", top_annotation = ha1) + 
    Heatmap(m, name = "mat2", left_annotation = ha2) + 
    ha3
draw(ht_list, merge_legend = TRUE)
image

如果您希望热图图例成为“纯热图图例”,您可以设置 legend_grouping = "original"强制将所有注释图例放在一起,无论它们是行注释图例还是列注释图例。

draw(ht_list, legend_grouping = "original")
image

通过设置color_bar = "discrete",连续颜色映射可以具有离散图例,均适用于热图图例和注释图例。

Heatmap(m, name = "mat", heatmap_legend_param = list(color_bar = "discrete"),
    top_annotation = HeatmapAnnotation(foo = 1:10,
        annotation_legend_param = list(
            foo = list(color_bar = "discrete"))))
image

如果value是字符向量,无论是注释还是热图的单行一列矩阵,图例标签的默认顺序都是sort(unique(value)),如果value 是因子,则图例标签的顺序是levels(value)。永远记住顺序可以分别通过Heatmap()heatmap_legend_param()/ annotation_legend_param()/HeamtapAnnotation()函数中设置atlabels参数进行微调。

chr = sample(letters[1:3], 10, replace = TRUE)
chr
##  [1] "a" "c" "b" "a" "c" "a" "a" "c" "c" "b"
fa1 = factor(chr)
fa2 = factor(chr, levels = c("c", "a", "b"))
Heatmap(m, top_annotation = HeatmapAnnotation(chr = chr, fa1 = fa1, fa2 = fa2, fa3 = fa2,
    annotation_legend_param = list(fa3 = list(at = c("b", "c", "a")))))
image

5.5 添加自定义图例

自定义图例(由Legend()构造)可以通过heatmap_legend_list参数添加到热图图例列表draw()中,注释的图例可以通过annotation_legend_list参数添加到注释图例列表中 。

拓展知识 中有一个很好的添加自定义图例的例子 ,但这里我们展示一个简单的例子。

如前所述,只有热图和简单的注释才能在图上生成图例。ComplexHeatmap提供了很多注释函数,但都不支持生成图例。在以下代码中,我们向热图中添加了点注释、线注释和摘要注释。

ha1 = HeatmapAnnotation(pt = anno_points(1:10, gp = gpar(col = rep(2:3, each = 5)), 
    height = unit(2, "cm")), show_annotation_name = FALSE)
ha2 = HeatmapAnnotation(ln = anno_lines(cbind(1:10, 10:1), gp = gpar(col = 4:5, lty = 1:2),
    height = unit(2, "cm")), show_annotation_name = FALSE)
m = matrix(rnorm(100), 10)
ht_list = Heatmap(m, name = "mat1", top_annotation = ha1) + 
          Heatmap(m, name = "mat2", top_annotation = ha2) +
          Heatmap(m[, 1], name = "mat3", 
            top_annotation = HeatmapAnnotation(
                summary = anno_summary(gp = gpar(fill = 2:3))
          ), width = unit(1, "cm"))
draw(ht_list, ht_gap = unit(7, "mm"), row_km = 2)
image

接下来,我们为点、线和箱线图构建图例。

lgd_list = list(
    Legend(labels = c("red", "green"), title = "pt", type = "points", pch = 16, 
        legend_gp = gpar(col = 2:3)),
    Legend(labels = c("darkblue", "lightblue"), title = "ln", type = "lines", 
        legend_gp = gpar(col = 4:5, lty = 1:2)),
    Legend(labels = c("group1", "group2"), title = "km", type = "boxplot",
        legend_gp = gpar(fill = 2:3))
)
draw(ht_list, ht_gap = unit(7, "mm"), row_km = 2, annotation_legend_list = lgd_list)
image

5.6 边缘图例

默认情况下,热图图例和注释图例放在图的右侧。两种类型图例的热图相对的一侧可以由函数draw()中的heatmap_legend_sideannotation_legend_side参数控制。可以为两个参数设置的值是 leftrightbottomtop

m = matrix(rnorm(100), 10)
ha1 = HeatmapAnnotation(foo1 = runif(10), bar1 = sample(c("f", "m"), 10, replace = TRUE))
ha2 = HeatmapAnnotation(foo2 = runif(10), bar2 = sample(c("f", "m"), 10, replace = TRUE))
ht_list = Heatmap(m, name = "mat1", top_annotation = ha1) +
    rowAnnotation(sth = runif(10)) +
    Heatmap(m, name = "mat2", top_annotation = ha2)
draw(ht_list, heatmap_legend_side = "left", annotation_legend_side = "bottom")
image

当图例放在底部或顶部时,图例水平排列。我们可能还需要设置每一个图例的水平图例,这需要通过设置Heatmap()HeatmapAnnotation() 函数中的heatmap_legend_paramannotation_legend_param参数:

ha1 = HeatmapAnnotation(foo1 = runif(10), bar1 = sample(c("f", "m"), 10, replace = TRUE),
    annotation_legend_param = list(
        foo1 = list(direction = "horizontal"),
        bar1 = list(nrow = 1)))
ha2 = HeatmapAnnotation(foo2 = runif(10), bar2 = sample(c("f", "m"), 10, replace = TRUE),
    annotation_legend_param = list(
        foo2 = list(direction = "horizontal"),
        bar2 = list(nrow = 1)))
ht_list = Heatmap(m, name = "mat1", top_annotation = ha1, 
        heatmap_legend_param = list(direction = "horizontal")) +
    rowAnnotation(sth = runif(10), 
        annotation_legend_param = list(sth = list(direction = "horizontal"))) +
    Heatmap(m, name = "mat2", top_annotation = ha2,
        heatmap_legend_param = list(direction = "horizontal"))
draw(ht_list, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
image
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342