ComplexHeatmap复杂热图绘制学习——3.热图注释(二)

3.14文字标注

文本可以用anno_text()注释。图形参数由gp控制。

ha = rowAnnotation(foo = anno_text(month.name, gp = gpar(fontsize = 1:12+4)))
image

位置由locationjust控制。旋转由rot控制。

ha = rowAnnotation(foo = anno_text(month.name, location = 1, rot = 30, 
    just = "right", gp = gpar(fontsize = 1:12+4)))
image
ha = rowAnnotation(foo = anno_text(month.name, location = 0.5, just = "center"))
image.png

locationjust根据放置在热图中的注释的位置自动计算(例如,如果文本是热图的右注释,则文本向左对齐,如果它是左注释则向右对齐)。

宽度/高度是根据所有文本自动计算的。通常你不需要手动设置它的宽度/高度。

可以通过gp设置背景颜色。这里fill控制填充背景颜色,col控制文本颜色,border控制背景边框颜色。

您可以看到我们明确设置width为最长文本宽度的 1.2 倍。

ha = rowAnnotation(foo = anno_text(month.name, location = 0.5, just = "center",
    gp = gpar(fill = rep(2:4, each = 4), col = "white", border = "black"),
    width = max_text_width(month.name)*1.2))
image

可以通过与gridtext 包集成来绘制更复杂的文本(gridtext注释)。一个简单的例子如下:

text = sapply(LETTERS[1:10], function(x) {
    qq("**@{x}**@{x}_@{x}_@{x}")
})
ha = rowAnnotation(
    foo = anno_text(gt_render(text, align_widths = TRUE, 
                        r = unit(2, "pt"),
                        padding = unit(c(2, 2, 2, 2), "pt")), 
                    gp = gpar(box_col = "blue", box_lwd = 2), 
                    just = "right", 
                    location = unit(1, "npc")
    ))
image

与其他注释不同,默认情况下文本注释没有注释标题。标题可以在anno_text()通过设置show_name = TRUE被添加:

m = matrix(rnorm(100), 10)
Heatmap(m) + rowAnnotation(month = anno_text(month.name[1:10], just = "center", 
        location = unit(0.5, "npc"), show_name = TRUE), 
    annotation_name_rot = 0)
image

3.15标记注释

有时热图中有很多行或列,我们想标记其中的一些。anno_mark()用于标记行或列的子集并用线连接到标签。

anno_mark()至少需要两个参数:atlabels,其中at是原始矩阵的索引和labels相应的文本。

m = matrix(rnorm(1000), nrow = 100)
rownames(m) = 1:100
ha = rowAnnotation(foo = anno_mark(at = c(1:4, 20, 60, 97:100), labels = month.name[1:10]))
Heatmap(m, name = "mat", cluster_rows = FALSE, right_annotation = ha,
    row_names_side = "left", row_names_gp = gpar(fontsize = 4))
Heatmap(m, name = "mat", cluster_rows = FALSE, right_annotation = ha,
    row_names_side = "left", row_names_gp = gpar(fontsize = 4), row_km = 4)
image

文本位置的计算取决于图形设备的绝对大小。如果您调整当前交互设备的大小或grid.grabExpr() 用于捕获当前绘图,您可能会看到文本的位置都已损坏。解决方法请参考cowplot。

3.16 摘要注释

有一个特殊的注释anno_summary()只适用于一列热图或一行热图(我们可以说热图只包含一个向量)。它显示了热图中向量的汇总统计信息。如果相应的向量是离散的,则摘要注释显示为条形图,如果向量是连续的,则摘要注释是箱线图。 anno_summary()总是在热图分割时使用,以便可以在热图切片之间比较统计数据。

第一个示例显示了离散热图的摘要注释。条形图显示每个切片中每个级别的比例。热图切片的高度已经可以看到绝对值。

条形图的颜色模式是从热图中自动获取的。

ha = HeatmapAnnotation(summary = anno_summary(height = unit(4, "cm")))
v = sample(letters[1:2], 50, replace = TRUE)
split = sample(letters[1:2], 50, replace = TRUE)

Heatmap(v, name = "mat", col = c("a" = "red", "b" = "blue"),
    top_annotation = ha, width = unit(2, "cm"), row_split = split)
image

第二个示例显示了连续热图的摘要注释。图形参数应由gp手动设置。可以按照离散图例最后第二段中的介绍创建和添加箱线图的图例。

