ComplexHeatmap复杂热图绘制学习——10.其它高级图

其它高级图

参考链接

1.密度热图

我们通常使用箱线图或小提琴图可视化矩阵或列表中的数据,。我们还可以使用颜色来映射密度值并通过热图可视化分布。如果您有大量数据要可视化,这将非常有用。

在以下示例中,我们使用矩阵作为输入数据,其中密度按列计算。输入数据也可以是一个列表。

set.seed(123)
m = cbind(matrix(rnorm(10*100), ncol = 10),
          matrix(runif(10*100, min = -2, max = 2) + 0.5, ncol = 10))
colnames(m) = paste0("C", 1:ncol(m))
densityHeatmap(m)
image

在热图上,还有五个分位数和平均值的线条。

数据范围由ylim控制。标题由titlecolumn_title控制。y 轴上的标题由ylab控制。

densityHeatmap(m, ylim = c(-2, 2), title = "Distribution as heatmap", ylab = "some values")
image.png

列顺序由column_order控制。

densityHeatmap(m, column_order = sample(20, 20))
image.png

密度值的颜色由col控制,col是一个向量。

densityHeatmap(m, col = topo.colors(10))
image

在内部,所有列的密度都存储为一个矩阵,其中行对应于相同的 bin。由于它是一个矩阵,因此可以对其应用聚类。有一种特殊的距离方法ks用于测量分布之间的相似性,即两个分布之间的 Kolmogorov-Smirnov 统计量(如果 cluster_column = TRUE,则ks距离是默认值)。

densityHeatmap(m, cluster_columns = TRUE, clustering_distance_columns = "ks")
image.png

当有许多分布来计算成对 Kolmogorov-Smirnov 距离时, 为提高运行速度,设置mc.cores参数可以并行运行。

densityHeatmap(m, cluster_columns = TRUE, mc.cores = ...)

列注释可以添加为顶部注释或底部注释。

ha1 = HeatmapAnnotation(dist = c(rep("rnorm", 10), rep("runif", 10)))
ha2 = HeatmapAnnotation(foo = anno_points(rnorm(20)))
densityHeatmap(m, top_annotation = ha1, bottom_annotation = ha2)
image

热图和列注释只能垂直连接到密度热图。

densityHeatmap(m) %v%
HeatmapAnnotation(foo = anno_barplot(1:20)) %v%
Heatmap(matrix(rnorm(20*20), ncol = 20), name = "mat", height = unit(6, "cm"))
image.png

还有一个frequencyHeatmap()函数类似于密度热图的直方图版本。用法类似于densityHeatmap()

frequencyHeatmap(m)

2. 堆叠图

多个注释和热图可用于可视化同一组特征的多个汇总统计数据。在以下示例中,有来自四个不同亚组的差异甲基化区域 (DMR) 的多个统计数据。

lt = readRDS(system.file("extdata", package = "ComplexHeatmap", "dmr_summary.rds"))
names(lt)
##  [1] "label"         "mean_meth"     "n_gr"          "n_corr"       
##  [5] "dist_tss"      "gene_anno"     "cgi_anno"      "mat_enrich_gf"
##  [9] "mat_pct_st"    "mat_enrich_st"

这些 DMR 的统计数据是:

  • label:DMR 集的标签。有四个亚组的 DMR,对于每个亚组,DMR 分为高甲基化 DMR 和低甲基化 DMR。
  • mean_meth:肿瘤样品和正常样品中 DMR 的平均甲基化。
  • n_gr 每组 DMR 的数量。
  • n_corr:显示与附近基因显着相关的 DMR 的百分比。分别计算正相关和负相关。
  • dist_tss:与附近基因 TSS 的距离。该值是当前集合中距离小于 1kb、1kb-5kb、5kb-10kb 以及大于 10kb 的 DMR 的比例。
  • gene_anno:与基因或基因间区域重叠的 DMR 的比例。
  • cgi_anno:与 CpG 岛或 CGI 岛重叠的 DMR 的比例。
  • mat_enrich_gf:对基因组特征列表的丰度。正值意味着过度代表。
  • mat_pct_st:与染色质状态重叠的 DMR 的比例。
  • mat_enrich_st:染色质状态的富集。

