本文主要是对 ComplexHeatmap Complete Reference(last revised on 2020-04-29)内容的翻译及理解,并且根据理解修改了部分示例以缩短原文的内容,主要是为了记录学习 ComplexHeatmap 包的过程,方便日后翻阅。

ComplexHeatmap 不仅可以画单个的热图,也可以制作多个热图及注释信息相互组合起来的更为复杂的图形,所以有必要先了解作者的构图思路。
  下图是作者的构图布局图,中间红色部分是画热图的部分,单个或者多个热图都可以,四个边都有可以添加如下图四种信息的部分。

ComplexHeatmap-0.png

  按照原文章节安排,本文主要分为下面八个板块,其中略有删减,如若不懂可以翻看原文。
  ComplexHeatmap 安装代码如下,随便选择一种即可:

install.packages("ComplexHeatmap")
devtools::install_github("jokergoo/ComplexHeatmap")

1 A Single Heatmap

  本节主要介绍如何绘制单个热图,这也是绘制热图中需求最大的一部分,理解这部分就可以实现其他画热图R包(如 pheatmap 包)的绝大部分功能。

# 加载R包

rm(list = ls())
library(ComplexHeatmap)

# 准备数据

set.seed(123)
nr1 = 4; nr2 = 8; nr3 = 6; nr = nr1 + nr2 + nr3
nc1 = 6; nc2 = 8; nc3 = 10; nc = nc1 + nc2 + nc3
mat = cbind(rbind(matrix(rnorm(nr1*nc1, mean = 1,   sd = 0.5), nr = nr1),
                  matrix(rnorm(nr2*nc1, mean = 0,   sd = 0.5), nr = nr2),
                  matrix(rnorm(nr3*nc1, mean = 0,   sd = 0.5), nr = nr3)),
            rbind(matrix(rnorm(nr1*nc2, mean = 0,   sd = 0.5), nr = nr1),
                  matrix(rnorm(nr2*nc2, mean = 1,   sd = 0.5), nr = nr2),
                  matrix(rnorm(nr3*nc2, mean = 0,   sd = 0.5), nr = nr3)),
            rbind(matrix(rnorm(nr1*nc3, mean = 0.5, sd = 0.5), nr = nr1),
                  matrix(rnorm(nr2*nc3, mean = 0.5, sd = 0.5), nr = nr2),
                  matrix(rnorm(nr3*nc3, mean = 1,   sd = 0.5), nr = nr3))
            )
mat = mat[sample(nr, nr), sample(nc, nc)] # 随机打乱行和列

rownames(mat) = paste0("row", seq_len(nr))
colnames(mat) = paste0("column", seq_len(nc))

使用默认参数的代码及绘图结果如下:

Heatmap(mat)

ComplexHeatmap-1.1.png

这里插播一个批量出图的小技巧,可以在循环里面使用如下代码:

ht = Heatmap(mat)
draw(ht)

1.1 Colors

图的好看与否,配色占了相当一部分的比重。

col_fun = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red"))
Heatmap(mat, name = "mat", col = col_fun)

ComplexHeatmap-1.2.png

  上面代码利用 col 参数将默认的白红变成了绿白红,其中颜色映射的数值范围是正负 2 之间,超过此范围的值的颜色都将使用阈值所对应的颜色。下面代码将会验证这个说法,善于利用这种设置阈值颜色的手段,可以提高热图的对比度。

mat2 = mat
mat2[1, 1] = 100000 # 设置极端值

Heatmap(mat2, name = "mat", col = col_fun)
Heatmap(mat2, name = "mat", col = circlize::colorRamp2(c(-20, 0, 20), c("green", "white", "red")))

ComplexHeatmap-1.3.png

  上图仅消除了极端值对颜色的影响,并没有消除极端值对聚类的影响,这个问题在聚类的小节会有相关说明。
  除了上述利用 circlize::colorRamp2 来设置阈值所映射的颜色之外,也可以直接填入颜色向量集来改变颜色。

Heatmap(mat, name = "mat", col = rev(rainbow(10)))
Heatmap(mat, name = "mat", col = c('#7b3294','#c2a5cf','#f7f7f7','#a6dba0','#008837'))

ComplexHeatmap-1.4.png

  值得一提的是 ComplexHeatmap 支持矩阵中包含 NA 值,并且可以使用 na_col 来控制其颜色,下面代码将 NA 值的颜色设置为黑色。

mat_with_na = mat
na_index = sample(c(TRUE, FALSE), nrow(mat)*ncol(mat), replace = TRUE, prob = c(1, 9))
mat_with_na[na_index] = NA
Heatmap(mat_with_na, name = "mat", na_col = "black")

ComplexHeatmap-1.5.png

热图主体的边框及热图中每个格子的边框都是可以进行调整的。

# 热图主体的边框

Heatmap(mat, name = "mat", border = TRUE)

# 热图每个格子的边框 border

Heatmap(mat, name = "mat", rect_gp = gpar(col = "white", lwd = 3))

ComplexHeatmap-1.6.png

  最后比较一下不同色系之间的差异,有需求的用户可以在下面代码的基础上自己探索适合自己的色系,提供的色系有 RGB, HSV, HLS, LAB, XYZ, sRGBLUV

f1 = circlize::colorRamp2(seq(min(mat), max(mat), length = 3), c("blue", "#EEEEEE", "red"))
f2 = circlize::colorRamp2(seq(min(mat), max(mat), length = 3), c("blue", "#EEEEEE", "red"), 
                space = "RGB")
Heatmap(mat, name = "mat1", col = f1, column_title = "LAB color space") + # 默认

Heatmap(mat, name = "mat2", col = f2, column_title = "RGB color space")

ComplexHeatmap-1.7.png

1.2 Titles

  与标题相关的参数都是带有 title 的,主要有行标题和列标题,比较实用参数代码展示如下:

Heatmap(mat, name = "mat", 
        column_title = "I am a column title", # 列标题

        row_title = "I am a row title") + # 行标题

Heatmap(mat, name = "mat", column_title = "I am a column title at the bottom", 
        column_title_side = "bottom") + # 标题位置("left", "right","top", "bottom")

Heatmap(mat, name = "mat", column_title = "column title", column_title_rot = 90) # 旋转角度(0, 90, 270)

ComplexHeatmap-1.8.png

Heatmap(mat, name = "mat", column_title = "I am a big column title", 
        column_title_gp = gpar(fontsize = 20, # 标题大小

                               fontface = "bold")) + # 标题字体

Heatmap(mat, name = "mat", column_title = "I am a column title", 
        column_title_gp = gpar(fill = "green", # 标题背景色

                               col = "white", # 标题颜色

                               border = "black")) # 标题边框色

ComplexHeatmap-1.9.png

还可以设置分割后的热图的各组标题。

Heatmap(mat, name = "mat", row_km = 2, row_title = "cluster_%s", 
        row_title_gp = gpar(fontsize = 20,fontface = "bold"))

ComplexHeatmap-1.10.png

1.3 Clustering

  Clustering 分为两步首先需要计算距离,再进行聚类。这两步在 ComplexHeatmap 中提供有内置的方法,用户也可以传入自定义方法。

下面代码主要是一些图形控制方面的参数:

Heatmap(mat, name = "mat1", cluster_rows = FALSE) # 关闭行聚类

Heatmap(mat, name = "mat2", show_column_dend = FALSE) # 隐藏列树图

Heatmap(mat, name = "mat3", 
        row_dend_side = "right", # 行树图位置

        column_dend_side = "bottom") # 列树图位置

Heatmap(mat, name = "mat4", 
        column_dend_height = unit(1, "cm"), # 列树图高度 

        row_dend_width = unit(4, "cm")) # 行树图宽度

ComplexHeatmap-1.11.png

1.3.1 Distance methods

  使用 clustering_distance_rows/clustering_distance_column 来选择不同的距离计算方法或者传入自定义的方法,内置的计算距离方法有 euclidean, maximum, manhattan, canberra, binary, minkowski, pearson, spearmankendall,并且是允许出现** NA 值**的。

Heatmap(mat, name = "mat", clustering_distance_rows = "pearson",
        column_title = "pre-defined distance method (1 - pearson)")

# 可以自定义计算矩阵的距离,函数应该只包含一个参数

Heatmap(mat, name = "mat", clustering_distance_rows = function(m) dist(m),
        column_title = "a function that calculates distance matrix")

# 可以自定义计算向量的距离,函数应该包含两个参数(速度会减慢)

Heatmap(mat, name = "mat", clustering_distance_rows = function(x, y) 1 - cor(x, y),
        column_title = "a function that calculates pairwise distance")

ComplexHeatmap-1.12.png

  下面就来展示一下自定义的一些骚操作。前面看到了极端值对聚类的影响,我们可以在计算距离的时候去除这个影响

# 构建含有极端值的矩阵

mat_with_outliers = mat
for(i in  1:10) mat_with_outliers[i, i] = 1000

# 自定义的距离计算方法

robust_dist = function(x, y) {
  qx = quantile(x, c(0.1, 0.9))
  qy = quantile(y, c(0.1, 0.9))
  l = x > qx[1] & x < qx[2] & y > qy[1] & y < qy[2]
  x = x[l]
  y = y[l]
  sqrt(sum((x - y)^2))
}

# 利用 clustering_distance_* 传入自定义的距离计算方法 

Heatmap(mat_with_outliers, name = "mat", 
        col = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red")),
        clustering_distance_rows = robust_dist,
        clustering_distance_columns = robust_dist,
        column_title = "robust_dist")

# 使用默认方法

Heatmap(mat_with_outliers, name = "mat", 
        col = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red")),
        column_title = "dist")

ComplexHeatmap-1.13.png

提供合适的方法,字符串同样也可以聚类。

mat_letters = matrix(sample(letters[1:4], 100, replace = TRUE), 10)

# distance in the ASCII table

dist_letters = function(x, y) {
  x = strtoi(charToRaw(paste(x, collapse = "")), base = 16)
  y = strtoi(charToRaw(paste(y, collapse = "")), base = 16)
  sqrt(sum((x - y)^2))
}

Heatmap(mat_letters, name = "letters", col = structure(2:5, names = letters[1:4]),
        clustering_distance_rows = dist_letters, clustering_distance_columns = dist_letters,
        cell_fun = function(j, i, x, y, w, h, col) { # add text to each grid

          grid.text(mat_letters[i, j], x, y)
        })

ComplexHeatmap-1.14.png

1.3.2 Clustering methods

  使用 clustering_method_rows/clustering_method_column 来选择不同的聚类方法或者传入自定义的方法,内置的计算距离方法有 ward.D, ward.D2, single, complete 等。

Heatmap(mat, name = "mat", clustering_method_rows = "single")

ComplexHeatmap-1.15.png

下面展示了三种自定义方法传入的方式,效果是一样的:

library(cluster)
Heatmap(mat, name = "mat", 
        cluster_rows = diana(mat),
        cluster_columns = agnes(t(mat)), 
        column_title = "clustering objects")

# if cluster_columns is set as a function, you don't need to transpose the matrix

Heatmap(mat, name = "mat", 
        cluster_rows = diana,
        cluster_columns = agnes, 
        column_title = "clustering functions")

Heatmap(mat, name = "mat", 
        cluster_rows = function(m) as.dendrogram(diana(m)),
        cluster_columns = function(m) as.dendrogram(agnes(m)), 
        column_title = "clutering functions")

ComplexHeatmap-1.16.png

  在行列比较多的情况下,速度又成为了一个需求。我们就可以使用 fastcluster 来加速聚类,如下展示两种方式,其效果是一样的,自己运行一下看看就行了:

# 使用 fastcluster 加快聚类速度

fh = function(x) fastcluster::hclust(dist(x))
Heatmap(mat, name = "mat", cluster_rows = fh, cluster_columns = fh)

# 将fastcluster作为默认聚类方法

ht_opt$fast_hclust = TRUE # used in all heatmaps


group = kmeans(t(mat), centers = 3)$cluster
Heatmap(mat, name = "mat", cluster_columns = cluster_within_group(mat, group))

ht_opt(RESET = TRUE) # 重置为默认配置

1.3.3 Render dendrograms

树图同样也可以使用默认和传入已经构好的,展示如下:

library(dendextend)
row_dend = as.dendrogram(hclust(dist(mat)))
row_dend = color_branches(row_dend, k = 2) # `color_branches()` returns a dendrogram object

Heatmap(mat, name = "mat", cluster_rows = row_dend)