ha = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:3), 
    height = unit(4, "cm")))
v = rnorm(50)
Heatmap(v, name = "mat", top_annotation = ha, width = unit(2, "cm"), 
    row_split = split)
image

通常我们不会绘制这个单列热图。它总是与其他“主要热图”结合在一起。例如,带有单列热图的基因表达矩阵,显示该基因是蛋白质编码基因还是 linc-RNA 基因。

在下面,我们展示了一个带有两个单列热图的“主热图”的简单示例。热图连接的功能将在热图列表介绍。

m = matrix(rnorm(50*10), nrow = 50)
ht_list = Heatmap(m, name = "main_matrix")

ha = HeatmapAnnotation(summary = anno_summary(height = unit(3, "cm")))
v = sample(letters[1:2], 50, replace = TRUE)
ht_list = ht_list + Heatmap(v, name = "mat1", top_annotation = ha, width = unit(1, "cm"))

ha = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:3), 
    height = unit(3, "cm")))
v = rnorm(50)
ht_list = ht_list + Heatmap(v, name = "mat2", top_annotation = ha, width = unit(1, "cm"))

split = sample(letters[1:2], 50, replace = TRUE)
lgd_boxplot = Legend(labels = c("group a", "group b"), title = "group",
    legend_gp = gpar(fill = c("red", "blue")))
draw(ht_list, row_split = split, ht_gap = unit(5, "mm"), 
    heatmap_legend_list = list(lgd_boxplot))
image

3.17 缩放/链接注释

anno_mark()将热图上的单行或单列连接到标签,下一个注释功能anno_link()将行或列的子集连接到可以添加更全面图形的绘图区域。请参阅以下示例,其中我们为每个行组制作箱线图。

set.seed(123)
m = matrix(rnorm(100*10), nrow = 100)
subgroup = sample(letters[1:3], 100, replace = TRUE, prob = c(1, 5, 10))
rg = range(m)
panel_fun = function(index, nm) {
    pushViewport(viewport(xscale = rg, yscale = c(0, 2)))
    grid.rect()
    grid.xaxis(gp = gpar(fontsize = 8))
    grid.boxplot(m[index, ], pos = 1, direction = "horizontal")
    popViewport()
}
anno = anno_link(align_to = subgroup, which = "row", panel_fun = panel_fun, 
    size = unit(2, "cm"), gap = unit(1, "cm"), width = unit(4, "cm"))
Heatmap(m, name = "mat", right_annotation = rowAnnotation(foo = anno), row_split = subgroup)
image

anno_zoom()的重要参数是:

  1. align_to:它定义了绘图区域(或框)如何对应于热图中的行或列。如果该值是一个索引列表,则每个框对应于列表中一个向量中带有索引的行或列。如果该值是与热图中的行或列具有相同长度的分类变量(例如因子或字符向量),则每个框对应于分类变量中每个级别的行/列。
  2. panel_fun: 自定义函数,定义如何在框中绘制图形。该函数必须有一个index参数,它是框对应的行/列的索引。它可以有第二个参数 nm,即热图中所选部分的“名称”。如果将其指定为分类变量或带有名称的列表,则对应的值nm来自align_to
  3. size: 盒子的大小。它们可以是纯数字,它们被视为热图总高度/宽度的相对分数。size的值也可以是绝对单位。
  4. gap: 盒子之间的间隙。它应该是一个unit对象。

anno_link() 也适用于列注释。

另一个使用anno_link()示例是将词云列表与行组对应,请参阅博客文章将词海应用到热图注释以了解如何使用anno_link().

image

anno_mark()类似,绘图区域的位置也取决于图形设备的绝对大小。如果您调整当前交互设备的大小或grid.grabExpr()用于捕获当前绘图,您可能会看到文本的位置都已损坏。解决方法请参考cowplot。

3.18 多重注解

3.18.1 一般设置

如前所述,要在HeatmapAnnotation()中放置多个注释,只需将它们指定为名称-值对。在HeatmapAnnotation()中,有一些参数控制多个注释。对于这些参数,它们被指定为长度与注释数量相同的向量,或具有注释子集的命名向量。

被指定为向量、矩阵和数据框的简单注释将自动在热图上有图例。show_legend控制是否为它们绘制图例。请注意,如果show_legend是向量,则show_legend的值应为以下格式之一:

  • 长度与简单注释数量相同的逻辑向量。
  • 一个与totla注释数量相同长度的逻辑向量。复杂注释的值将被忽略。
  • 用于控制简单注释子集的命名向量。