将所有这些变量附加到工作环境中。

attach(lt)

由于我们有许多统计数据需要可视化,我们首先定义颜色。我们为要可视化为热图的统计数据定义颜色映射函数,并为要可视化为条形图的统计数据定义颜色映射函数。

library(circlize)
meth_col_fun = colorRamp2(c(0, 0.5, 1), c("blue", "white", "red"))
corr_col = c("green", "red")
dist_tss_col = c("#FF0000", "#FF7352", "#FFB299", "#FFD9CB")
gene_anno_col = c("green", "blue")
cgi_anno_col = c("#FFA500", "#FFD191")
z_score_col_fun = colorRamp2(c(-200, 0, 200), c("green", "white", "red"))
state_col = c("#FF0000", "#008000", "#C2E105", "#8A91D0", "#CD5C5C", "#808080", "#000000")

热图列表的构建非常简单。每个统计数据都被构造为热图或行注释。

anno_width = unit(3, "cm")
ht_list = rowAnnotation(text = anno_text(label, location = unit(1, "npc"), just = "right", 
    gp = gpar(fontsize = 12)))

ht_list = ht_list + Heatmap(mean_meth, name = "mean_meth", col = meth_col_fun, 
    cluster_rows = FALSE, row_title = NULL, cluster_columns = FALSE, show_row_names = FALSE,
    heatmap_legend_param = list(title = "Methylation"), width = ncol(mean_meth)*unit(4, "mm")) +
rowAnnotation("n_gr" = anno_barplot(n_gr, bar_width = 1, width = anno_width), 
    show_annotation_name = FALSE) +
rowAnnotation("n_corr" = anno_barplot(n_corr, bar_width = 1, gp = gpar(fill = corr_col), 
    width = anno_width), show_annotation_name = FALSE) +
rowAnnotation("dist_tss" = anno_barplot(dist_tss, bar_width = 1, gp = gpar(fill = dist_tss_col), 
    width = anno_width), show_annotation_name = FALSE) +
rowAnnotation("gene_anno" = anno_barplot(gene_anno, bar_width = 1, gp = gpar(fill = gene_anno_col), 
    width = anno_width), show_annotation_name = FALSE) +
rowAnnotation("cgi_anno" = anno_barplot(cgi_anno, bar_width = 1, gp = gpar(fill = cgi_anno_col), 
    width = anno_width), show_annotation_name = FALSE) +
Heatmap(mat_enrich_gf, name = "enrich_gf", col = z_score_col_fun, cluster_columns = FALSE,
    width = unit(ncol(mat_enrich_gf)*4, "mm"), column_title = "",
    heatmap_legend_param = list(title = "Z-score")) +
rowAnnotation("pct_st" = anno_barplot(mat_pct_st, bar_width = 1, gp = gpar(fill = state_col), 
    width = anno_width), show_annotation_name = FALSE) +
Heatmap(mat_enrich_st, name = "enrich_st", col = z_score_col_fun, cluster_columns = FALSE, 
    width = unit(ncol(mat_enrich_st)*6, "mm"), column_title = "", show_heatmap_legend = FALSE,
    column_names_gp = gpar(col = state_col), show_row_names = FALSE)

由于注释条形图不生成图例,我们使用Legend()函数手动构建这些图例。

lgd_list = list(
    Legend(labels = c("gene", "intergenic"), title = "Gene annotation", 
        legend_gp = gpar(fill = gene_anno_col)),
    Legend(labels = c("<1kb", "1kb~5kb", "5kb~10kb", ">10kb"), title = "Distance to TSS", 
        legend_gp = gpar(fill = dist_tss_col)),
    Legend(labels = c("CGI", "CGI shore"), title = "CGI annotation", 
        legend_gp = gpar(fill = cgi_anno_col)),
    Legend(labels = colnames(mat_enrich_st), title = "Chromatin states", 
        legend_gp = gpar(fill = state_col))
)

在绘制热图列表时,所有热图和注释的行被分为两大组。注意在Heatmap()对应于平均甲基化矩阵的第一个中,我们设置 row_title = NULL删除来自行拆分的行标题。