Heatmap(mat, name = "mat", cluster_rows = row_dend, row_dend_gp = gpar(col = "red")) # 树图颜色

ComplexHeatmap-1.17.png

1.3.4 Reorder dendrograms

  可以使用 row_dend_reorder 参数来对聚类后的结果进行排序,也可以使用 cluster_rows 在外面排序好之后再传入。

m2 = matrix(1:100, nr = 10, byrow = TRUE)
Heatmap(m2, name = "mat", row_dend_reorder = FALSE, column_title = "no reordering")
Heatmap(m2, name = "mat", row_dend_reorder = TRUE, column_title = "apply reordering")

# 使用 dendsort 再排序后传入

Heatmap(mat, name = "mat", column_title = "default reordering")
library(dendsort)
dend = dendsort(hclust(dist(mat)))
Heatmap(mat, name = "mat", cluster_rows = dend, column_title = "reorder by dendsort")

ComplexHeatmap-1.18.png

1.4 Set row and column orders

  当然聚类并不是必须的,也可以不聚类,使用自定义的顺序,只需在 row_order/column_order 中传入一个所需顺序的行列名的向量即可。

Heatmap(mat, name = "mat", 
        row_order = order(as.numeric(gsub("row", "", rownames(mat)))), 
        column_order = order(as.numeric(gsub("column", "", colnames(mat)))))

Heatmap(mat, name = "mat", 
        row_order = sort(rownames(mat)), 
        column_order = sort(colnames(mat)))

ComplexHeatmap-1.19.png

1.5 Dimension names

下面是名称相关设置的一些参数的说明。

Heatmap(mat, name = "mat1", 
        row_names_side = "left", column_names_side = "top", # 行/列名位置

        row_dend_side = "right", column_dend_side = "bottom") # 行/列树图位置


Heatmap(mat, name = "mat2", show_row_names = FALSE) # 不显示行名

Heatmap(mat, name = "mat3", row_names_gp = gpar(fontsize = 20, # 行名大小

                                               col = c(rep("red", 10), rep("blue", 8)))) # 行名颜色


Heatmap(mat, name = "mat4", 
        row_names_centered = TRUE, # 行名居中

        column_names_centered = TRUE) # 列名居中


Heatmap(mat, name = "mat5", 
        column_names_rot = 45, #列名旋转角度 

        column_names_side = "top", #列名位置

        column_dend_side = "bottom") #列树图位置

ComplexHeatmap-1.20.png

如果名称太长可以使用 row_names_max_width 来显示过长的名字。

mat2 = mat
rownames(mat2)[1] = paste(c(letters, LETTERS), collapse = "")
Heatmap(mat2, name = "mat")
Heatmap(mat2, name = "mat", 
        row_names_max_width = max_text_width(
          rownames(mat2), 
          gp = gpar(fontsize = 12)
        ))

ComplexHeatmap-1.21.png

  上面右图虽然过长的名字显示了,但是热图基本看不见了,这是由于存图时候的宽度过小,保存图片的时候宽度给足就可以了。

  可以使用 row_labels/column_labels 修改行/列名,并且支持数学表达式。

row_labels = structure(paste0(letters[1:24], 1:24), names = paste0("row", 1:24))
column_labels = structure(paste0(LETTERS[1:24], 1:24), names = paste0("column", 1:24))
Heatmap(mat, name = "mat", 
        row_labels = row_labels[rownames(mat)], 
        column_labels = column_labels[colnames(mat)])

Heatmap(mat, name = "mat", 
        row_labels = expression(alpha, beta, gamma, delta, epsilon,
                                zeta, eta, theta, iota, kappa, lambda,
                                mu, nu, xi, omicron, pi, rho, sigma))

ComplexHeatmap-1.22.png

1.6 Heatmap split

  可以用来分割热图的参数有 row_km, row_split, column_kmcolumn_split,下面会一一说明,注意理解示例即可。

1.6.1 Split by k-means clustering

Heatmap(mat, name = "mat", 
        row_km = 2, # 行按照km分割

        column_km = 3) # 列按照km分割

ComplexHeatmap-1.23.png

1.6.2 Split by categorical variables

# split by a vector

Heatmap(mat, name = "mat", 
        row_split = rep(c("A", "B"), 9), 
        column_split = rep(c("C", "D"), 12))

# split by a data frame

Heatmap(mat, name = "mat", 
        row_split = data.frame(rep(c("A", "B"), 9), 
                               rep(c("C", "D"), each = 9)))

# split on both dimensions

Heatmap(mat, name = "mat", 
        row_split = factor(rep(c("A", "B"), 9)),
        column_split = factor(rep(c("C", "D"), 12)))

ComplexHeatmap-1.24.png

Heatmap(mat, name = "mat1", 
        row_split = rep(c("A", "B"), 9), 
        row_km = 2)

# 本质是split by a data frame

cl = kmeans(mat, centers = 2)$cluster
Heatmap(mat, name = "mat2", row_split = cbind(cl, rep(c("A", "B"), 9)))

# 本质是split by a vector

pa = cluster::pam(mat, k = 3)
Heatmap(mat, name = "mat3", row_split = paste0("pam", pa$clustering))

# remember when `row_order` is set, row clustering is turned off

Heatmap(mat, name = "mat4", row_order = 18:1, row_km = 2)


# Character matrix can only be split by row_split/column_split argument.

# split by the first column in `discrete_mat`

discrete_mat = matrix(sample(letters[1:4], 100, replace = TRUE), 10, 10)
Heatmap(discrete_mat, name = "mat5", col = 1:4, row_split = discrete_mat[, 1])

# 去除分割标记的虚线 show_parent_dend_line

Heatmap(mat, name = "mat6", row_km = 2, column_km = 3, show_parent_dend_line = FALSE)

ComplexHeatmap-1.25.png

1.6.3 Split by dendrogram

Heatmap(mat, name = "mat1", row_split = 2, column_split = 3)

dend = hclust(dist(mat))
dend = dendextend::color_branches(dend, k = 2)
Heatmap(mat, name = "mat2", cluster_rows = dend, row_split = 2)

split = data.frame(cutree(hclust(dist(mat)), k = 2), rep(c("A", "B"), 9))
Heatmap(mat, name = "mat3", row_split = split, show_parent_dend_line = FALSE)

ComplexHeatmap-1.26.png

1.6.4 Order of slices

Heatmap(mat, name = "mat1", 
        row_split = rep(LETTERS[1:3], 6),
        column_split = rep(letters[1:6], 4))

# clustering is similar as previous heatmap with branches in some nodes in the dendrogram flipped

Heatmap(mat, name = "mat2", 
        row_split = factor(rep(LETTERS[1:3], 6), levels = LETTERS[3:1]),
        column_split = factor(rep(letters[1:6], 4), levels = letters[6:1]))

# 去除树图中分割标记的虚线以上的部分 cluster_row_slices/cluster_column_slices

# now the order is exactly what we set

Heatmap(mat, name = "mat", 
        row_split = factor(rep(LETTERS[1:3], 6), levels = LETTERS[3:1]),
        column_split = factor(rep(letters[1:6], 4), levels = letters[6:1]),
        cluster_row_slices = FALSE, 
        cluster_column_slices = FALSE)

ComplexHeatmap-1.27.png

1.6.5 Titles for splitting

split = data.frame(rep(c("A", "B"), 9), rep(c("C", "D"), each = 9))
Heatmap(mat, name = "mat1", row_split = split, row_title = "%s|%s")
Heatmap(mat, name = "mat2", row_split = split, row_title = "%s\n%s")
Heatmap(mat, name = "mat3", row_split = 2, row_title = "cluster_%s")

Heatmap(mat, name = "mat4", row_split = split, row_title = NULL)
Heatmap(mat, name = "mat5", row_split = split, row_title = "there are four slices")
ht = Heatmap(mat, name = "mat6", row_split = split, row_title = "%s|%s")
draw(ht, row_title = "I am a row title")

ComplexHeatmap-1.28.png

1.6.6 Graphic parameters for splitting

Heatmap(mat, name = "mat", 
        row_km = 2, row_title_gp = gpar(col = c("red", "blue"), font = 1:2),
        row_names_gp = gpar(col = c("green", "orange"), fontsize = c(10, 14)),
        column_km = 3, column_title_gp = gpar(fill = c("red", "blue", "green"), font = 1:3),
        column_names_gp = gpar(col = c("green", "orange", "purple"), fontsize = c(10, 14, 8)))

ComplexHeatmap-1.29.png

1.6.7 Gaps between slices

Heatmap(mat, name = "mat1", row_km = 3, row_gap = unit(5, "mm"))
Heatmap(mat, name = "mat2", row_km = 3, row_gap = unit(c(2, 4), "mm"))

ComplexHeatmap-1.30.png

这里需要注意一下,分割后热图的边框就会改变。

Heatmap(mat, name = "mat1", row_km = 2, column_km = 3, border = TRUE)
Heatmap(mat, name = "mat2", row_km = 2, column_km = 3, 
        row_gap = unit(0, "mm"), column_gap = unit(0, "mm"), border = TRUE)

ComplexHeatmap-1.31.png

1.6.8 Split heatmap annotations

分割后注释也会随之分割。

Heatmap(mat, name = "mat", row_km = 2, column_km = 3,
        top_annotation = HeatmapAnnotation(foo1 = 1:24, bar1 = anno_points(runif(24))),
        right_annotation = rowAnnotation(foo2 = 18:1, bar2 = anno_barplot(runif(18)))
        )

ComplexHeatmap-1.32.png

1.7 Heatmap as raster image

这里主要是比较不同质量参数保存图片后的文件大小。

Heatmap(mat, use_raster = TRUE, raster_quality = 2)

set.seed(123)
mat2 = matrix(rnorm(10000*100), ncol = 100)
pdf("heatmap.pdf", width = 8, height = 8)
Heatmap(mat2, cluster_rows = FALSE, cluster_columns = FALSE, use_raster = FALSE)
dev.off()

pdf("heatmap_raster_by_png.pdf", width = 8, height = 8)
Heatmap(mat2, cluster_rows = FALSE, cluster_columns = FALSE, use_raster = TRUE, 
        raster_device = "png")
dev.off()

pdf("heatmap_raster_by_jpeg.pdf", width = 8, height = 8)
Heatmap(mat2, cluster_rows = FALSE, cluster_columns = FALSE, use_raster = TRUE, 
        raster_device = "jpeg")
dev.off()

pdf("heatmap_raster_by_tiff.pdf", width = 8, height = 8)
Heatmap(mat2, cluster_rows = FALSE, cluster_columns = FALSE, use_raster = TRUE, 
        raster_device = "tiff")
dev.off()

pdf("heatmap_raster_by_CairoPNG.pdf", width = 8, height = 8)
Heatmap(mat2, cluster_rows = FALSE, cluster_columns = FALSE, use_raster = TRUE, 
        raster_device = "CairoPNG")
dev.off()

pdf("heatmap_raster_by_CairoJPEG.pdf", width = 8, height = 8)
Heatmap(mat2, cluster_rows = FALSE, cluster_columns = FALSE, use_raster = TRUE, 
        raster_device = "CairoJPEG")
dev.off

all_files = c("heatmap.pdf", "heatmap_raster_by_png.pdf", 
              "heatmap_raster_by_jpeg.pdf", "heatmap_raster_by_tiff.pdf",
              "heatmap_raster_by_CairoPNG.pdf", "heatmap_raster_by_CairoJPEG.pdf")
fs = file.size(all_files)
names(fs) = all_files
sapply(fs, function(x) paste(round(x/1024), "KB"))

1.8 Customize the heatmap body

1.8.1 cell_fun

 cell_fun draws in each cell repeatedly, with 7 arguments.

  • j: column index in the matrix. Column index corresponds to the x-direction in the viewport, that’s why j is put as the first argument.
  • i: row index in the matrix.
  • x: x coordinate of middle point of the cell which is measured in the viewport of the heatmap body.
  • y: y coordinate of middle point of the cell which is measured in the viewport of the heatmap body.
  • width: width of the cell. The value is unit(1/ncol(sub_mat), “npc”) where sub_mat correspond to the sub-matrix by row splitting and column splitting.
  • height: height of the cell. The value is unit(1/nrow(sub_mat), “npc”).
  • fill: color of the cell.
small_mat = mat[1:9, 1:9]
col_fun = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red"))
Heatmap(small_mat, name = "mat1", col = col_fun,
        cell_fun = function(j, i, x, y, width, height, fill) {
          grid.text(sprintf("%.1f", small_mat[i, j]), x, y, gp = gpar(fontsize = 10))
        })