自定义注释图例,请参考热图图例注释节。

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    show_legend = c("bar" = FALSE)
)
Heatmap(matrix(rnorm(100), 10), name = "mat", top_annotation = ha)
image

gp控制简单注释的图形参数(除了fill),例如注释网格的边框。

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    gp = gpar(col = "red")
)
image

border控制每个注释的边界。 show_annotation_name控制是否显示注释名称。如前所述,该值可以是单个值、向量或命名向量。

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    show_annotation_name = c(bar = FALSE), # only turn off `bar`
    border = c(foo = TRUE) # turn on foo
)
image

annotation_name_gp, annotation_name_offset,annotation_name_sideannotation_name_rot控制注释名称的样式和位置。后三个可以指定为命名向量。如果 annotation_name_offset指定为命名向量,则可以指定为字符而不是unit对象:annotation_name_offset = c(foo = "1cm")

gap控制每两个相邻注释之间的空间。该值可以是单个值或单位向量。

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    gap = unit(2, "mm"))
image
ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    gap = unit(c(2, 10), "mm"))
image

3.18.2注释的大小

height, width,annotation_heightannotation_width控制完整热图注释的高度或宽度。通常你不需要设置它们,因为所有单个注释都有固定的高度/宽度,整个热图注释的最终高度/宽度是它们的总和。调整这些值的大小将涉及相当复杂的调整,具体取决于它是简单注释还是复杂注释。调整热图列表时也会调整热图注释的大小。在下面的例子中,我们以列注解为例,展示了一些调整大小的场景。

首先是默认高度ha

# foo: 1cm, bar: 5mm, pt: 1cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10))
image

如果设置height,则简单注释的大小不会改变,而只调整复杂注释。如果有多个复杂的注解,则按照其原始大小的比例进行调整。

# foo: 1cm, bar: 5mm, pt: 4.5cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10),
    height = unit(6, "cm"))
image

simple_anno_size控制所有简单注释的高度。ht_opt$simple_anno_size可以设置为全局控制所有热图中简单注释的大小。

# foo: 2cm, bar:1cm, pt: 3cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10),
    simple_anno_size = unit(1, "cm"), height = unit(6, "cm"))
image

如果annotation_height设置为绝对单位向量,则所有三个注释的高度都会相应调整。

# foo: 1cm, bar: 2cm, pt: 3cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10),
    annotation_height = unit(1:3, "cm"))
image

如果annotation_height设置为纯数字作为注释的相对比例,height也应该设置为绝对单位,每个注释的大小由比例调整。

# foo: 1cm, bar: 2cm, pt: 3cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10),
    annotation_height = 1:3, height = unit(6, "cm"))
image

annotation_height可以与相对单位(null 单位)和绝对单位混合使用。

# foo: 1.5cm, bar: 1.5cm, pt: 3cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10),
    annotation_height = unit(c(1, 1, 3), c("null", "null", "cm")), height = unit(6, "cm")
)
image
# foo: 2cm, bar: 1cm, pt: 3cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    pt = anno_points(1:10),
    annotation_height = unit(c(2, 1, 3), c("cm", "null", "cm")), height = unit(6, "cm")
)
image

如果只有简单的注释,简单的设置height不会改变高度。

# foo: 1cm, bar: 5mm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    height = unit(6, "cm"))
image

除非simple_anno_size_adjust设置为TRUE

# foo: 4cm, bar: 2cm
ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
    bar = 1:10,
    height = unit(6, "cm"),
    simple_anno_size_adjust = TRUE)
image

调整注释大小介绍了如何在热图列表中调整注释大小。

3.18.3注释标签

从2.3.3 版本开始,可以通过annotation_label参数设置注释的替代标签:

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    annotation_label = c("Annotation_foo", "Annotation_bar", "Annotation_pt")
)
image

也可以使用复杂的文本设置注释标签:

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    annotation_label = gt_render(
        c("**Annotation**_foo", 
          "**Annotation**_bar", 
          "**Annotation**_pt"),
        gp = gpar(box_fill = "grey")
    )
)
image

从 2.5.6 版本开始,可以配置注释名称的轮换。

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    annotation_name_rot = 45
)
Heatmap(matrix(rnorm(100), 10), name = "mat", top_annotation = ha)
image