由于稍后我们将为注释添加标题,因此我们通过padding参数在整个绘图区域的顶部分配空白。此外,我们将自定义图例列表连接到热图图例列表,并将它们水平放置在热图列表的底部。

draw(ht_list, padding = unit(c(2, 2, 20, 2), "mm"), row_split = gsub("\\d+$", "", label), 
    heatmap_legend_list = lgd_list, heatmap_legend_side = "bottom")
anno_title = c("n_gr" = "Number of\nDMRs", "n_corr" = "Significantly\ncorrelated genes",
    "gene_anno" = "Gene annotation", "dist_tss" = "Distance to TSS",
    "cgi_anno" = "CGI annotation", "pct_st" = "Overlap to\nChromatin states")
for(an in names(anno_title)) {
    decorate_annotation(an, {
        grid.text(anno_title[an], y = unit(1, "npc") + unit(3, "mm"), just = "bottom")
    })
}
ht_title = c("mean_meth" = "Mean\nmethylation", "enrich_gf" = "Enrichment to\ngenomic features",
    "enrich_st" = "Enrichment to\nchromatin states")
for(an in names(ht_title)) {
    decorate_heatmap_body(an, {
        grid.text(ht_title[an], y = unit(1, "npc") + unit(3, "mm"), just = "bottom")
    })
}
image

同样,多个统计量也可以垂直排列。在以下示例中,我们将来自四个子组的 40 个样本中的基因组区域列表的多个统计数据可视化。统计数据如下:

  • prop: 基因组中的比例。
  • median_length:每个样本中区域的中位数长度。
  • group: 子组标签。
prop = c(
    runif(10, min = 0.1, max = 0.5),
    runif(10, min = 0.2, max = 0.4),
    runif(10, min = 0.3, max = 0.6),
    runif(10, min = 0.4, max = 0.8)
)
median_length = c(
    runif(10, min = 5000, max = 10000),
    runif(10, min = 6000, max = 20000),
    runif(10, min = 7000, max = 15000),
    runif(10, min = 6000, max = 30000)
)
group = rep(letters[1:4], each = 10)

请注意,在以下示例中,列表中没有热图。

ht_list = HeatmapAnnotation(prop = anno_barplot(prop, height = unit(4, "cm"),
        axis_param = list(at = c(0, 0.2, 0.4, 0.6, 0.8), 
            labels = c("0%", "20%", "40%", "60%", "80%"))),
    annotation_name_rot = 90) %v%
HeatmapAnnotation(median_length = anno_barplot(median_length, height = unit(4, "cm"),
        axis_param = list(at = c(0, 10000, 20000), labels = c("0kb", "10kb", "20kb"))),
    annotation_name_rot = 90) %v%
HeatmapAnnotation(group = group)
draw(ht_list, column_title = "Statistics for a list of genomic regions")
image

对于多个注释的串联,也可以将单个注释放入一个 HeatmapAnnotation(). 例如,之前的代码与以下代码几乎完全相同:

# code only for demonstration
HeatmapAnnotation(
    prop = anno_barplot(prop, height = unit(4, "cm"),
        axis_param = list(at = c(0, 0.2, 0.4, 0.6, 0.8), 
            labels = c("0%", "20%", "40%", "60%", "80%"))),
    median_length = anno_barplot(median_length, height = unit(4, "cm"),
        axis_param = list(at = c(0, 10000, 20000), labels = c("0kb", "10kb", "20kb"))),
    group = group,
    annotation_name_rot = c(90, 90, 0),
    gap = unit(2, "mm")
) %v% NULL # add NULL to convert single HeatmapAnnotation to HeatmapList

三维热图

参考链接

1.motivation

ComplexHeatmap具有densityHeatmap()可视化密度分布列表,例如在以下示例中:

library(ComplexHeatmap)
set.seed(123)
mat = matrix(rnorm(500), ncol = 10)
colnames(mat) = letters[1:10]
densityHeatmap(mat)
image