Heatmap(small_mat, name = "mat2",  col = col_fun,
        cell_fun = function(j, i, x, y, width, height, fill) {
          if(small_mat[i, j] > 0)
            grid.text(sprintf("%.1f", small_mat[i, j]), x, y, gp = gpar(fontsize = 10))
        })

Heatmap(small_mat, name = "mat3", col = col_fun,
        row_km = 2, column_km = 2,
        cell_fun = function(j, i, x, y, width, height, fill) {
          grid.text(sprintf("%.1f", small_mat[i, j]), x, y, gp = gpar(fontsize = 10))
        })

ComplexHeatmap-1.33.png

cor_mat = cor(small_mat)
od = hclust(dist(cor_mat))$order
cor_mat = cor_mat[od, od]
nm = rownames(cor_mat)
col_fun = circlize::colorRamp2(c(-1, 0, 1), c("green", "white", "red"))
# `col = col_fun` here is used to generate the legend

Heatmap(cor_mat, name = "correlation", col = col_fun, rect_gp = gpar(type = "none"), 
        cell_fun = function(j, i, x, y, width, height, fill) {
          grid.rect(x = x, y = y, width = width, height = height, 
                    gp = gpar(col = "grey", fill = NA))
          if(i == j) {
            grid.text(nm[i], x = x, y = y)
          } else if(i > j) {
            grid.circle(x = x, y = y, r = abs(cor_mat[i, j])/2 * min(unit.c(width, height)), 
                        gp = gpar(fill = col_fun(cor_mat[i, j]), col = NA))
          } else {
            grid.text(sprintf("%.1f", cor_mat[i, j]), x, y, gp = gpar(fontsize = 10))
          }
        }, cluster_rows = FALSE, cluster_columns = FALSE,
        show_row_names = FALSE, show_column_names = FALSE)

ComplexHeatmap-1.34.png

1.8.2 layer_fun

 cell_fun adds graphics cell by cell, while layer_fun adds graphics in a block-wise manner.

mfoo = matrix(1:9, nr = 3)
mfoo[1:2, c(1, 3)]
# but we actually want mfoo[1, 1] and mfoo[2, 3]

pindex(mfoo, 1:2, c(1, 3))

col_fun = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red"))
Heatmap(small_mat, name = "mat1", col = col_fun,
        layer_fun = function(j, i, x, y, width, height, fill) {
          # since grid.text can also be vectorized

          grid.text(sprintf("%.1f", pindex(small_mat, i, j)), x, y, gp = gpar(fontsize = 10))
        })

Heatmap(small_mat, name = "mat2", col = col_fun, 
        layer_fun = function(j, i, x, y, width, height, fill) {
          v = pindex(small_mat, i, j)
          l = v > 0
          grid.text(sprintf("%.1f", v[l]), x[l], y[l], gp = gpar(fontsize = 10))
        })

Heatmap(small_mat, name = "mat3", col = col_fun,
        row_km = 2, column_km = 2,
        layer_fun = function(j, i, x, y, width, height, fill) {
          v = pindex(small_mat, i, j)
          grid.text(sprintf("%.1f", v), x, y, gp = gpar(fontsize = 10))
          if(sum(v > 0)/length(v) > 0.75) {
            grid.rect(gp = gpar(lwd = 2, fill = "transparent"))
          }
        })

Heatmap(small_mat, name = "mat4", col = col_fun,
        row_km = 2, column_km = 2,
        layer_fun = function(j, i, x, y, width, height, fill, slice_r, slice_c) {
          v = pindex(small_mat, i, j)
          grid.text(sprintf("%.1f", v), x, y, gp = gpar(fontsize = 10))
          if(slice_r != slice_c) {
            grid.rect(gp = gpar(lwd = 2, fill = "transparent"))
          }
        })

ComplexHeatmap-1.35.png

Heatmap(small_mat, name = "mat", col = col_fun,
        row_km = 2, column_km = 2,
        layer_fun = function(j, i, x, y, w, h, fill) {
          # restore_matrix() is explained after this chunk of code

          ind_mat = restore_matrix(j, i, x, y)
          for(ir in seq_len(nrow(ind_mat))) {
            # start from the second column

            for(ic in seq_len(ncol(ind_mat))[-1]) {
              ind1 = ind_mat[ir, ic-1] # previous column

              ind2 = ind_mat[ir, ic]   # current column

              v1 = small_mat[i[ind1], j[ind1]]
              v2 = small_mat[i[ind2], j[ind2]]
              if(v1 * v2 > 0) { # if they have the same sign

                col = ifelse(v1 > 0, "darkred", "darkgreen")
                grid.segments(x[ind1], y[ind1], x[ind2], y[ind2],
                              gp = gpar(col = col, lwd = 2))
                grid.points(x[c(ind1, ind2)], y[c(ind1, ind2)], 
                            pch = 16, gp = gpar(col = col), size = unit(4, "mm"))
              }
            }
          }
        })

ComplexHeatmap-1.36.png

1.9 Size of the heatmap

# 控制热图主体尺寸

Heatmap(mat, name = "mat1", width = unit(8, "cm"), height = unit(8, "cm"))

# 控制热图尺寸(包括注释和图例)

Heatmap(mat, name = "mat2", heatmap_width = unit(8, "cm"), heatmap_height = unit(8, "cm"))

ComplexHeatmap-1.37.png

  为了更加明显的展示尺寸关系,上图是以 600·600 的大小保存的,并在后期加上黑边框。

1.10 Get orders and dendrograms

ht = Heatmap(small_mat)
ht = draw(ht)

row_order(ht)
column_order(ht)

1.11 Subset a heatmap

ht = Heatmap(mat, name = "mat", row_km = 2)
ht
ht[1:10, 1:10]

ComplexHeatmap-1.38.png

  上图可以看出来,此功能本质是取输入的矩阵的子集,再画热图。换个思路,在括号中填入所需顺序,此功能不就可以实现在不聚类的情况下的重新排序吗!

2 Heatmap Annotations

  正式开始说明之前,先准备一下矩阵和简单秀下画热图注释的相关代码。

# 构建矩阵

rm(list = ls())
set.seed(123)
mat = matrix(rnorm(100), 10)
rownames(mat) = paste0("R", 1:10)
colnames(mat) = paste0("C", 1:10)
column_ha = HeatmapAnnotation(foo1 = runif(10), bar1 = anno_barplot(runif(10)))
row_ha = rowAnnotation(foo2 = runif(10), bar2 = anno_barplot(runif(10)))
Heatmap(mat, name = "mat", top_annotation = column_ha, right_annotation = row_ha)

Heatmap(mat, name = "mat", bottom_annotation = column_ha, left_annotation = row_ha)

ComplexHeatmap-2.1.png

2.1 Simple annotation

简单注释,就是利用不同颜色来展示行/列中不同的信息。

# 用1到10作注释

ha = HeatmapAnnotation(foo = 1:10)
draw(ha)

# 用abc字母作注释

ha = HeatmapAnnotation(bar = sample(letters[1:3], 10, replace = TRUE))
draw(ha)

# 渐变色映射1到10作注释

col_fun = circlize::colorRamp2(c(0, 5, 10), c("blue", "white", "red"))
ha = HeatmapAnnotation(foo = 1:10, col = list(foo = col_fun))
draw(ha)

# abc字母作注释并分别指定不同的颜色

ha = HeatmapAnnotation(bar = sample(letters[1:3], 10, replace = TRUE),
                       col = list(bar = c("a" = "red", "b" = "green", "c" = "blue")))
draw(ha)

# 组合前面两种注释,并分别指定不同的颜色

ha = HeatmapAnnotation(
  foo = 1:10, 
  bar = sample(letters[1:3], 10, replace = TRUE),
  col = list(foo = col_fun,
             bar = c("a" = "red", "b" = "green", "c" = "blue")
  )
)
draw(ha)

下图依次是上面五种示例的结果:

ComplexHeatmap-2.2.png

# NA value

ha = HeatmapAnnotation(
  foo = c(1:4, NA, 6:10), 
  bar = c(NA, sample(letters[1:3], 9, replace = TRUE)),
  col = list(foo = col_fun,
             bar = c("a" = "red", "b" = "green", "c" = "blue")),
  na_col = "black"
)
draw(ha)

# 每个格子的边框

ha = HeatmapAnnotation(
  foo = 1:10, 
  bar = sample(letters[1:3], 10, replace = TRUE),
  col = list(foo = col_fun,
             bar = c("a" = "red", "b" = "green", "c" = "blue")
  ),
  gp = gpar(col = "black")
)
draw(ha)

# 两行注释的两种方式

ha = HeatmapAnnotation(foo = cbind(a = runif(10), b = runif(10)))
draw(ha)
ha = HeatmapAnnotation(foo = cbind(runif(10), runif(10)))
draw(ha)

下图依次是上面四种示例的结果:

ComplexHeatmap-2.3.png

# 制作数据框传入

anno_df = data.frame(foo = 1:10,
                     bar = sample(letters[1:3], 10, replace = TRUE))
ha = HeatmapAnnotation(df = anno_df,
                       col = list(foo = col_fun,
                                  bar = c("a" = "red", "b" = "green", "c" = "blue")
                       )
)
draw(ha)

# 数据框和额外注释

ha = HeatmapAnnotation(df = anno_df,
                       foo2 = rnorm(10),
                       col = list(foo = col_fun,
                                  bar = c("a" = "red", "b" = "green", "c" = "blue")
                       )
)
draw(ha)

# 每个注释的边框 border

ha = HeatmapAnnotation(
  foo = cbind(1:10, 10:1),
  bar = sample(letters[1:3], 10, replace = TRUE),
  col = list(foo = col_fun,
             bar = c("a" = "red", "b" = "green", "c" = "blue")
  ),
  border = TRUE
)
draw(ha)

# 注释的尺寸 simple_anno_size

ha = HeatmapAnnotation(
  foo = cbind(a = 1:10, b = 10:1), 
  bar = sample(letters[1:3], 10, replace = TRUE),
  col = list(foo = col_fun,
             bar = c("a" = "red", "b" = "green", "c" = "blue")
  ),
  simple_anno_size = unit(3, "cm")
)
draw(ha)

下图依次是上面四种示例的结果:

ComplexHeatmap-2.4.png

2.2 Simple annotation as an annotation function

ha = HeatmapAnnotation(foo = anno_simple(1:10, 
                                         pch = c(1:4, NA, 6:8, NA, 10, 11), #形状

                                         pt_gp = gpar(col = "red"), pt_size = unit(1:10, "mm")))
draw(ha)

ha = HeatmapAnnotation(foo = anno_simple(1:10, 
                                         pch = sample(letters[1:3], 10, replace = TRUE)))
draw(ha)

ha = HeatmapAnnotation(foo = anno_simple(cbind(1:10, 10:1), pch = 1:10))
draw(ha)

# pch通过matrix传入

pch = matrix(1:20, nc = 2)
pch[sample(length(pch), 10)] = NA
ha = HeatmapAnnotation(foo = anno_simple(cbind(1:10, 10:1), pch = pch))
draw(ha)

下图依次是上面四种示例的结果:

ComplexHeatmap-2.5.png

set.seed(123)
pvalue = 10^-runif(10, min = 0, max = 3)
is_sig = pvalue < 0.01
pch = rep("*", 10)
pch[!is_sig] = NA
# color mapping for -log10(pvalue)

pvalue_col_fun = circlize::colorRamp2(c(0, 2, 3), c("green", "white", "red")) 
ha = HeatmapAnnotation(
  pvalue = anno_simple(-log10(pvalue), col = pvalue_col_fun, pch = pch),
  annotation_name_side = "left")
ht = Heatmap(matrix(rnorm(100), 10), name = "mat", top_annotation = ha)
# now we generate two legends, one for the p-value

# see how we define the legend for pvalue

lgd_pvalue = Legend(title = "p-value", col = pvalue_col_fun, at = c(0, 1, 2, 3), 
                    labels = c("1", "0.1", "0.01", "0.001"))
# and one for the significant p-values

lgd_sig = Legend(pch = "*", type = "points", labels = "< 0.01")
# these two self-defined legends are added to the plot by `annotation_legend_list`

draw(ht, annotation_legend_list = list(lgd_pvalue, lgd_sig))

ComplexHeatmap-2.6.png

2.3 Empty annotation

使用 anno_empty 获得空白注释,具体有什么用可以参考下面两个例子。

示例1:利用空白注释在右侧加上行名