或在行上:

ha = rowAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10),
    annotation_name_rot = 45
)
Heatmap(matrix(rnorm(100), 10), name = "mat", left_annotation = ha)
image

3.19实用功能

有一些实用函数可以使热图注释的操作更容易。请参阅以下示例。

ha = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10))
length(ha)
## [1] 3
nobs(ha)
## [1] 10

获取或设置注释的名称:

names(ha)
## [1] "foo" "bar" "pt"
names(ha) = c("FOO", "BAR", "PT")
names(ha)
## [1] "FOO" "BAR" "PT"

如果两个HeatmapAnnotation对象包含相同数量的观察名和不同的注释名称,则可以将它们连接起来。

ha1 = HeatmapAnnotation(foo = 1:10, 
    bar = cbind(1:10, 10:1),
    pt = anno_points(1:10))
ha2 = HeatmapAnnotation(FOO = runif(10), 
    BAR = sample(c("a", "b"), 10, replace = TRUE),
    PT = anno_points(rnorm(10)))
ha = c(ha1, ha2)
names(ha)
## [1] "foo" "bar" "pt"  "FOO" "BAR" "PT"
image

HeatmapAnnotation对象有时是允许有子集的。行索引对应于注释中的观察值,列索引对应于注释。如果注释都是简单注释或者ComplexHeatmap包中的anno_*()函数创建的复杂注解,则HeatmapAnnotation对象始终是子集化的。

ha_subset = ha[1:5, c("foo", "PT")]
ha_subset
## A HeatmapAnnotation object with 2 annotations
##   name: heatmap_annotation_109 
##   position: column 
##   items: 5 
##   width: 1npc 
##   height: 15.3514598035146mm 
##   this object is subsetable
##   7.57106666666667mm extension on the left 
##   6.75733333333333mm extension on the right 
## 
##  name   annotation_type color_mapping height
##   foo continuous vector        random    5mm
##    PT     anno_points()                 10mm
image

热图和注释的构建可以分开,以后可以通过attach_annotation()函数将注释填充到热图对象中。

# code only for demonstration
ha1 = HeatmapAnnotation(foo = 1:10)
ha2 = rowAnnotation(bar = letters[1:10])
ht = Heatmap(mat)
ht = attach_annotation(ht, ha1, side = "top")
ht = attach_annotation(ht, ha2, side = "left")

3.20 实现新的注解功能

ComplexHeatmap中定义的所有注释函数都是由AnnotationFunction该类构造的。的AnnotationFunction类不仅存储了“REAL R函数”,其绘制的图形,它也计算产生的注释轴的空间,更重要的是,它可以根据主热图的分割而分裂的注释的图形。

正如预估,AnnotationFunction类的主要部分是一个函数,它定义了如何在与热图中的行或列相对应的特定位置进行绘制。该函数应具有三个参数:index,kn(参数的名称可以是任意的)其中kn是可选的。index对应于热图的行或列的索引。index的值不一定是热图中的整个行索引或列索引。如果根据热图的拆分将注释拆分为切片,则它也可以是索引的子集。 index根据热图行或列的重新排序(例如通过聚类重新排序)。所以,index 实际上包含行或列重新排序后当前切片的行或列索引列表。

如前所述,注释可以分成多个切片。k对应当前切片,n对应切片总数。注释函数在每个切片中重复绘制。kn有时是有用的信息,例如,我们要在注释中添加轴,如果它是一个列注释和轴画在最右边标注的面积,轴只绘制时k == n

由于该函数只允许index,kn,该函数有时会使用多个无法在函数内部定义的外部变量,例如注释的数据点。这些变量应该被导入到AnnotationFunction类中,var_import这样函数才能正确地找到这些变量。

AnnotationFunction类的一个重要特性是它可以是可子集的,这是拆分的基础。为了允许对象的子集化,用户需要为导入的变量定义规则(如果有相应的规则)。规则是简单的函数,它接受变量和索引,并返回变量的子集。在这个包中实现的子集规则函数是 subset_gp(),subset_matrix_by_row()subset_vector()。如果未提供子集规则,则通过对象的类型来推断。

我们首先构造一个需要外部变量并支持子集化的AnnotationFunction对象。