在基本的 R 图形中,由于分布也可以通过直方图进行可视化,因此从ComplexHeatmap 版本 2.7.9 开始,添加了一个新函数frequencyHeatmap(),类似于密度热图的直方图版本。用法类似于densityHeatmap()

frequencyHeatmap(mat)
image

在前面的示例中,频率矩阵被可视化为热图。注意:frequencyHeatmap()可以使用不同的统计,"count""proportion""density"

由于频率热图声称是密度热图的直方图版本,但它看起来根本不像直方图。也许带有 3D 条的 3D 热图更合适。这可以在frequencyHeatmap()使用use_3d = TRUE.

frequencyHeatmap(mat, use_3d = TRUE)
image

接下来,将解释 3D 热图是如何实现的。

2. 3D热图的实现

首先,需要绘制 3D 条。这可以通过新函数来完成bar3D()。用法如下:

bar3D(x = 0.5, y = 0.5, w = 0.2, h = 0.2, l = unit(1, "cm"), theta = 60)
image

论据是:

  • x:底面中心点的x坐标。值应该是一个unit对象。如果是数字,则默认单位为npc
  • y:底面中心点的y坐标。
  • w:条的宽度(在 x 方向)。请参见下图。
  • h:条的高度(在 y 方向)。请参见下图。
  • l:钢筋的长度(在 z 方向)。请参见下图。
  • theta:投影的角度。请参见下图。注意theta只能取 0 到 90 之间的值。
image

为了增强 3D 可视化的视觉效果,可以通过fill参数设置颜色。

bar3D(x = seq(0.2, 0.8, length = 4), y = 0.5, w = unit(5, "mm"), h = unit(5, "mm"), 
    l = unit(1, "cm"), fill = c("red", "green", "blue", "purple"))
image

theta参数设置投影的角度,theta只能取 0 到 90 之间的值。

bar3D(x = seq(0.2, 0.8, length = 4), y = 0.5, w = unit(5, "mm"), h = unit(5, "mm"), 
    l = unit(1, "cm"), theta = c(20, 40, 60, 80))
image

要将条形添加到热图的每个单元,我们可以简单地在将每个条形bar3D()添加到每个单元格的位置cell_funlayer_fun位置中实现。通过 Heatmap3D()可以简化这一操作。Heatmap3D()接受几乎所有的参数,Heatmap()唯一的区别是每个单元格都有一个 3D 条,其高度对应于它的值。

Heatmap3D()只允许非负矩阵作为输入。默认值也是一些参数的更改,例如行名称放在热图的左侧,仍然应用聚类,但默认情况下不绘制树状图。

以下是使用的演示Heatmap3D()

set.seed(7)
mat = matrix(runif(100), 10)
rownames(mat) = LETTERS[1:10]
colnames(mat) = letters[1:10]
Heatmap3D(mat, name = "mat", column_title = "This is a 3D heatmap")
image

在前面的例子中,如果靠近热图顶部或热图右侧的条形长度过大,它们将与热图标题或图例重叠,在这种情况下,我们需要手动调整它们之间的间距,例如,标题和主体热图。

ComplexHeatmap 中,有几个全局选项可以控制热图组件之间的空间。为了解决前面例子中的问题,我们可以手动为ht_opt$HEATMAP_LEGEND_PADDINGht_opt$TITLE_PADDING设置一个合适的值。

ht_opt$HEATMAP_LEGEND_PADDING = unit(5, "mm")
ht_opt$TITLE_PADDING = unit(c(9, 2), "mm") # bottom and top padding
Heatmap3D(mat, name = "mat", column_title = "This is a 3D heatmap")
image

通过ht_opt(RESET = TRUE)以下方式重置全局选项:

ht_opt(RESET = TRUE)

接下来,我将演示另一个应用于众所周知的麻疹疫苗数据集的示例。首先,我展示了“普通 2D 热图”。可以在此处找到用于生成热图的代码。

image

要将其更改为 3D 可视化,只需替换Heatmap()Heatmap3D()并且大多数原始参数Heatmap()仍然可以放在那里。为简单起见,在 3D 热图中,我删除了顶部注释和右侧注释。