random_text = function(n) {
  sapply(1:n, function(i) {
    paste0(sample(letters, sample(4:10, 1)), collapse = "")
  })
}
text_list = list(
  text1 = random_text(4),
  text2 = random_text(4),
  text3 = random_text(4),
  text4 = random_text(4)
)
# note how we set the width of this empty annotation

ha = rowAnnotation(foo = anno_empty(border = FALSE, 
                                    width = max_text_width(unlist(text_list)) + unit(4, "mm")))
Heatmap(matrix(rnorm(1000), nrow = 100), name = "mat", row_km = 4, right_annotation = ha)
for(i in 1:4) {
  decorate_annotation("foo", slice = i, {
    grid.rect(x = 0, width = unit(2, "mm"), gp = gpar(fill = i, col = NA), just = "left")
    grid.text(paste(text_list[[i]], collapse = "\n"), x = unit(4, "mm"), just = "left")
  })
}

ComplexHeatmap-2.7.png

示例2:利用空白注释在上方添加画散点图的位置

ha = HeatmapAnnotation(foo = anno_empty(border = TRUE, height = unit(3, "cm")))
ht = Heatmap(matrix(rnorm(100), nrow = 10), name = "mat", top_annotation = ha)
ht = draw(ht)
co = column_order(ht)
value = runif(10)
decorate_annotation("foo", {
  # value on x-axis is always 1:ncol(mat)

  x = 1:10
  # while values on y-axis is the value after column reordering

  value = value[co]
  pushViewport(viewport(xscale = c(0.5, 10.5), yscale = c(0, 1)))
  grid.lines(c(0.5, 10.5), c(0.5, 0.5), gp = gpar(lty = 2),
             default.units = "native")
  grid.points(x, value, pch = 16, size = unit(2, "mm"),
              gp = gpar(col = ifelse(value > 0.5, "red", "blue")), default.units = "native")
  grid.yaxis(at = c(0, 0.5, 1))
  popViewport()
})

ComplexHeatmap-2.8.png

2.4 Block annotation

Heatmap(matrix(rnorm(100), 10), name = "mat",
        top_annotation = HeatmapAnnotation(foo = anno_block(gp = gpar(fill = 2:4))),
        column_km = 3)


Heatmap(matrix(rnorm(100), 10), 
        top_annotation = HeatmapAnnotation(foo = anno_block(gp = gpar(fill = 2:4),
                                                            labels = c("group1", "group2", "group3"), 
                                                            labels_gp = gpar(col = "white", fontsize = 10))),
        column_km = 3,
        left_annotation = rowAnnotation(foo = anno_block(gp = gpar(fill = 2:4),
                                                         labels = c("group1", "group2", "group3"), 
                                                         labels_gp = gpar(col = "white", fontsize = 10))),
        row_km = 3)

ComplexHeatmap-2.9.png

2.5 Points annotation

# 一组数值

Heatmap(matrix(rnorm(100), 10), name = "mat1",
        top_annotation = HeatmapAnnotation(foo = anno_points(runif(10)))) 
# 两组数值

Heatmap(matrix(rnorm(100), 10), name = "mat2",
        top_annotation = HeatmapAnnotation(foo = anno_points(matrix(runif(20), nc = 2), 
                                                             pch = 1:2, gp = gpar(col = 2:3))))
# 点注释参数设置

Heatmap(matrix(rnorm(100), 10), name = "mat3",
        top_annotation = HeatmapAnnotation(foo = anno_points(runif(10), 
                                                             ylim = c(0, 1), # y轴范围

                                                             height = unit(2, "cm"), # 高度

                                                             axis_param = list( # 坐标轴设置

                                                               side = "left", # 位置

                                                               at = c(0, 0.5, 1), # 刻度

                                                               labels = c("zero", "half", "one") # 标记

                                                             ))))
# 注意是行注释和列注释的参数区别

Heatmap(matrix(rnorm(100), 10), name = "mat4",
        left_annotation = rowAnnotation(foo = anno_points(runif(10), 
                                                          ylim = c(0, 1),
                                                          width = unit(2, "cm"), # 宽度

                                                          axis_param = list(
                                                            side = "bottom",
                                                            at = c(0, 0.5, 1), 
                                                            labels = c("zero", "half", "one"),
                                                            labels_rot = 45 # 标记旋转角度

                                                          ))))

ComplexHeatmap-2.10.png

2.6 Lines annotation

# 一组数值

Heatmap(matrix(rnorm(100), 10), name = "mat1",
        top_annotation = HeatmapAnnotation(foo = anno_lines(runif(10)))) 
# 两组数值

Heatmap(matrix(rnorm(100), 10), name = "mat2",
        top_annotation = HeatmapAnnotation(foo = anno_lines(cbind(c(1:5, 1:5), c(5:1, 5:1)), 
                                                            gp = gpar(col = 2:3), add_points = TRUE, 
                                                            pt_gp = gpar(col = 5:6), pch = c(1, 16)))) 
# 平滑曲线

Heatmap(matrix(rnorm(100), 10), name = "mat3",
        top_annotation = HeatmapAnnotation(foo = anno_lines(runif(10), 
                                                            smooth = TRUE, # 平滑曲线

                                                            height = unit(2, "cm")))) #高度

ComplexHeatmap-2.11.png

2.7 Barplot annotation

# 默认

Heatmap(matrix(rnorm(100), 10), name = "mat1",
        top_annotation = HeatmapAnnotation(foo = anno_barplot(1:10)))

Heatmap(matrix(rnorm(100), 10), name = "mat2",
        top_annotation = HeatmapAnnotation(foo = anno_barplot(1:10, bar_width = 1, # 柱宽(0-1)

                                                              gp = gpar(fill = 1:10)))) # 填充色


# 设置基线  "min" "max" or a numeric value

Heatmap(matrix(rnorm(100), 10), name = "mat3",
        top_annotation = HeatmapAnnotation(foo = anno_barplot(seq(-5, 4), baseline = "min")))
Heatmap(matrix(rnorm(100), 10), name = "mat4",
        top_annotation = HeatmapAnnotation(foo = anno_barplot(seq(-5, 4), baseline = 0)))

ComplexHeatmap-2.12.png

# 堆积图

Heatmap(matrix(rnorm(100), 10), name = "mat1",
        top_annotation = HeatmapAnnotation(foo = anno_barplot(cbind(1:10, 1:10), 
                                                              gp = gpar(fill = 2:3, col = 2:3),
                                                              height = unit(2, "cm")))) # 高度

# 百分比堆积图

m = matrix(runif(4*10), nc = 4)
m = t(apply(m, 1, function(x) x/sum(x)))
Heatmap(matrix(rnorm(100), 10), name = "mat2",
        top_annotation = HeatmapAnnotation(foo = anno_barplot(m, gp = gpar(fill = 2:5), 
                                                              bar_width = 1, 
                                                              height = unit(3, "cm"))))

# 翻转  reverse

ha_list = rowAnnotation(axis_reverse = anno_barplot(m, gp = gpar(fill = 2:5), 
                                                    axis_param = list(direction = "reverse"), 
                                                    bar_width = 1, width = unit(4, "cm"))) +
  rowAnnotation(axis_normal = anno_barplot(m, gp = gpar(fill = 2:5), 
                                           bar_width = 1, width = unit(4, "cm")))
draw(ha_list, ht_gap = unit(4, "mm")) # 注释间距离

ComplexHeatmap-2.13.png

2.8 Boxplot annotation

set.seed(12345)
m = matrix(rnorm(100), 10)

ha = HeatmapAnnotation(foo = anno_boxplot(m, height = unit(3, "cm"))) # 高度

Heatmap(matrix(rnorm(100), 10), name = "mat1",top_annotation = ha)

ha = HeatmapAnnotation(foo = anno_boxplot(m, height = unit(3, "cm"), gp = gpar(fill = 1:10))) # 填充色

Heatmap(matrix(rnorm(100), 10), name = "mat2",top_annotation = ha)

ha = HeatmapAnnotation(foo = anno_boxplot(m, height = unit(3, "cm"), 
                                          box_width = 0.9, # 箱体宽度

                                          outline = FALSE)) # 去除异常值

Heatmap(matrix(rnorm(100), 10), name = "mat3",top_annotation = ha)

ComplexHeatmap-2.14.png

2.9 Histogram annotation

m = matrix(rnorm(1000), nc = 100)
ha = rowAnnotation(foo = anno_histogram(m)) # apply `m` on rows

Heatmap(matrix(rnorm(100), 10), name = "mat1",right_annotation = ha)

ha = rowAnnotation(foo = anno_histogram(m, n_breaks = 100, # 设置刻度大小

                                        gp = gpar(fill = 1:10))) # 设置填充色

Heatmap(matrix(rnorm(100), 10), name = "mat2",right_annotation = ha)

ComplexHeatmap-2.15.png

2.10 Density annotation

ha = rowAnnotation(foo = anno_density(m))
Heatmap(matrix(rnorm(100), 10), name = "mat1",right_annotation = ha)

# Joyplot

ha = rowAnnotation(foo = anno_density(m, joyplot_scale = 2, 
                                      gp = gpar(fill = "#e41a1c60"), # 使用带有透明度的颜色填充

                                      border = FALSE)) # 去除边框

Heatmap(matrix(rnorm(100), 10), name = "mat2",right_annotation = ha)

# type:"violine" for violin plot 

ha = rowAnnotation(foo = anno_density(m, type = "violin", 
                                      gp = gpar(fill = 1:10)))
Heatmap(matrix(rnorm(100), 10), name = "mat3",right_annotation = ha)

# type:"heatmap" for heatmap visualization of density distribution 

m2 = matrix(rnorm(50*10), nrow = 10)
ha = rowAnnotation(foo = anno_density(m2, type = "heatmap", 
                                      width = unit(6, "cm"))) # 宽度

Heatmap(matrix(rnorm(100), 10), name = "mat4",right_annotation = ha)


ha = rowAnnotation(foo = anno_density(m2, type = "heatmap", width = unit(6, "cm"), 
                                      heatmap_colors = c("white", "orange"))) # 热图颜色

Heatmap(matrix(rnorm(100), 10), name = "mat5",right_annotation = ha)

ComplexHeatmap-2.16.png

2.11 Joyplot annotation

m = matrix(rnorm(1000), nc = 10)
lt = apply(m, 2, function(x) data.frame(density(x)[c("x", "y")]))
ha = rowAnnotation(foo = anno_joyplot(lt, width = unit(4, "cm"), # 宽度

                                      gp = gpar(fill = 1:10), # 填充色

                                      transparency = 0.75, # 透明度

                                      scale = 3)) # 相对高度,1为界限

Heatmap(matrix(rnorm(100), 10), name = "mat",right_annotation = ha)

ComplexHeatmap-2.17.png

2.12 Horizon chart annotation

# 一个list

lt = lapply(1:10, function(x) cumprod(1 + runif(1000, -x/100, x/100)) - 1)
# 默认效果

ha = rowAnnotation(foo = anno_horizon(lt))
Heatmap(matrix(rnorm(100), 10), name = "mat1",right_annotation = ha)

# 负值翻转 negative_from_top

ha = rowAnnotation(foo = anno_horizon(lt, negative_from_top = TRUE))
Heatmap(matrix(1:100, 10), name = "mat2",right_annotation = ha)

# 颜色及间隔

ha = rowAnnotation(foo = anno_horizon(lt,gp = gpar(pos_fill = "orange", # 负值填充色

                                                   neg_fill = "darkgreen"), # 正值填充色

                                      gap = unit(1, "mm"))) # 间隔

Heatmap(matrix(1:100, 10), name = "mat3",right_annotation = ha)

# 也可以填充颜色的向量

ha = rowAnnotation(foo = anno_horizon(lt, gp = gpar(pos_fill = rep(c("orange", "red"), each = 10),
                                                    neg_fill = rep(c("darkgreen", "blue"), each = 10))))
Heatmap(matrix(1:100, 10), name = "mat4",right_annotation = ha)

ComplexHeatmap-2.18.png

2.13 Text annotation

ha = rowAnnotation(foo = anno_text(month.name[1:10], 
                                   gp = gpar(fontsize = 1:12+4), # 大小

                                   rot = 30, # 角度

                                   location = 0, # 位置

                                   just = "left")) # 对齐方式("left", "right", "centre", "center", "bottom", and "top" )

Heatmap(matrix(1:100, 10), name = "mat1",right_annotation = ha)

