ComplexHeatmap复杂热图绘制学习——3.热图注释(二
3.14文字标注
文本可以用anno_text()
注释。图形参数由gp
控制。
ha = rowAnnotation(foo = anno_text(month.name, gp = gpar(fontsize = 1:12+4)))
image
位置由location
和just
控制。旋转由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
location
和just
根据放置在热图中的注释的位置自动计算(例如,如果文本是热图的右注释,则文本向左对齐,如果它是左注释则向右对齐)。
宽度/高度是根据所有文本自动计算的。通常你不需要手动设置它的宽度/高度。
可以通过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("<span style='color:red'>**@{x}**<sub>@{x}</sub></span>_@{x}_<sup>@{x}</sup>")
})
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()
至少需要两个参数:at
、labels
,其中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()
的重要参数是:
-
align_to
:它定义了绘图区域(或框)如何对应于热图中的行或列。如果该值是一个索引列表,则每个框对应于列表中一个向量中带有索引的行或列。如果该值是与热图中的行或列具有相同长度的分类变量(例如因子或字符向量),则每个框对应于分类变量中每个级别的行/列。 -
panel_fun
: 自定义函数,定义如何在框中绘制图形。该函数必须有一个index
参数,它是框对应的行/列的索引。它可以有第二个参数nm
,即热图中所选部分的“名称”。如果将其指定为分类变量或带有名称的列表,则对应的值nm
来自align_to
。 -
size
: 盒子的大小。它们可以是纯数字,它们被视为热图总高度/宽度的相对分数。size
的值也可以是绝对单位。 -
gap
: 盒子之间的间隙。它应该是一个unit
对象。
anno_link()
也适用于列注释。
另一个使用anno_link()
示例是将词云列表与行组对应,请参阅博客文章将词海应用到热图注释以了解如何使用anno_link()
.
与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_side
和 annotation_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_height
并annotation_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**_<span style='color:red'>foo</span>",
"**Annotation**_<span style='color:blue'>bar</span>",
"**Annotation**_<span style='color:green'>pt</span>"),
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
,k
和n
(参数的名称可以是任意的)其中k
和n
是可选的。index
对应于热图的行或列的索引。index
的值不一定是热图中的整个行索引或列索引。如果根据热图的拆分将注释拆分为切片,则它也可以是索引的子集。 index
根据热图行或列的重新排序(例如通过聚类重新排序)。所以,index
实际上包含行或列重新排序后当前切片的行或列索引列表。
如前所述,注释可以分成多个切片。k
对应当前切片,n
对应切片总数。注释函数在每个切片中重复绘制。k
和n
有时是有用的信息,例如,我们要在注释中添加轴,如果它是一个列注释和轴画在最右边标注的面积,轴只绘制时k == n
。
由于该函数只允许index
,k
和n
,该函数有时会使用多个无法在函数内部定义的外部变量,例如注释的数据点。这些变量应该被导入到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
对象。ComplexHeatmap 中anno_*()
实现的标注功能,对于大部分的分析任务来说已经足够了。另一方面,用户还可以使用和快速添加自定义标注图形。例如,我们可以将之前的热图重新实现为: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