mat = readRDS(system.file("extdata", "measles.rds", package = "ComplexHeatmap"))
year_text = as.numeric(colnames(mat))
year_text[year_text %% 10 != 0] = ""
ha_column = HeatmapAnnotation(
    year = anno_text(year_text, rot = 0, location = unit(1, "npc"), just = "top")
)
col_fun = circlize::colorRamp2(c(0, 800, 1000, 127000), c("white", "cornflowerblue", "yellow", "red"))
ht_opt$TITLE_PADDING = unit(c(15, 2), "mm")
Heatmap3D(mat, name = "cases", col = col_fun,
    cluster_columns = FALSE, show_row_dend = FALSE, 
    show_column_names = FALSE,
    row_names_side = "left", row_names_gp = gpar(fontsize = 8),
    column_title = 'Measles cases in US states 1930-2001\nVaccine introduced 1961',
    bottom_annotation = ha_column,
    heatmap_legend_param = list(at = c(0, 5e4, 1e5, 1.5e5), 
        labels = c("0", "50k", "100k", "150k")),
    # new arguments for Heatmap3D()
    bar_rel_width = 1, bar_rel_height = 1, bar_max_length = unit(2, "cm")
)
image

顺便说一下,还可以通过包InteractiveComplexHeatmap将静态 3D 热图转换为交互式 Shiny 应用程序。见下图:

image

Heatmap3D()可以做很多与Heatmap()相同的事情,例如添加注释、拆分热图或通过+/%v%连接更多热图。但由于 3D 可视化通常不是一个好主意,而且它实际上不会为您提供比 2D 可视化更多的信息,因此,如果您想使用Heatmap3D(),您最好保持它尽可能简单。另外,请将其应用于小矩阵,大矩阵需要很长时间才能生成。

基因组级热图

参考链接

许多人对制作具有多个轨迹的基因组规模热图比较感兴趣,例如此处 和 此处的示例。在本章中,我将演示如何使用ComplexHeatmap实现它 。

为了制作基因组规模图,我们首先需要染色体水平的范围。有很多方法可以获取这些信息。在下面,我使用 circlize::read.chromInfo()函数。

library(circlize)
library(GenomicRanges)
chr_df = read.chromInfo()$df
chr_df = chr_df[chr_df$chr %in% paste0("chr", 1:22), ]
chr_gr = GRanges(seqnames = chr_df[, 1], ranges = IRanges(chr_df[, 2] + 1, chr_df[, 3]))
chr_gr
## GRanges object with 22 ranges and 0 metadata columns:
##        seqnames      ranges strand
##                
##    [1]     chr1 1-249250621      *
##    [2]     chr2 1-243199373      *
##    [3]     chr3 1-198022430      *
##    [4]     chr4 1-191154276      *
##    [5]     chr5 1-180915260      *
##    ...      ...         ...    ...
##   [18]    chr18  1-78077248      *
##   [19]    chr19  1-59128983      *
##   [20]    chr20  1-63025520      *
##   [21]    chr21  1-48129895      *
##   [22]    chr22  1-51304566      *
##   -------
##   seqinfo: 22 sequences from an unspecified genome; no seqlengths

在最终的热图中,每一行(如果基因组方向是垂直的)或每一列(如果基因组方向是水平的)实际上代表一个基因组窗口,因此我们需要用等宽窗口分割基因组。这里我使用 EnrichedHeatmap::makeWindows()函数将基因组分割为 1MB 窗口(这里的两个元列chr_window可以忽略)。

library(EnrichedHeatmap)
chr_window = makeWindows(chr_gr, w = 1e6)
chr_window
## GRanges object with 2875 ranges and 2 metadata columns:
##          seqnames            ranges strand |  .i_query .i_window
##                         |  
##      [1]     chr1         1-1000000      * |         1         1
##      [2]     chr1   1000001-2000000      * |         1         2
##      [3]     chr1   2000001-3000000      * |         1         3
##      [4]     chr1   3000001-4000000      * |         1         4
##      [5]     chr1   4000001-5000000      * |         1         5
##      ...      ...               ...    ... .       ...       ...
##   [2871]    chr22 46000001-47000000      * |        22        47
##   [2872]    chr22 47000001-48000000      * |        22        48
##   [2873]    chr22 48000001-49000000      * |        22        49
##   [2874]    chr22 49000001-50000000      * |        22        50
##   [2875]    chr22 50000001-51000000      * |        22        51
##   -------
##   seqinfo: 22 sequences from an unspecified genome; no seqlengths