ha = rowAnnotation(foo = anno_text(month.name[1:10], location = 0.5, just = "center",
                                   gp = gpar(fill = 1:10, # 背景填充色

                                             col = "white", # 文字颜色 

                                             border = "black"), # 边框颜色

                                   width = max_text_width(month.name)*1.2)) # 宽度

Heatmap(matrix(1:100, 10), name = "mat2",right_annotation = ha)

ComplexHeatmap-2.19.png

2.14 Mark annotation

m = matrix(rnorm(1000), nrow = 100)
ha = rowAnnotation(foo = anno_mark(at = c(1:4, 20, 60, 97:100), 
                                   labels = month.name[1:10],
                                   link_width = unit(10, "mm"), #线长度

                                   padding = unit(5, "mm"), # 标签间隔

                                   extend = unit(0, "mm")))
Heatmap(m, name = "mat", cluster_rows = FALSE, right_annotation = ha)

ComplexHeatmap-2.20.png

2.15 Summary annotation

统计划分后的每个区块的相关信息。

# 条形图

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 = "mat1", col = c("a" = "red", "b" = "blue"),
        top_annotation = ha, width = unit(2, "cm"), row_split = split)

# 箱线图

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

ComplexHeatmap-2.21.png

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))

ComplexHeatmap-2.22.png

2.16 Zoom annotation

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_zoom(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)

ComplexHeatmap-2.23.png

2.17 Multiple annotations

set.seed(123)
mat = matrix(rnorm(100), 10)

ha = HeatmapAnnotation(foo = 1:10, 
                       bar = cbind(1:10, 10:1),
                       pt = anno_points(1:10),
                       # show_legend = c(bar = FALSE),

                       show_legend = c(T,F), # 是否显示图例

                       show_annotation_name = c(T,T,F), # 是否显示注释名

                       border = c(F,T) ,# 是否显示边框

                       gap = unit(c(2,4), "mm")
                       )
Heatmap(mat, name = "mat1", top_annotation = ha)

ha = HeatmapAnnotation(foo = 1:10, 
                       bar = cbind(1:10, 10:1),
                       pt = anno_points(1:10),
                       gp = gpar(col = "red") # 线条或边框的颜色

)
Heatmap(mat, name = "mat2", top_annotation = ha)

ComplexHeatmap-2.24.png

2.18 Size of annotations

ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
                       bar = 1:10,
                       pt = anno_points(1:10))
Heatmap(mat, name = "mat1", top_annotation = ha)

# annotation_height 直接添加长度单位

ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
                       bar = 1:10,
                       pt = anno_points(1:10),
                       annotation_height = unit(1:3, "cm"))
Heatmap(mat, name = "mat2", top_annotation = ha)

ComplexHeatmap-2.25.png

  • height :确定总的注释高度
  • annotation_height :确定每个注释比例。
# foo: 2cm, bar: 4cm, pt: 6cm

ha = HeatmapAnnotation(foo = cbind(1:10, 10:1), 
                       bar = 1:10,
                       pt = anno_points(1:10),
                       annotation_height = 1:3, height = unit(12, "cm"))
Heatmap(mat, name = "mat1", top_annotation = ha)


# 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"))
Heatmap(mat, name = "mat2", top_annotation = ha)


# 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"))
Heatmap(mat, name = "mat3", top_annotation = ha)

ComplexHeatmap-2.26.png

2.19 Utility functions

这里主要介绍一些比较实用的小功能。

ha = HeatmapAnnotation(foo = 1:10, 
                       bar = cbind(1:10, 10:1),
                       pt = anno_points(1:10))
length(ha) # 注释个数

nobs(ha) #行数

names(ha) # 注释名


names(ha) = c("FOO", "BAR", "PT") # 重命名注释名

names(ha)

多个注释也是一样的。

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)

2.20 Implement new annotation functions

自定义注释。

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

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))

ComplexHeatmap-2.27.png

3 A List of Heatmaps

  本节主要就是介绍怎么样组合多个热图。老样子先构建矩阵。

set.seed(123)
mat1 = matrix(rnorm(80, 2), 8, 10)
mat1 = rbind(mat1, matrix(rnorm(40, -2), 4, 10))
rownames(mat1) = paste0("R", 1:12)
colnames(mat1) = paste0("C", 1:10)

mat2 = matrix(runif(60, max = 3, min = 1), 6, 10)
mat2 = rbind(mat2, matrix(runif(60, max = 2, min = 0), 6, 10))
rownames(mat2) = paste0("R", 1:12)
colnames(mat2) = paste0("C", 1:10)

le = sample(letters[1:3], 12, replace = TRUE)
names(le) = paste0("R", 1:12)

ind = sample(12, 12)
mat1 = mat1[ind, ]
mat2 = mat2[ind, ]
le = le[ind]

  上面构建了mat1, mat2 和 le 三个矩阵,最简单粗暴的组合方式就是利用 + 来完成热图之间的组合,可以自己先运行下面的代码简单感受一下花式组合,后面再继续介绍相关参数的设置。

ht1 = Heatmap(mat1, name = "rnorm")
ht2 = Heatmap(mat2, name = "runif")
ht3 = Heatmap(le, name = "letters")

ht1 + ht2 + ht3
ht_list = ht1 + ht2 + ht3
ht1 + ht_list
ht_list + ht1
ht_list + ht_list

  在介绍单个热图制作的时候,提到过循环出图的问题。现在了解了组合,我们可以先用一个 list 来存储热图。

ht_list = NULL  ## Heatmap(...) + NULL gives you a HeatmapList object

for(s in sth) {
  ht_list = ht_list + Heatmap(...)
}

3.1 Titles

col_rnorm = circlize::colorRamp2(c(-3, 0, 3), c("green", "white", "red"))
col_runif = circlize::colorRamp2(c(0, 3), c("white", "orange"))
col_letters = c("a" = "pink", "b" = "purple", "c" = "blue")

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm,
              row_title = "Heatmap 1", column_title = "Heatmap 1")
ht2 = Heatmap(mat2, name = "runif", col = col_runif,
              row_title = "Heatmap 2", column_title = "Heatmap 2")
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3

draw(ht_list, 
     row_title = "Three heatmaps, row title", # 行标题

     row_title_gp = gpar(col = "red"), # 行标题名参数

     column_title = "Three heatmaps, column title", # 列标题

     column_title_gp = gpar(fontsize = 16)) # 列标题参数

ComplexHeatmap-3.1.png

3.2 Size of heatmaps

参数后传入长度。

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, width = unit(4, "cm"))
ht2 = Heatmap(mat2, name = "runif", col = col_runif, width = unit(6, "cm"))
ht3 = Heatmap(le, name = "letters", col = col_letters, width = unit(1, "cm"))
ht1 + ht2 + ht3

ComplexHeatmap-3.2.png

参数后传入比例,如下直接填入数字即可。

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, width = 6)
ht2 = Heatmap(mat2, name = "runif", col = col_runif, width = 4)
ht3 = Heatmap(le, name = "letters", col = col_letters, width = 1)
ht1 + ht2 + ht3

ComplexHeatmap-3.3.png

3.3 Gap between heatmaps

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list, ht_gap = unit(3, "mm"))
draw(ht_list, ht_gap = unit(c(3, 10), "mm"))

ComplexHeatmap-3.4.png

3.4 Automatic adjustment to the main heatmap

热图的行聚类及切割效果均以主热图为基准,默认放在最前面的为主热图。

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, row_km = 2)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht2 + ht1 + ht3 # ht2 is the main heatmap and row_km in ht1 is ignored

ComplexHeatmap-3.5.png

下面是一些相关参数的示例:

ht_list = ht2 + ht1 + ht3
draw(ht_list, main_heatmap = "rnorm", # 调整主热图

     row_dend_side = "right", # 行树图位置

     row_sub_title_side = "left") # 行子标题位置

ComplexHeatmap-3.6.png

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list, auto_adjust = FALSE)
draw(ht_list)

ComplexHeatmap-3.7.png

3.5 Control main heatmap in draw() function

In draw() function, following main heatmap settings control row orders of all heatmaps.

  • cluster_rows
  • clustering_distance_rows
  • clustering_method_rows
  • row_dend_width
  • show_row_dend
  • row_dend_reorder
  • row_dend_gp
  • row_order

Following settings control the row slices.

  • row_gap
  • row_km
  • row_km_repeats
  • row_split

Following settings control the heatmap height.

  • height
  • heatmap_height
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, row_km = 2, cluster_rows = FALSE)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list, row_km = 1, 
     row_split = le, 
     cluster_rows = TRUE)

ComplexHeatmap-3.8.png

3.6 Annotations as components are adjusted

  每个热图不全是简单注释的热图会自动对齐注释,如果在注释中已经设定了注释的高度的是不能自动对齐的。

ha1 = HeatmapAnnotation(foo1 = 1:10, 
                        bar1 = anno_points(1:10), 
                        annotation_name_side = "left")
ha2 = HeatmapAnnotation(bar2 = anno_barplot(1:10))
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, top_annotation = ha1)
ht2 = Heatmap(mat2, name = "runif", col = col_runif, top_annotation = ha2)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list, ht_gap = unit(c(6, 2), "mm")) 

ComplexHeatmap-3.9.png

有和无注释的热图不能自动对齐注释。

ha1 = HeatmapAnnotation(foo1 = 1:10, annotation_name_side = "left")
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, top_annotation = ha1)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht1 + ht2 + ht3

ComplexHeatmap-3.10.png

下面的情况就是至少有一个热图全是简单注释从而不能自动对齐。

ha1 = HeatmapAnnotation(foo1 = 1:10, annotation_name_side = "left")
ha2 = HeatmapAnnotation(bar2 = anno_barplot(1:10, height = unit(2, "cm")))
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, top_annotation = ha1)
ht2 = Heatmap(mat2, name = "runif", col = col_runif, top_annotation = ha2)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list, ht_gap = unit(c(6, 2), "mm"))

ha1 = HeatmapAnnotation(foo1 = 1:10, annotation_name_side = "left")
ha2 = HeatmapAnnotation(bar2 = cbind(b1 = 1:10, b2 = 11:20, b3 = 21:30))
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, top_annotation = ha1)
ht2 = Heatmap(mat2, name = "runif", col = col_runif, top_annotation = ha2)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list)

ComplexHeatmap-3.11.png

  想要保持注释对齐的话,可以在 HeatmapAnnotation 中加 simple_anno_size_adjust = TRUE

ha1 = HeatmapAnnotation(foo1 = 1:10, annotation_name_side = "left", simple_anno_size_adjust = TRUE)
ha2 = HeatmapAnnotation(bar2 = anno_barplot(1:10, height = unit(2, "cm")))
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, top_annotation = ha1)
ht2 = Heatmap(mat2, name = "runif", col = col_runif, top_annotation = ha2)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list, ht_gap = unit(c(6, 2), "mm"))

ComplexHeatmap-3.12.png

第二个热图无底部注释,第一个热图的列名会直接置于最下。

ha1 = HeatmapAnnotation(foo1 = 1:10, bar1 = anno_points(1:10), annotation_name_side = "left")
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, bottom_annotation = ha1)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht3 = Heatmap(le, name = "letters", col = col_letters)
ht_list = ht1 + ht2 + ht3
draw(ht_list)

ComplexHeatmap-3.13.png

3.7 Concatenate with annotations

# 热图和注释连接

ha1 = rowAnnotation(foo = 1:12, bar = anno_barplot(1:12, width = unit(4, "cm")))
ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, row_km = 2)
ht1 + ha1

# 下面代码等同上面

Heatmap(mat1, name = "rnorm", col = col_rnorm, row_km = 2) + 
  rowAnnotation(foo = 1:12) +
  rowAnnotation(bar = anno_barplot(1:12, width = unit(4, "cm")))

ComplexHeatmap-3.14.png

rowAnnotation(foo = 1:12) +
  Heatmap(mat1, name = "rnorm", col = col_rnorm, row_km = 2) + 
  rowAnnotation(bar = anno_barplot(1:12, width = unit(4, "cm"))) +
  Heatmap(mat2, name = "runif", col = col_runif)

ComplexHeatmap-3.15.png

3.8 Concatenate only the annotations

# 没有热图也是可以的

rowAnnotation(foo = 1:12) +
  rowAnnotation(bar = anno_barplot(1:12, width = unit(4, "cm")))

# 只有一个注释则必须额外加上NULL

rowAnnotation(bar = anno_barplot(1:12, width = unit(4, "cm"))) + NULL

# 同样可以使用draw里面的功能进行操作