x = 1:10
anno1 = AnnotationFunction(
    fun = function(index, k, n) {
        n = length(index)
        pushViewport(viewport(xscale = c(0.5, n + 0.5), yscale = c(0, 10)))
        grid.rect()
        grid.points(1:n, x[index], default.units = "native")
        if(k == 1) grid.yaxis()
        popViewport()
    },
    var_import = list(x = x),
    n = 10,
    subsetable = TRUE,
    height = unit(2, "cm")
)
anno1
## An AnnotationFunction object
##   function: user-defined
##   position: column 
##   items: 10 
##   width: 1npc 
##   height: 2cm 
##   imported variable: x 
##   this object is subsetable

然后我们可以在HeatmapAnnotation()函数中赋值anno1。由于anno1是子集化的,您可以拆分热图的列。

m = rbind(1:10, 11:20)
Heatmap(m, top_annotation = HeatmapAnnotation(foo = anno1))
Heatmap(m, top_annotation = HeatmapAnnotation(foo = anno1), 
    column_split = rep(c("A", "B"), each = 5))
image

第二种方式是将所有数据变量放在函数内部,不需要导入其他变量。

# code only for demonstration
anno2 = AnnotationFunction(
    fun = function(index) {
        x = 1:10
        n = length(index)
        pushViewport(viewport())
        grid.points(1:n, x[index])
        popViewport()
    },
    n = 10,
    subsetable = TRUE
)

仅向构造函数指定函数的最紧凑方法。

# code only for demonstration
anno3 = AnnotationFunction(
    fun = function(index) {
        x = 1:10
        n = length(index)
        pushViewport(viewport())
        grid.points(1:n, x[index])
        popViewport()
    }
)

anno_*()本节介绍的所有函数实际上都不是真正的注释函数,而是生成特定配置的注释函数的函数。作为用户就不需要知道。

anno_points(1:10)
## An AnnotationFunction object
##   function: anno_points()
##   position: column 
##   items: 10 
##   width: 1npc 
##   height: 1cm 
##   imported variable: data_scale, axis_param, border, size, value, pch_as_image, axis, gp, axis_grob, pch 
##   subsetable variable: gp, value, size, pch 
##   this object is subsetable
##   5.13831111111111mm extension on the left

在大多数情况下,您不需要手动构建AnnotationFunction 对象。ComplexHeatmapanno_*()实现的标注功能,对于大部分的分析任务来说已经足够了。另一方面,用户还可以使用和快速添加自定义标注图形。例如,我们可以将之前的热图重新实现为:anno_empty() decorate_annotation()

ht = Heatmap(m, top_annotation = HeatmapAnnotation(foo = anno_empty(height = unit(2, "cm"))), 
    column_split = rep(c("A", "B"), each = 5))
ht = draw(ht)
co = column_order(ht)
decorate_annotation("foo", slice = 1, {
    od = co[[1]]
    pushViewport(viewport(xscale = c(0.5, length(od) + 0.5), yscale = range(x)))
    grid.points(seq_along(od), x[od])
    grid.yaxis()
    popViewport()
})
decorate_annotation("foo", slice = 2, {
    od = co[[2]]
    pushViewport(viewport(xscale = c(0.5, length(od) + 0.5), yscale = range(x)))
    grid.points(seq_along(od), x[od])
    popViewport()
})
image

为了简化 的使用AnnotationFunction(),从 2.9.3 版本开始,它有一个新参数cell_fun,该参数接受仅在单个“注释单元格”中绘制的自定义函数。请参阅以下示例:

anno_pct = function(x) {

    max_x = max(x)
    text = paste0(sprintf("%.2f", x*100), "%")
    cell_fun_pct = function(i) {
        pushViewport(viewport(xscale = c(0, max_x)))
        grid.roundrect(x = unit(1, "npc"), width = unit(x[i], "native"), height = unit(1, "npc") - unit(4, "pt"), 
            just = "right", gp = gpar(fill = "#0000FF80", col = NA))
        grid.text(text[i], x = unit(1, "npc"), just = "right")
        popViewport()
    }

    AnnotationFunction(
        cell_fun = cell_fun_pct,
        var_import = list(max_x, x, text), 
        which = "row",
        width = max_text_width(text)*1.25
    )
}

x = runif(10)
ha = rowAnnotation(foo = anno_pct(x), annotation_name_rot = 0)

m = matrix(rnorm(100), 10)
rownames(m) = x
ha + Heatmap(m)
image

你可能感兴趣的:(ComplexHeatmap复杂热图绘制学习——3.热图注释(二))