为了将基因组尺度信号可视化为热图以及其他轨迹,现在的任务是通过重叠基因组窗口和基因组信号来计算 1MB 窗口中的平均信号。这里我实现了一个功能 average_in_window()。这个函数改编自HilbertCurve 包,因为那里有类似的任务。

average_in_window = function(window, gr, v, method = "weighted", empty_v = NA) {

    if(missing(v)) v = rep(1, length(gr))
    if(is.null(v)) v = rep(1, length(gr))
    if(is.atomic(v) && is.vector(v)) v = cbind(v)

    v = as.matrix(v)
    if(is.character(v) && ncol(v) > 1) {
        stop("`v` can only be a character vector.")
    }

    if(length(empty_v) == 1) {
        empty_v = rep(empty_v, ncol(v))
    }

    u = matrix(rep(empty_v, each = length(window)), nrow = length(window), ncol = ncol(v))

    mtch = as.matrix(findOverlaps(window, gr))
    intersect = pintersect(window[mtch[,1]], gr[mtch[,2]])
    w = width(intersect)
    v = v[mtch[,2], , drop = FALSE]
    n = nrow(v)

    ind_list = split(seq_len(n), mtch[, 1])
    window_index = as.numeric(names(ind_list))
    window_w = width(window)

    if(is.character(v)) {
        for(i in seq_along(ind_list)) {
            ind = ind_list[[i]]
            if(is.function(method)) {
                u[window_index[i], ] = method(v[ind], w[ind], window_w[i])
            } else {
                tb = tapply(w[ind], v[ind], sum)
                u[window_index[i], ] = names(tb[which.max(tb)])
            }
        }
    } else {
        if(method == "w0") {
            gr2 = reduce(gr, min.gapwidth = 0)
            mtch2 = as.matrix(findOverlaps(window, gr2))
            intersect2 = pintersect(window[mtch2[, 1]], gr2[mtch2[, 2]])

            width_intersect = tapply(width(intersect2), mtch2[, 1], sum)
            ind = unique(mtch2[, 1])
            width_setdiff = width(window[ind]) - width_intersect

            w2 = width(window[ind])

            for(i in seq_along(ind_list)) {
                ind = ind_list[[i]]
                x = colSums(v[ind, , drop = FALSE]*w[ind])/sum(w[ind])
                u[window_index[i], ] = (x*width_intersect[i] + empty_v*width_setdiff[i])/w2[i]
            }

        } else if(method == "absolute") {
            for(i in seq_along(ind_list)) {
                u[window_index[i], ] = colMeans(v[ind_list[[i]], , drop = FALSE])
            }

        } else if(method == "weighted") {
            for(i in seq_along(ind_list)) {
                ind = ind_list[[i]]
                u[window_index[i], ] = colSums(v[ind, , drop = FALSE]*w[ind])/sum(w[ind])
            }
        } else {
            if(is.function(method)) {
                for(i in seq_along(ind_list)) {
                    ind = ind_list[[i]]
                    u[window_index[i], ] = method(v[ind], w[ind], window_w[i])
                }
            } else {
                stop("wrong method.")
            }
        }
    }

    return(u)
}

average_in_window()函数中,有以下参数:

  • windowGRanges基因组窗口的对象。
  • grGRanges基因组信号的对象。
  • v: 向量或矩阵。这是与gr关联的值,它的长度应与grnrow相同。v可以是数字或字符。如果是missingNULL,则将 值 1 分配给gr中的每个区域。如果v是数字,则可以是向量或矩阵,如果v是字符,则只能是向量。
  • method:总结每个基因组窗口信号的方法。
  • empty_v: 如果没有区域gr与其重叠,则为窗口的默认值。

该函数返回一个与window具有相同行长和顺序的矩阵。