anno_list = rowAnnotation(foo = 1:12) +
  rowAnnotation(bar = anno_barplot(1:12, width = unit(4, "cm")))
draw(anno_list, row_split = rep(c("A", "B"), each = 6))

ComplexHeatmap-3.16.png

3.9 Vertical concatenation

纵向连接使用 %v% ,其余参数均类似于横向连接,下面代码可以自行体会。

mat1t = t(mat1)
mat2t = t(mat2)
ht1 = Heatmap(mat1t, name = "rnorm", col = col_rnorm, row_title = "rnorm")
ht2 = Heatmap(mat2t, name = "runif", col = col_runif, row_title = "runif")
ht3 = Heatmap(rbind(letters = le), name = "letters", col = col_letters)
ht_list = ht1 %v% ht2 %v% ht3
draw(ht_list)
draw(ht_list, column_km = 2)

ha = HeatmapAnnotation(foo = anno_barplot(1:12, height = unit(2, "cm")))
ht_list = ht1 %v% ha %v% ht2 %v% ht3
draw(ht_list, column_km = 2)

ht1 = Heatmap(mat1t, name = "rnorm", col = col_rnorm, row_km = 2)
ht2 = Heatmap(mat2t, name = "runif", col = col_runif, row_km = 2)
ht3 = Heatmap(rbind(letters = le), name = "letters", col = col_letters)
ha = HeatmapAnnotation(foo = anno_barplot(1:12, height = unit(2, "cm")))
ht_list = ht1 %v% ha %v% ht2 %v% ht3
draw(ht_list, column_km = 2)

ht1 = Heatmap(mat1t, name = "rnorm", col = col_rnorm, row_km = 2,
              left_annotation = rowAnnotation(foo1 = 1:10, bar1 = anno_barplot(1:10)))
ha = HeatmapAnnotation(foo = anno_barplot(1:12, height = unit(2, "cm"), 
                                          axis_param = list(side = "right")))
ht2 = Heatmap(mat2t, name = "runif", col = col_runif, row_km = 2,
              left_annotation = rowAnnotation(foo2 = 1:10))
ht3 = Heatmap(rbind(letters = le), name = "letters", col = col_letters)
ht_list = ht1 %v% ha %v% ht2 %v% ht3
draw(ht_list, column_km = 2)

3.10 Subset the heatmap list

与前面画单个热图的亚集类似。

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm, 
              left_annotation = rowAnnotation(foo1 = 1:12, bar1 = anno_points(1:12)))
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ha = rowAnnotation(foo2 = anno_barplot(1:12), bar2 = 12:1)
ht_list = ht1 + ht2 + ha
names(ht_list)
draw(ht_list)
ht_list[1:6, c("rnorm", "bar2")]

ComplexHeatmap-3.17.png

3.11 Get orders and dendrograms

同样与单个热图取顺序类似。

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm)
ht2 = Heatmap(mat2, name = "runif", col = col_runif)
ht_list = ht1 + ht2
ht_list = draw(ht_list)
row_order(ht_list)
column_order(ht_list)

# 分割成多少块,获得的顺序也会化分成多少个

ht1 = Heatmap(mat1, name = "rnorm", col = col_rnorm)
ht2 = Heatmap(mat2, name = "runif", col = col_runif, column_km = 2)
ht_list = ht1 + ht2
ht_list = draw(ht_list, row_km = 2)
row_order(ht_list)
column_order(ht_list)

# 只获得其中一部分的顺序

column_order(ht_list, name = "runif")

3.12 Change parameters globally

ht_opt

There are following parameters to control all heatmaps:

  • heatmap_row_names_gp: set row_names_gp in all Heatmap().
  • heatmap_column_names_gp: set column_names_gp in all Heatmap().
  • heatmap_row_title_gp: set row_title_gp in all Heatmap().
  • heatmap_column_title_gp: set column_title_gp in all Heatmap().
  • heatmap_border: set border in all Heatmap().

Following parameters control the legends:

  • legend_title_gp: set title_gp in all heatmap legends and annotation legends.
  • legend_title_position: set title_position in all heatmap legends and annotation legends.
  • legend_labels_gp: set labels_gp in all heatmap legends and annotation legends.
  • legend_grid_width: set grid_width in all heatmap legends and annotation legends.
  • legend_grid_height: set grid_height in all heatmap legends and annotation legends.
  • legend_border: set border in all heatmap legends and annotation legends.

Following parameters control heatmap annotations:

  • annotation_border: set border in all HeatmapAnnotation().
  • anno_simple_size: set size for the simple annotation.

Following parameters control the space between heatmap components:

  • DENDROGRAM_PADDING: space bewteen dendrograms and heatmap body.
  • DIMNAME_PADDING: space between row/column names and heatmap body.
  • TITLE_PADDING: space between row/column titles and heatmap body.
  • COLUMN_ANNO_PADDING: space between column annotations and heatmap body.
  • ROW_ANNO_PADDING: space between row annotations and heatmap body.

Other parameters:

  • fast_hclust: whether use fastcluster::hclust() to speed up clustering?
  • show_parent_dend_line: when heatmap is split, whether to add a dashed line to mark parent dendrogram and children dendrograms?
ht_opt(heatmap_column_names_gp = gpar(fontface = "italic"), 
       heatmap_column_title_gp = gpar(fontsize = 10),
       legend_border = "black",
       heatmap_border = TRUE,
       annotation_border = TRUE
)
ht1 = Heatmap(mat1, name = "ht1", column_title = "Heatmap 1",
              top_annotation = HeatmapAnnotation(foo = 1:10))
ht2 = Heatmap(mat2, name = "ht2", column_title = "Heatmap 2",
              top_annotation = HeatmapAnnotation(bar = 1:10))
ht1 + ht2
ht_opt(RESET = TRUE) # 重置为默认配置

ComplexHeatmap-3.18.png

3.13 Adjust blank space caused by annotations

m = matrix(rnorm(100), 10)
ht = Heatmap(m, name = "mat",
             top_annotation = HeatmapAnnotation(foo = anno_points(1:10)),
             show_row_dend = FALSE)
draw(ht, row_title = "fooooooooooo", adjust_annotation_extension = TRUE,  # default

     column_title = "adjust_annotation_extension = TRUE")
draw(ht, row_title = "fooooooooooo", adjust_annotation_extension = FALSE,
     column_title = "adjust_annotation_extension = FALSE")

ComplexHeatmap-3.19.png

3.14 Manually increase space around the plot

m2 = m
rownames(m2) = paste0("R", 1:10)
rownames(m2)[1] = "a long long long long long row name"
ht = Heatmap(m2, name = "mat", row_names_side = "left", show_row_dend = FALSE)
draw(ht, padding = unit(c(2, 20, 2, 2), "mm")) ## see right heatmap in following

ComplexHeatmap-3.20.png

4 Legends

4.1 Continuous legends

rm(list = ls())
library(ComplexHeatmap)

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

ComplexHeatmap-4.1.png

需要单独画图例的时候,可以利用 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()

ComplexHeatmap-4.2.png

Heatmap(matrix(rnorm(100), 10), 
        heatmap_legend_param = list(
          title = "rnorm", # 标题

          title_position = "topleft", # 标题位置(topleft, topcenter, leftcenter-rot and lefttop-rot are only for vertical legend and leftcenter, lefttop are only for horizontal legend.)

          legend_height = unit(6, "cm"), #t图例主体高度

          grid_width = unit(1, "cm"), # 宽度

          # legend_width = unit(1, "cm"), # 宽度,作用于连续的水平图例

          labels_gp = gpar(col = "red", font = 3), # label的颜色及大小

          border = "black", # 边框颜色

          at = c(-2, 0, 2),  # Break values of the legend

          labels = c("neg_two", "zero", "pos_two"),# Labels corresponding to break values

          labels_rot = 180),
        top_annotation = HeatmapAnnotation(
          foo = 1:10,
          annotation_legend_param = list(foo = list(title = "foo_top_anno"))))

ComplexHeatmap-4.3.png

# 支持数学表达式

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))
draw(lgd)

# 水平图例(大部分参数同上)

lgd = Legend(col_fun = col_fun, title = "foo", at = c(0, 0.25, 0.5, 0.75, 1), 
             title_gap = unit(3, "cm"), # 标题和主体的间隔

             title_position = "topcenter",
             direction = "horizontal", # 设置为水平("vertical", "horizontal")

             labels_rot = 45)
draw(lgd)

ComplexHeatmap-4.4.png

4.2 Discrete legends

与连续型图例参数类似,直接看下面代码。

lgd = Legend(at = 1:6, 
             direction = "vertical",
             title = "foo", 
             title_position = "topleft",
             labels = month.name[1:6],
             grid_height = unit(1, "cm"), # 区别于前面的legend_height

             grid_width = unit(10, "mm"),
             border = "red",
             legend_gp = gpar(fill = 1:6),
             labels_gp = gpar(col = "red", fontsize = 14),
             title_gp = gpar(col = "black", 
                             fontsize = 14))
draw(lgd)

ComplexHeatmap-4.5.png

图例太多的话,可以使用 ncol/nrow 来分组。

lgd = Legend(labels = month.name[1:10], legend_gp = gpar(fill = 1:10), title = "foo",  title_position = "topcenter", 
             gap = unit(1, "cm"), # 设置间隔大小

             ncol = 3)
draw(lgd)

ComplexHeatmap-4.6.png

ncol/nrow 默认按行排序,按列排序需要使用 by_row

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

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

ComplexHeatmap-4.7.png

# 使用 points 图例

lgd = Legend(labels = month.name[1:6], title = "foo1", 
             type = "points", 
             pch = 1:6, # 数字表示不同的形状

             border = "black", legend_gp = gpar(col = 1:6), background = "white")
draw(lgd)

lgd = Legend(labels = month.name[1:6], title = "foo1", 
             type = "points", 
             pch = letters[1:6],# 传入字母

             border = "black", legend_gp = gpar(col = 1:6), background = "white")
draw(lgd)

# 使用 lines 画图例

lgd = Legend(labels = month.name[1:6], title = "foo3", 
             type = "lines", 
             legend_gp = gpar(col = 1:6, 
                              lty = 1:6), # 数字表示不同线的种类

             grid_width = unit(1, "cm"),
             border = "white", background = "white")
draw(lgd)

# 使用 boxplot 画图例

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

ComplexHeatmap-4.8.png

4.3 A list of legends

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)
pd = packLegend(list = list(lgd1, lgd2, lgd3))
draw(pd)


pd = packLegend(lgd1, lgd3, lgd2, lgd3, lgd2, lgd1, 
                direction = "vertical", # "vertical", "horizontal"

                max_height = unit(10, "cm"), # 整个图例的最大高度

                column_gap = unit(1, "cm")) # 列间隔

draw(pd)

ComplexHeatmap-4.9.png

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, 
                direction = "horizontal", column_gap = unit(5, "mm"), 
                max_width = unit(10, "cm"), # 整个图例的最大宽度

                row_gap = unit(1, "cm")) # 行间隔

draw(pd)

ComplexHeatmap-4.10.png

4.4 Heatmap and annotation legends

# 热图的图例(heatmap_legend_param),参数和上面基本一致。

m = matrix(rnorm(100), 10)
Heatmap(m, name = "mat1", 
        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"
        ))

# 注释的图例(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 = "mat2", top_annotation = ha)

ComplexHeatmap-4.11.png

下面给出大量的例子以供体会。

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)

ComplexHeatmap-4.12.png

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))

ComplexHeatmap-4.13.png

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)

ComplexHeatmap-4.14.png

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)

ComplexHeatmap-4.15.png

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"))))

ComplexHeatmap-4.16.png

4.5 Add customized legends

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"))
# 增加注释的图例

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)

ComplexHeatmap-4.17.png

4.6 The side of legends

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 = T, 
     heatmap_legend_side = "bottom", 
     annotation_legend_side = "bottom")

ComplexHeatmap-4.18.png

5 Heatmap Decoration

  顾名思义,本节主要介绍热图的装饰美化,下图红框部分都是可进行操作的部分。

ComplexHeatmap-5.0.png

set.seed(123)
mat = matrix(rnorm(80, 2), 8, 10)
mat = rbind(mat, matrix(rnorm(40, -2), 4, 10))
rownames(mat) = paste0("R", 1:12)
colnames(mat) = paste0("C", 1:10)

ha_column1 = HeatmapAnnotation(points = anno_points(rnorm(10)), 
                               annotation_name_side = "left")
ht1 = Heatmap(mat, name = "ht1", km = 2, column_title = "Heatmap 1", 
              top_annotation = ha_column1, row_names_side = "left")

ha_column2 = HeatmapAnnotation(type = c(rep("a", 5), rep("b", 5)),
                               col = list(type = c("a" = "red", "b" = "blue")))
ht2 = Heatmap(mat, name = "ht2", row_title = "Heatmap 2", column_title = "Heatmap 2",
              bottom_annotation = ha_column2, column_km = 2)

ht_list = ht1 + ht2 + 
  rowAnnotation(bar = anno_barplot(rowMeans(mat), width = unit(2, "cm")))
draw(ht_list, row_title = "Heatmap list", column_title = "Heatmap list")

ComplexHeatmap-5.1.png

5.1 Decoration functions

There are following decoration functions.

  • decorate_heatmap_body()
  • decorate_annotation()
  • decorate_dend()
  • decorate_title()
  • decorate_dimnames()
  • decorate_row_names(), identical to decorate_dimnames(…, which = “row”).
  • decorate_column_names(), identical to decorate_dimnames(…, which = “column”).
  • decorate_row_dend(), identical to decorate_dend(…, which = “row”).
  • decorate_column_dend(), identical to decorate_dend(…, which = “column”).
  • decorate_row_title(), identical to decorate_title(…, which = “row”).
  • decorate_column_title(), identical to decorate_title(…, which = “column”).

依次运行下面代码查看就可以知道每个代码的作用。

ht_list = draw(ht_list, row_title = "Heatmap list", column_title = "Heatmap list", 
               heatmap_legend_side = "right", annotation_legend_side = "left")

decorate_heatmap_body("ht1", {
  grid.text("outlier", 1.5/10, 2.5/4, default.units = "npc")
  grid.lines(c(0.5, 0.5), c(0, 1), gp = gpar(lty = 2, lwd = 2))
}, slice = 2)

decorate_column_dend("ht1", {
  tree = column_dend(ht_list)$ht1[[1]]
  ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]
  
  first_index = function(l) which(l)[1]
  last_index = function(l) { x = which(l); x[length(x)] }
  x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
  x2 = c(last_index(ind == 1), last_index(ind == 2))
  grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
            default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})

decorate_row_names("ht1", {
  grid.rect(gp = gpar(fill = "#FF000040"))
}, slice = 2)

decorate_row_title("ht1", {
  grid.rect(gp = gpar(fill = "#00FF0040"))
}, slice = 1)

decorate_annotation("points", {
  grid.lines(c(0, 1), unit(c(0, 0), "native"), gp = gpar(col = "red"))
})

ComplexHeatmap-5.2.png

5.2 Examples

Barplot for single-column heatmap.

# DMRs

bed = generateRandomBed(nr = 1000)
# fractions

frac = c(runif(400, min = 0.4, max = 1), runif(nrow(bed) - 400, min = 0.2, max = 0.6))
col_fun = circlize::colorRamp2(c(0, 1), c("white", "orange"))
# two groups

split = c(rep("group1", 400), rep("group2", nrow(bed) - 400))
# draw the fraction heatmap with an empty annotation

ht = Heatmap(frac, name = "fraction", col = col_fun, width = unit(2, "cm"),
             top_annotation = HeatmapAnnotation(barplot = anno_empty(height = unit(4, "cm"))))
ht = draw(ht, row_split = split)
# get the row indices in the two row-groups

ro = row_order(ht)
w = bed[, 3] - bed[, 2]
# the mean weighted fraction in the two groups

p = sapply(ro, function(index) {
  sum(w[index]*frac[index])/sum(w[index])
})
# add two bars of `p`

decorate_annotation("barplot", {
  pushViewport(viewport(xscale = c(0.5, 2.5), yscale = c(0, max(p)*1.1)))
  grid.rect(x = 1:2, y = 0, width = 0.8, height = p, just = "bottom",
            gp = gpar(fill = "orange"), default.units = "native")
  grid.yaxis()
  grid.text("mean fraction", x = unit(-1.5, "cm"),rot = 90, just = "bottom")
  popViewport()
})

ComplexHeatmap-5.3.png

Add titles for row annotations.

ht_list = Heatmap(matrix(rnorm(100), 10), name = "mat", show_column_dend = FALSE) +
  rowAnnotation(foo = anno_barplot(1:10, width = unit(4, "cm"))) +
  rowAnnotation(bar = anno_boxplot(matrix(rnorm(100), 10)), width = unit(4, "cm"))
draw(ht_list, padding = unit(c(2, 2, 10, 2), "mm")) # add space for titles

decorate_annotation("foo", { 
  grid.text("title for barplot", y = unit(1, "npc") + unit(2, "mm"), just = "bottom") 
})
decorate_annotation("bar", { 
  grid.text("title for boxplot", y = unit(1, "npc") + unit(2, "mm"), just = "bottom") 
})
decorate_heatmap_body("mat", {
  grid.text("title for the heatmap", y = unit(1, "npc") + unit(2, "mm"), just = "bottom")
})

ComplexHeatmap-5.4.png

6 UpSet plot

6.1 Input data

准备好如下格式的数据。

rm(list = ls())
lt = list(set1 = c("a", "b", "c"),
          set2 = c("b", "c", "d", "e"))
list_to_matrix(lt)

6.2 Mode

  共有如下三种模式,三种模式的差别如下图所示。

  • distinct mode
  • intersect mode
  • union mode

ComplexHeatmap-6.0.png

6.3 Make the combination matrix

数据准备

set.seed(123)
lt = list(a = sample(letters, 5),
          b = sample(letters, 10),
          c = sample(letters, 15))

make_comb_mat 生产比较矩阵

m1 = make_comb_mat(lt)
m2 = make_comb_mat(a = lt$a, b = lt$b, c = lt$c)
m3 = make_comb_mat(list_to_matrix(lt))

选择不同的模式,在此可以观察三者之间的差别。

m1 = make_comb_mat(lt) # the default mode is `distinct`

m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")

也可以对数据利用不同的条件过滤

m1 = make_comb_mat(lt, min_set_size = 7) # 去除数据少于7的set

m2 = make_comb_mat(lt, top_n_sets = 2) # 保留set最大的前2个

m3 = make_comb_mat(lt, universal_set = letters[1:10]) # 所有set中只保留前10个字母的元素

m4 = make_comb_mat(lt, complement_size = 5) # 所有集合的补集的大小

6.4 Utility functions

实用小工具环节,知道有这些函数即可,具体有啥用处,后面都会举例说明。

m = make_comb_mat(lt)
set_name(m) # 集合名

comb_name(m) # 组合的集合名

set_size(m)
comb_size(m)
comb_degree(m) # 组合中包含的及集合数

extract_comb(m, "101") # 提取指定组合里面的元素

  用基因组的例子解释 extract_comb 的作用,在数据过大时就可以用这些函数来进行提取查看等一系列必须的操作。

library(circlize)
library(GenomicRanges)
lt2 = lapply(1:4, function(i) generateRandomBed())
lt2 = lapply(lt2, function(df) GRanges(seqnames = df[, 1], 
                                       ranges = IRanges(df[, 2], df[, 3])))
names(lt2) = letters[1:4]
m = make_comb_mat(lt2)
set_size(m)
comb_size(m)
extract_comb(m, "1010")

6.5 Make the plot

m = make_comb_mat(lt)
UpSet(m) # 默认


# 一些参数设置

UpSet(m, 
      pt_size = unit(5, "mm"), # 点大小

      set_order = c("a", "b", "c"),  # 集合排序

      comb_order = order(comb_size(m)), # 组合排序

      comb_col = c("red", "blue", "black")[comb_degree(m)], # 组合颜色

      bg_pt_col = "green", #不在组合中的点颜色

      bg_col = c("#F0F0FF", "#FFF0F0")) # 背景颜色一个或两个

ComplexHeatmap-6.1.png

  下面的代码本质都是对前面数据进行处理,可以更好的理解前面那些函数的功用,自行按需组合使用即可。

UpSet(t(m)) # 转置图形

UpSet(m[comb_size(m) >= 4])
UpSet(m[comb_degree(m) == 2])
m1 = make_comb_mat(lt) # the default mode is `distinct`

m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")
UpSet(m1)
UpSet(m2)
UpSet(m3)

  使用 upset_top_annotation 修改顶部注释,还可以使用 upset_right_annotation 修改右边的注释。

UpSet(m, comb_order = order(comb_degree(m)), 
      top_annotation =  
        upset_top_annotation(m, # 修改顶部注释

                             gp = gpar(col = comb_degree(m), # 按照comb_degree对边框着色

                                       fill = "gray"), # 填充色

                             axis_param = list(side = "right", # 坐标轴位置('left', 'right', 'top' and 'bottom')

                                               at = c(0, 5, 10, 15), # 刻度

                                               labels = c("zero", "five", "ten", "fifteen")), # 刻度标记

                             annotation_name_rot = 90, # 注释名角度(0, 90, 180, 270)

                             annotation_name_side = "right",
                             ylim = c(0, 15), # y轴范围

                             bar_width = 1), # 柱体宽度

      ) 

ComplexHeatmap-6.3.png

  利用 HeatmapAnnotation 增加额外的注释,下面的代码就比较魔幻了,注意消化。

UpSet(m, top_annotation = HeatmapAnnotation(
  degree = as.character(comb_degree(m)),
  "Intersection\nsize1" = anno_barplot(comb_size(m), 
                                      border = FALSE, 
                                      gp = gpar(fill = "black"), 
                                      height = unit(2, "cm")
  ), 
  annotation_name_side = "left", 
  annotation_name_rot = 0))

UpSet(m, right_annotation = rowAnnotation(
  "Set size2" = anno_barplot(set_size(m), 
                            border = FALSE, 
                            gp = gpar(fill = "black"), 
                            width = unit(2, "cm")
  ),
  group = c("group1", "group1", "group2")))


UpSet(m, left_annotation = rowAnnotation(
  "Set size3" = anno_barplot(set_size(m), 
                            border = FALSE, 
                            gp = gpar(fill = "black"), 
                            width = unit(2, "cm")
  )), right_annotation = NULL)


UpSet(m, left_annotation = rowAnnotation(
  "Set size4" = anno_barplot(set_size(m), 
                            axis_param = list(direction = "reverse"),
                            border = FALSE, 
                            gp = gpar(fill = "black"), 
                            width = unit(2, "cm")
  )), right_annotation = NULL,
  row_names_side = "right")

ComplexHeatmap-6.4.png

当然也是可以和热图进行组合的。

ht = UpSet(m)
ht + Heatmap(1:3, name = "foo", width = unit(5, "mm")) + 
  rowAnnotation(bar = anno_points(1:3))


ht %v% Heatmap(rbind(1:7), name = "foo", row_names_side = "left", 
               height = unit(5, "mm")) %v% 
  HeatmapAnnotation(bar = anno_points(1:7),
                    annotation_name_side = "left")

ComplexHeatmap-6.5.png

m1 = make_comb_mat(lt, mode = "distinct")
m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")
UpSet(m1, row_title = "distinct mode") %v%
  UpSet(m2, row_title = "intersect mode") %v%
  UpSet(m3, row_title = "union mode")

# 利用 anno_lines 达到上图能够反应三组数据的结果

ht = UpSet(m1, top_annotation = HeatmapAnnotation(size = anno_lines(
  cbind(comb_size(m1), comb_size(m2), comb_size(m3)),
  gp = gpar(col = 2:4), height = unit(3, "cm")
)))
# you need to manually construct a legend

draw(ht, annotation_legend_list = list(Legend(
  title = "mode",
  type = "lines",
  labels = c("distinct", "intersect", "union"),
  legend_gp = gpar(col = 2:4)
))
)

ComplexHeatmap-6.6.png

7 Density heatmap

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)

# 配置参数

densityHeatmap(m, 
               col = topo.colors(10), # 颜色

               # column_order = sample(20, 20), # 列重排序

               cluster_columns = TRUE, # 列聚类

               clustering_distance_columns = "ks", #列距离计算方法

               title = "Distribution as heatmap", # 标题

               ylim = c(-2, 2), # y轴范围

               ylab = "some values") # y轴标题

ComplexHeatmap-7.1.png

# 增加注释

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)

# 与热图组合

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

ComplexHeatmap-7.2.png

8 More Examples

8.1 Add more information for gene expression matrix

rm(list = ls())
library(ComplexHeatmap)
library(circlize)