重叠模型如下图所示。底部的红线代表某个基因组窗口。顶部的黑线是与窗口重叠的基因组信号区域。粗线表示信号区域和窗口之间的相交部分。

image

对于一个给定的窗口,n是与窗口重叠的信号区域的数量(上图中为5),wi是相交段的宽度(黑色粗线),xi是与原始区域相关联的信号值。
使用函数average_in_window(),我可以将基因组信号转换为基于窗口的矩阵。在以下示例中,我生成了大约 1000 个随机基因组区域,其中包含 10 列随机值(以模拟 10 个样本)。

bed1 = generateRandomBed(nr = 1000, nc = 10) # generateRandomBed() is from circlize package
# convert to a GRanes object
gr1 = GRanges(seqnames = bed1[, 1], ranges = IRanges(bed1[, 2], bed1[, 3]))

num_mat = average_in_window(chr_window, gr1, bed1[, -(1:3)])
dim(num_mat)
## [1] 2875   10
head(num_mat)
##            [,1]       [,2]      [,3]       [,4]       [,5]        [,6]
## [1,] 0.17092940 -0.4323175 0.5814975  0.5419019 -1.3986643 -0.73240405
## [2,] 0.17092940 -0.4323175 0.5814975  0.5419019 -1.3986643 -0.73240405
## [3,] 0.17092940 -0.4323175 0.5814975  0.5419019 -1.3986643 -0.73240405
## [4,] 0.17092940 -0.4323175 0.5814975  0.5419019 -1.3986643 -0.73240405
## [5,] 0.17092940 -0.4323175 0.5814975  0.5419019 -1.3986643 -0.73240405
## [6,] 0.06902516 -0.6065132 0.5130708 -0.0876663  0.4215547 -0.08663985
##            [,7]        [,8]       [,9]      [,10]
## [1,]  0.8572341  0.04271758 -0.6805558  1.1822941
## [2,]  0.8572341  0.04271758 -0.6805558  1.1822941
## [3,]  0.8572341  0.04271758 -0.6805558  1.1822941
## [4,]  0.8572341  0.04271758 -0.6805558  1.1822941
## [5,]  0.8572341  0.04271758 -0.6805558  1.1822941
## [6,] -1.0614186 -0.10839748  0.3643813 -0.2047742

前五个基因组窗口没有关联的值,因为没有gr1与它们重叠的区域 ,因此,empty_v默认情况下它们取自的值NA

要可视化的第二个数据是具有特征信号的 10 个基因组区域列表(假设它们是来自 10 个样本的拷贝数变异结果)。在每个随机区域,我还从它们中抽取了 20 个样本,只是为了使它们在基因组中变得稀疏。

bed_list = lapply(1:10, function(i) {
    generateRandomBed(nr = 1000, nc = 1, 
        fun = function(n) sample(c("gain", "loss"), n, replace = TRUE))
})
char_mat = NULL
for(i in 1:10) {
    bed = bed_list[[i]]
    bed = bed[sample(nrow(bed), 20), , drop = FALSE]
    gr_cnv = GRanges(seqnames = bed[, 1], ranges = IRanges(bed[, 2], bed[, 3]))

    char_mat = cbind(char_mat, average_in_window(chr_window, gr_cnv, bed[, 4]))
}

要可视化的第三个数据只是具有两个数字列的基因组区域,其中两列将可视化为点轨迹,第一列将可视化为条形图轨迹。

bed2 = generateRandomBed(nr = 100, nc = 2)
gr2 = GRanges(seqnames = bed2[, 1], ranges = IRanges(bed2[, 2], bed2[, 3]))

v = average_in_window(chr_window, gr2, bed2[, 4:5])

要可视化的第四个数据是我们要在图中标记的基因符号列表。gr3包含基因的基因组位置及其符号。该变量at包含相应窗口的行索引chr_windowlabels包含基因名称。如以下代码所示,我只是findOverlaps()将基因区域与基因组窗口关联起来。

bed3 = generateRandomBed(nr = 40, nc = 0)
gr3 = GRanges(seqnames = bed3[, 1], ranges = IRanges(bed3[, 2], bed3[, 2]))
gr3$gene = paste0("gene_", 1:length(gr3))