expr = readRDS(system.file(package = "ComplexHeatmap", "extdata", "gene_expression.rds"))
mat = as.matrix(expr[, grep("cell", colnames(expr))])
base_mean = rowMeans(mat)
mat_scaled = t(apply(mat, 1, scale))

type = gsub("s\\d+_", "", colnames(mat))
ha = HeatmapAnnotation(type = type, annotation_name_side = "left")

ht_list = Heatmap(mat_scaled, name = "expression", row_km = 5, 
                  col = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red")),
                  top_annotation = ha, 
                  show_column_names = FALSE, row_title = NULL, show_row_dend = FALSE) +
  Heatmap(base_mean, name = "base mean", 
          top_annotation = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:6), 
                                                                    height = unit(2, "cm"))),
          width = unit(15, "mm")) +
  rowAnnotation(length = anno_points(expr$length, pch = 16, size = unit(1, "mm"), 
                                     axis_param = list(at = c(0, 2e5, 4e5, 6e5), 
                                                       labels = c("0kb", "200kb", "400kb", "600kb")),
                                     width = unit(2, "cm"))) +
  Heatmap(expr$type, name = "gene type", 
          top_annotation = HeatmapAnnotation(summary = anno_summary(height = unit(2, "cm"))),
          width = unit(15, "mm"))

ht_list = rowAnnotation(block = anno_block(gp = gpar(fill = 2:6, col = NA)), 
                        width = unit(2, "mm")) + ht_list

draw(ht_list, ht_gap = unit(5, "mm"))

ComplexHeatmap-8.1.png

8.2 The measles vaccine heatmap

mat = readRDS(system.file("extdata", "measles.rds", package = "ComplexHeatmap"))
ha1 = HeatmapAnnotation(
  dist1 = anno_barplot(
    colSums(mat), 
    bar_width = 1, 
    gp = gpar(col = "white", fill = "#FFE200"), 
    border = FALSE,
    axis_param = list(at = c(0, 2e5, 4e5, 6e5, 8e5),
                      labels = c("0", "200k", "400k", "600k", "800k")),
    height = unit(2, "cm")
  ), show_annotation_name = FALSE)
ha2 = rowAnnotation(
  dist2 = anno_barplot(
    rowSums(mat), 
    bar_width = 1, 
    gp = gpar(col = "white", fill = "#FFE200"), 
    border = FALSE,
    axis_param = list(at = c(0, 5e5, 1e6, 1.5e6),
                      labels = c("0", "500k", "1m", "1.5m")),
    width = unit(2, "cm")
  ), show_annotation_name = FALSE)
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_list = Heatmap(mat, name = "cases", col = col_fun,
                  cluster_columns = FALSE, show_row_dend = FALSE, rect_gp = gpar(col= "white"), 
                  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',
                  top_annotation = ha1, bottom_annotation = ha_column,
                  heatmap_legend_param = list(at = c(0, 5e4, 1e5, 1.5e5), 
                                              labels = c("0", "50k", "100k", "150k"))) + ha2
draw(ht_list, ht_gap = unit(3, "mm"))
decorate_heatmap_body("cases", {
  i = which(colnames(mat) == "1961")
  x = i/ncol(mat)
  grid.lines(c(x, x), c(0, 1), gp = gpar(lwd = 2, lty = 2))
  grid.text("Vaccine introduced", x, unit(1, "npc") + unit(5, "mm"))
})

ComplexHeatmap-8.2.png

8.3 Visualize Cell Heterogeneity from Single Cell RNASeq

rm(list = ls())
library(ComplexHeatmap)

expr = read.table("mouse_scRNAseq_corrected.txt", sep = "\t", header = TRUE,row.names = 1)
expr = t(expr)

expr = expr[apply(expr, 1, function(x) sum(x > 0)/length(x) > 0.5), , drop = FALSE]

get_correlated_variable_genes = function(mat, n = nrow(mat), cor_cutoff = 0, n_cutoff = 0) {
  ind = order(apply(mat, 1, function(x) {
    q = quantile(x, c(0.1, 0.9))
    x = x[x < q[1] & x > q[2]]
    var(x)/mean(x)
  }), decreasing = TRUE)[1:n]
  mat2 = mat[ind, , drop = FALSE]
  dt = cor(t(mat2), method = "spearman")
  diag(dt) = 0
  dt[abs(dt) < cor_cutoff] = 0
  dt[dt < 0] = -1
  dt[dt > 0] = 1
  
  i = colSums(abs(dt)) > n_cutoff
  
  mat3 = mat2[i, ,drop = FALSE]
  return(mat3)
}

mat = get_correlated_variable_genes(expr, cor_cutoff = 0.5, n_cutoff = 20)
mat2 = t(apply(mat, 1, function(x) {
  q10 = quantile(x, 0.1)
  q90 = quantile(x, 0.9)
  x[x < q10] = q10
  x[x > q90] = q90
  scale(x)
}))
colnames(mat2) = colnames(mat)

cc = readRDS("mouse_cell_cycle_gene.rds")
ccl = rownames(mat) %in% cc
cc_gene = rownames(mat)[ccl]

rp = readRDS("mouse_ribonucleoprotein.rds")
rpl = rownames(mat) %in% rp

base_mean = rowMeans(mat)

library(GetoptLong)
ht_list = Heatmap(mat2, col = circlize::colorRamp2(c(-1.5, 0, 1.5), c("blue", "white", "red")), 
                  name = "scaled_expr", column_title = qq("relative expression for @{nrow(mat)} genes"),
                  show_column_names = FALSE, width = unit(8, "cm"),
                  heatmap_legend_param = list(title = "Scaled expr")) +
  Heatmap(base_mean, name = "base_expr", width = unit(5, "mm"),
          heatmap_legend_param = list(title = "Base expr")) +
  Heatmap(rpl + 0, name = "ribonucleoprotein", col = c("0" = "white", "1" = "purple"), 
          show_heatmap_legend = FALSE, width = unit(5, "mm")) +
  Heatmap(ccl + 0, name = "cell_cycle", col = c("0" = "white", "1" = "red"), 
          show_heatmap_legend = FALSE, width = unit(5, "mm")) +
  rowAnnotation(link = anno_mark(at = which(ccl & base_mean > quantile(base_mean, 0.25)), 
                                 labels = rownames(mat)[ccl & base_mean > quantile(base_mean, 0.25)], 
                                 labels_gp = gpar(fontsize = 10), padding = unit(1, "mm"))) +
  Heatmap(cor(t(mat2)), name = "cor", 
          col = circlize::colorRamp2(c(-1, 0, 1), c("green", "white", "red")), 
          show_row_names = FALSE, show_column_names = FALSE, row_dend_side = "right", 
          show_column_dend = FALSE, column_title = "pairwise correlation between genes",
          heatmap_legend_param = list(title = "Correlation"))
ht_list = draw(ht_list, main_heatmap = "cor")
decorate_column_dend("scaled_expr", {
  tree = column_dend(ht_list)$scaled_expr
  ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]
  
  first_index = function(l) which(l)[1]
  last_index = function(l) { x = which(l); x[length(x)] }
  x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
  x2 = c(last_index(ind == 1), last_index(ind == 2))
  grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
            default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})

ComplexHeatmap-8.3.png

8.4 Correlations between methylation, expression and other genomic features

rm(list = ls())
library(ComplexHeatmap)

res_list = readRDS("meth.rds")
type = res_list$type
mat_meth = res_list$mat_meth
mat_expr = res_list$mat_expr
direction = res_list$direction
cor_pvalue = res_list$cor_pvalue
gene_type = res_list$gene_type
anno_gene = res_list$anno_gene
dist = res_list$dist
anno_enhancer = res_list$anno_enhancer


column_tree = hclust(dist(t(mat_meth)))
column_order = column_tree$order

library(RColorBrewer)
meth_col_fun = circlize::colorRamp2(c(0, 0.5, 1), c("blue", "white", "red"))
direction_col = c("hyper" = "red", "hypo" = "blue")
expr_col_fun = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red"))
pvalue_col_fun = circlize::colorRamp2(c(0, 2, 4), c("white", "white", "red"))
gene_type_col = structure(brewer.pal(length(unique(gene_type)), "Set3"), 
                          names = unique(gene_type))
anno_gene_col = structure(brewer.pal(length(unique(anno_gene)), "Set1"), 
                          names = unique(anno_gene))
dist_col_fun = circlize::colorRamp2(c(0, 10000), c("black", "white"))
enhancer_col_fun = circlize::colorRamp2(c(0, 1), c("white", "orange"))


ht_opt(
  legend_title_gp = gpar(fontsize = 8, fontface = "bold"), 
  legend_labels_gp = gpar(fontsize = 8), 
  heatmap_column_names_gp = gpar(fontsize = 8),
  heatmap_column_title_gp = gpar(fontsize = 10),
  heatmap_row_title_gp = gpar(fontsize = 8)
)

ha = HeatmapAnnotation(type = type, 
                       col = list(type = c("Tumor" = "pink", "Control" = "royalblue")),
                       annotation_name_side = "left")
ha2 = HeatmapAnnotation(type = type, 
                        col = list(type = c("Tumor" = "pink", "Control" = "royalblue")), 
                        show_legend = FALSE)

ht_list = Heatmap(mat_meth, name = "methylation", col = meth_col_fun,
                  column_order= column_order,
                  top_annotation = ha, column_title = "Methylation") +
  Heatmap(direction, name = "direction", col = direction_col) +
  Heatmap(mat_expr[, column_tree$order], name = "expression", 
          col = expr_col_fun, 
          column_order = column_order, 
          top_annotation = ha2, column_title = "Expression") +
  Heatmap(cor_pvalue, name = "-log10(cor_p)", col = pvalue_col_fun) +
  Heatmap(gene_type, name = "gene type", col = gene_type_col) +
  Heatmap(anno_gene, name = "anno_gene", col = anno_gene_col) +
  Heatmap(dist, name = "dist_tss", col = dist_col_fun) +
  Heatmap(anno_enhancer, name = "anno_enhancer", col = enhancer_col_fun, 
          cluster_columns = FALSE, column_title = "Enhancer")

draw(ht_list, row_km = 2, row_split = direction,
     column_title = "Comprehensive correspondence between methylation, expression and other genomic features", 
     column_title_gp = gpar(fontsize = 12, fontface = "bold"), 
     merge_legends = TRUE, heatmap_legend_side = "bottom")

ht_opt(RESET = TRUE)

ComplexHeatmap-8.4.png

8.5 Add multiple boxplots for single row

m1 = matrix(sort(rnorm(100)), 10, byrow = TRUE)
m2 = matrix(sort(rnorm(100), decreasing = TRUE), 10, byrow = TRUE)
nr = nrow(m1)

ht_list = Heatmap(m1, name = "m1") + Heatmap(m2, name = "m2")

rg = range(c(m1, m2))
rg[1] = rg[1] - (rg[2] - rg[1])* 0.02
rg[2] = rg[2] + (rg[2] - rg[1])* 0.02
anno_multiple_boxplot = function(index) {
  pushViewport(viewport(xscale = rg, yscale = c(0.5, nr + 0.5)))
  for(i in seq_along(index)) {
    grid.rect(y = nr-i+1, height = 1, default.units = "native")
    grid.boxplot(m1[ index[i], ], pos = nr-i+1 + 0.2, box_width = 0.3, 
                 gp = gpar(fill = "red"), direction = "horizontal")
    grid.boxplot(m2[ index[i], ], pos = nr-i+1 - 0.2, box_width = 0.3, 
                 gp = gpar(fill = "green"), direction = "horizontal")
  }
  grid.xaxis()
  popViewport()
}

ht_list = ht_list + rowAnnotation(boxplot = anno_multiple_boxplot, width = unit(4, "cm"), 
                                  show_annotation_name = FALSE)
lgd = Legend(labels = c("m1", "m2"), title = "boxplots",
             legend_gp = gpar(fill = c("red", "green")))
draw(ht_list, padding = unit(c(20, 2, 2, 2), "mm"), heatmap_legend_list = list(lgd))

ComplexHeatmap-8.5.png


参考资料:
1.ComplexHeatmap Complete Reference
2.【r<-包】ComplexHeatmap(1):介绍
3.【r<-包】ComplexHeatmap(2):创建一个简单的热图
4.【r<-包】ComplexHeatmap(3):创建热图列表
5.【r<-包】ComplexHeatmap(4):热图注释
6.【r<-包】ComplexHeatmap(5):热图和注释图例
7.使用ComplexHeatmap包绘制热图
8.ComplexHeatmap包更新支持pheatmap转换