mtch = as.matrix(findOverlaps(chr_window, gr3))
at = mtch[, 1]
labels = mcols(gr3)[mtch[, 2], 1]

现在拥有了所有变量并准备好制作热图。在此之前,为了更好地控制热图,我设置chr了一个因子来控制最终图中染色体的顺序,并创建一个变量subgroup来模拟矩阵中两个子组的 10 列。

chr = as.vector(seqnames(chr_window))
chr_level = paste0("chr", 1:22)
chr = factor(chr, levels = chr_level)

subgroup = rep(c("A", "B"), each = 5)

以下代码使热图带有附加轨道。该图是两个热图和三行注释的组合。不要被大量的争论吓到。

library(ComplexHeatmap)
ht_opt$TITLE_PADDING = unit(c(4, 4), "points")
ht_list = Heatmap(num_mat, name = "mat", col = colorRamp2(c(-1, 0, 1), c("green", "white", "red")),
    row_split = chr, cluster_rows = FALSE, show_column_dend = FALSE,
    column_split = subgroup, cluster_column_slices = FALSE,
    column_title = "numeric matrix",
    top_annotation = HeatmapAnnotation(subgroup = subgroup, annotation_name_side = "left"),
    row_title_rot = 0, row_title_gp = gpar(fontsize = 10), border = TRUE,
    row_gap = unit(0, "points")) +
Heatmap(char_mat, name = "CNV", col = c("gain" = "red", "loss" = "blue"),
    border = TRUE, column_title = "character matrix") +
rowAnnotation(label = anno_mark(at = at, labels = labels)) +
rowAnnotation(pt = anno_points(v, gp = gpar(col = 4:5), pch = c(1, 16)), 
    width = unit(2, "cm")) +
rowAnnotation(bar = anno_barplot(v[, 1], gp = gpar(col = ifelse(v[ ,1] > 0, 2, 3))), 
    width = unit(2, "cm"))
draw(ht_list, merge_legend = TRUE)
image

很容易使热图的垂直排列(用于%v%连接热图!)。只需仔细切换行相关参数和列相关参数即可。

注意使用了一个技巧来排列染色体名称。由于小染色体的染色体名称会重叠,因此只需在相邻染色体名称之前或之后添加\n

ht_list = Heatmap(t(num_mat), name = "mat", col = colorRamp2(c(-1, 0, 1), c("green", "white", "red")),
    column_split = chr, cluster_columns = FALSE, show_row_dend = FALSE,
    row_split = subgroup, cluster_row_slices = FALSE,
    row_title = "numeric matrix",
    left_annotation = rowAnnotation(subgroup = subgroup, show_annotation_name = FALSE,
        annotation_legend_param = list(
            subgroup = list(direction = "horizontal", title_position = "lefttop", nrow = 1))),
    column_title_gp = gpar(fontsize = 10), border = TRUE,
    column_gap = unit(0, "points"),
    column_title = ifelse(1:22 %% 2 == 0, paste0("\n", chr_level), paste0(chr_level, "\n")),
    heatmap_legend_param = list(direction = "horizontal", title_position = "lefttop")) %v%
Heatmap(t(char_mat), name = "CNV", col = c("gain" = "red", "loss" = "blue"),
    border = TRUE, row_title = "character matrix",
    heatmap_legend_param = list(direction = "horizontal", title_position = "lefttop", nrow = 1)) %v%
HeatmapAnnotation(label = anno_mark(at = at, labels = labels, side = "bottom")) %v%
HeatmapAnnotation(pt = anno_points(v, gp = gpar(col = 4:5), pch = c(1, 16)),
    annotation_name_side = "left", height = unit(2, "cm")) %v%
HeatmapAnnotation(bar = anno_barplot(v[, 1], gp = gpar(col = ifelse(v[ ,1] > 0, 2, 3))), 
    annotation_name_side = "left", height = unit(2, "cm"))
draw(ht_list, heatmap_legend_side = "bottom", merge_legend = TRUE)
image

你可能感兴趣的:(ComplexHeatmap复杂热图绘制学习——10.其它高级图)