查看原文
其他

你要的 ComplexHeatmap TA 来了!

JunJunLab 老俊俊的生信笔记 2022-08-15


点击上方「蓝字」关注我们



介绍


ComplexHeatmap 包是一个非常强大的 绘制热图利器 !他的设计灵感来自于 pheatmap 这个包,作者是 顾祖光博士 ,当然 circlize 包也是这位大佬开发的,他的介绍我在写介绍 circlize 包时介绍过。

作者顾祖光南京大学博士毕业,现在在德国癌症研究中心工作,是一名生信研究员,研究领域有基因组学、表观组学、开发软件、可视化等等。其中 ComlexHeatmapEnrichedHeatmapsimplifyEnrichment 等强大的 R 包都是他开发的,大佬!

安装方式:

BiocManager::install("ComplexHeatmap")

# 安装最新版
library(devtools)
install_github("jokergoo/ComplexHeatmap")

总体设计:

单个热图由 热图主体热图组件 组成。热图主体可以 按行和列分割 。热图组件包括标题树状图矩阵名称热图注释,它们被放置在主体的四面。

热图列表 由一系列的热图和注释组成,标题和注释围绕在热图四周。对于热图列表来说,一个重要的点是所有热图和注释的 行/列 都要进行调整,以便所有热图和注释中的同一 行/列 对应于相同的特征。

此外热图列表也可以按行和列进行分割。

作品展示:


ComplexHeatmap 包是以面向对象的方式实现的。要描述一个热图列表,有以下类:

  • Heatmap 类:包含热图主体、行/列名称、标题、树状图和行/列注释的单个热图。
  • HeatmapList 类:热图列表和热图注释列表。
  • HeatmapAnnotation 类:定义行注释和列注释的列表。热图注释可以是热图的组件,也可以是独立的。

其它的内部类:

  • SingleAnnotation 类:定义单个行注释或列注释。HeatmapAnnotation 对象包含一个 SingleAnnotation 对象列表。
  • ColorMapping 类:从值到颜色的映射。主矩阵的颜色映射和注释由 ColorMapping 类控制。
  • AnnotationFunction 类:构建自定义的注释。这是创建用户定义的注释图形的基础。
内容概要

内容太多,我会选择性的选择关于 热图 的主要部分介绍。

  • 1、A Single Heatmap
  • 2、Heatmap Annotations
  • 3、A List of Heatmaps
  • 4、Legends
  • 5、Heatmap Decoration
  • 6、OncoPrint
  • 7、UpSet plot
  • 8、Other High-level Plots
  • 9、Integrate with other packages
  • 10、Interactive heatmap
  • 11、More Examples


A Single Heatmap


构造矩阵数据:

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)] # random shuffle rows and columns
rownames(mat) = paste0("row", seq_len(nr))
colnames(mat) = paste0("column", seq_len(nc))

# 查看内容
head(mat,3)

       column1     column2   column3    column4   column5   column6    column7    column8
row1 0.9047416 -0.35229823 0.5016096 1.26769942 0.8251229 0.1621522 -0.2869867  0.6803262
row2 0.9088297  0.79157121 1.0726316 0.01299521 0.1391978 0.4683369  1.2814948  0.3899826
row3 0.2807467  0.02987497 0.7052595 1.21514235 0.1747267 0.2094912 -0.6423579 -0.3139530
        column9   column10  column11   column12   column13   column14   column15  column16
row1 -0.1629658  0.8254537 0.7821773 -0.4962536 -0.0895258 -0.3552033  0.1072694 0.9632220
row2 -0.3473535  1.3508922 1.1183375  2.0500545  1.3770269 -0.7743764  0.9829664 0.2385438
row3  0.2175907 -0.2973086 0.4322058 -0.2580319 -0.5686518 -0.5132105 -0.0451598 0.8227288
        column17   column18  column19  column20   column21   column22  column23  column24
row1 -0.39245223 -0.1878014 1.0873632 0.7132199 -0.1853300 -0.1423865 0.6407669 1.3266288
row2 -0.53589561  1.3003544 0.1423789 0.4471643  0.4475628 -0.3125196 0.7057150 0.8120937
row3 -0.02251386  0.2427300 1.0951152 0.5852612  0.1926402  0.5127857 1.6361334 1.1339175

默认绘制热图:

Heatmap(mat)

1、颜色

使用 circlize 包的 colorRamp2 函数生成颜色:

library(circlize)
col_fun = colorRamp2(c(-202), c("green""white""red"))
col_fun(seq(-33))
## [1] "#00FF00FF" "#00FF00FF" "#B1FF9AFF" "#FFFFFFFF" "#FF9E81FF" "#FF0000FF"
## [7] "#FF0000FF"

Heatmap(mat, name = "mat", col = col_fun)

颜色映射函数精确地将负值映射为绿色,将正值映射为红色,即使负值和正值的分布不是以零为中心。此外,这种颜色映射功能不受异常值的影响。在下面的图中,聚类严重受离群值的影响(见树形图),但不受颜色映射的影响:

mat2 = mat
mat2[11] = 100000
Heatmap(mat2, name = "mat", col = col_fun,
    column_title = "a matrix with outliers")

colorRamp2()使多个热图中的颜色具有 可比性 ,如果它们使用 相同的颜色映射函数设置。在下面的三个热图中,相同的颜色总是对应着相同的值:

Heatmap(mat, name = "mat", col = col_fun, column_title = "mat")
Heatmap(mat/4, name = "mat", col = col_fun, column_title = "mat/4")
Heatmap(abs(mat), name = "mat", col = col_fun, column_title = "abs(mat)")

如果矩阵是连续的,你也可以简单地提供一个颜色向量,颜色将被线性插值。但是,这种方法对异常值并不有效,因为映射从矩阵中的 最小值 开始,以 最大值 结束。下面的颜色映射设置与colorRamp2(seq(min(mat), max(mat), length = 10), rev(rainbow(10))) 相同:

Heatmap(mat, name = "mat", col = rev(rainbow(10)),
    column_title = "set a color vector for a continuous matrix")

如果矩阵包含离散值(数字或字符),则颜色应指定为命名向量,以使离散值与颜色之间的可以映射。如果颜色没有名称,颜色的顺序对应于 unique(mat) 的顺序。注意,现在图例是由颜色映射向量生成的:

discrete_mat = matrix(sample(1:4100, replace = TRUE), 1010)
head(discrete_mat,3)
##     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    4    1    2    2    2    4    1    2    3     2
## [2,]    4    3    4    1    2    4    3    1    3     3
## [3,]    1    4    3    2    3    1    4    3    2     1

colors = structure(1:4, names = c("1""2""3""4")) # black, red, green, blue
colors
## 1 2 3 4
## 1 2 3 4
Heatmap(discrete_mat, name = "mat", col = colors,
    column_title = "a discrete numeric matrix")

或者字符矩阵:

discrete_mat = matrix(sample(letters[1:4], 100, replace = TRUE), 1010)
head(discrete_mat,3)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] "b"  "b"  "b"  "b"  "b"  "b"  "a"  "d"  "c"  "b"
## [2,] "a"  "b"  "b"  "d"  "a"  "b"  "b"  "c"  "b"  "d"
## [3,] "c"  "b"  "a"  "d"  "b"  "b"  "d"  "c"  "b"  "a"
colors = structure(1:4, names = letters[1:4])
## a b c d
## 1 2 3 4
Heatmap(discrete_mat, name = "mat", col = colors,
    column_title = "a discrete character matrix")

NA 在矩阵中是允许的。你可以通过 na_col 参数控制 NA 的颜色(默认情况下,NA 为 灰色 )。一个包含 NA 的矩阵可以被 Heatmap()聚类,只要在任何行或列之间没有 NA 距离。通常这些情况对应的是稀疏矩阵(填充了大量的 NA 值),表明未知值需要先通过其他方法进行预测。

NA 值不会显示在图例中:

mat_with_na = mat
na_index = sample(c(TRUEFALSE), nrow(mat)*ncol(mat), replace = TRUE, prob = c(19))
mat_with_na[na_index] = NA
head(mat_with_na[1:3,1:5],3)
##        column1     column2   column3  column4   column5
## row1 0.9047416 -0.35229823        NA 1.267699 0.8251229
## row2 0.9088297  0.79157121 1.0726316       NA 0.1391978
## row3 0.2807467  0.02987497 0.7052595 1.215142 0.1747267
Heatmap(mat_with_na, name = "mat", na_col = "black",
    column_title = "a matrix with NA values")

颜色空间对于插值颜色很重要。默认情况下,颜色在 LAB color space 中是线性插值的,但您可以在 colorRamp2() 函数中选择颜色空间:

f1 = colorRamp2(seq(min(mat), max(mat), length = 3), c("blue""#EEEEEE""red"))
f2 = 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")

颜色在不同的颜色空间的变化:

使用 border_gp 参数结合 grid::gpar() 函数控制热图主体边框:

Heatmap(mat, name = "mat", border_gp = gpar(col = "black", lty = 2),
    column_title = "set heatmap borders")

使用 rect_gp 参数结合 grid::gpar() 函数控制热图单元格边框:

Heatmap(mat, name = "mat", rect_gp = gpar(col = "white", lwd = 2),
    column_title = "set cell borders")

如果 col 颜色参数没有设置,则会使用默认颜色 ComplexHeatmap:::default_col() ,如果是字符矩阵,则使用 circlize::rand_color()

rect_gp 允许使用非标准参数类型。如果将其设置为 “none” ,则仍会聚类,但不会在热图主体上绘制任何内容。热图主体上的自定义图形可以通过自定义的 cell_funlayer_fun 添加:

Heatmap(mat, name = "mat", rect_gp = gpar(type = "none"),
    column_title = "nothing is drawn in the heatmap body")

2、标题

图形参数可以分别由 row_title_gpcolumn_title_gp 设置。记住,应该使用 gpar 来指定图形参数:

Heatmap(mat, name = "mat", column_title = "I am a column title",
    row_title = "I am a row title")

column_title_side 参数放置于底部:

Heatmap(mat, name = "mat", column_title = "I am a column title at the bottom",
    column_title_side = "bottom")

column_title_gp 设置样式:

Heatmap(mat, name = "mat", column_title = "I am a big column title",
    column_title_gp = gpar(fontsize = 20, fontface = "bold"))

标题的旋转可以通过 row_title_rotcolumn_title_rot 设置,但只允许 水平垂直 旋转:

Heatmap(mat, name = "mat", row_title = "row title", row_title_rot = 0)

使用 fillcolboder 参数控制标题样式:

Heatmap(mat, name = "mat", column_title = "I am a column title",
    column_title_gp = gpar(fill = "red", col = "white", border = "blue"))

ht_opt$TITLE_PADDING 控制标题与边框顶部距离:

ht_opt$TITLE_PADDING = unit(c(8.58.5), "points")
Heatmap(mat, name = "mat", column_title = "I am a column title",
    column_title_gp = gpar(fill = "red", col = "white", border = "blue"))

# 重置
ht_opt(RESET = TRUE)

使用表达式或公式:

Heatmap(mat, name = "mat",
    column_title = expression(hat(beta) == (X^t * X)^{-1} * X^t * y))

3、聚类

关闭横向聚类:

Heatmap(mat, name = "mat", cluster_rows = FALSE# turn off row clustering

关闭列聚类:

Heatmap(mat, name = "mat", show_column_dend = FALSE# hide column dendrogram

改变聚类树的位置:

Heatmap(mat, name = "mat", row_dend_side = "right", column_dend_side = "bottom")

调整聚类树高度:

Heatmap(mat, name = "mat", column_dend_height = unit(4"cm"),
    row_dend_width = unit(4"cm"))
计算距离方法

层次聚类分两步执行:计算距离矩阵和聚类。可以通过三种方式为聚类指定距离矩阵:

  • 1、将距离指定为预定义选项:有效值是 dist() 函数和 pearsonspearmankendall 中支持的方法。相关距离定义为 1 - cor(x, y, method)。所有这些内置距离方法都允许含有 NA 值。
  • 2、自定义函数:用于计算到矩阵的距离。函数应该只包含一个参数。请注意在列上聚类,矩阵将自动转置。
  • 3、一个自定义的函数:用来计算两个向量之间的距离。函数应该只包含两个参数。注意,这可能很慢,因为它是由两个嵌套的 for 循环实现的。

指定距离方法:

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

对含有异常值的数据使用自定义函数计算距离:

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.10.9))
    qy = quantile(y, c(0.10.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))
}

比较:

Heatmap(mat_with_outliers, name = "mat",
    col = colorRamp2(c(-202), c("green""white""red")),
    column_title = "dist")
Heatmap(mat_with_outliers, name = "mat",
    col = colorRamp2(c(-202), c("green""white""red")),
    clustering_distance_rows = robust_dist,
    clustering_distance_columns = robust_dist,
    column_title = "robust_dist")

如果有合适的距离方法(如 stringdist 包中的方法),也可以对字符矩阵进行聚类:

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)
    })
聚类方法

可以通过 clustering_method_rowsclustering_method_columns 指定执行层次聚类的方法。可以的方法是 hclust() 函数支持的方法。

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

如果你已经有一个聚类对象或一个直接返回一个聚类对象的函数,你可以忽略距离设置并将 cluster_rowscluster_columns 设置为聚类对象或聚类函数。如果它是一个聚类函数,唯一的参数应该是矩阵,它应该返回一个 hclustdendrogram 对象或一个可以转换为 dendrogram 类的对象。

在以下示例中,我们通过预先计算的聚类对象或聚类函数使用 cluster 包中的方法执行聚类:

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

上面命令和下面代码等价:

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

请注意,当 cluster_rows 设置为函数时,参数 m 是输入 mat 本身,而对于 cluster_columns,m 是 mat 的转置。

这是一种特殊情况,你可能已经对矩阵行或列进行了分类,而只想对同一组中的执行聚类。可以通过分组变量拆分热图,也可以使用 cluster_within_group() 聚类函数生成特殊的树状图:

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

在上面的例子中,同一组中的列仍然是聚类的,但是树状图变为为一条扁平线。列上的树状图显示了组的层次结构。

渲染聚类树

如果要渲染树状图,通常需要生成一个 dendrogram 对象,并提前通过 nodeParedgePar 参数渲染,然后将其发送到 cluster_rowscluster_columns 参数。

可以通过 dendextend 包渲染树状图对象,以对树状图进行更自定义的可视化:

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)

row_dend_gpcolumn_dend_gp 控制树状图的全局图形设置。注意:例如 row_dend 中的图形设置将被 row_dend_gp 覆盖:

Heatmap(mat, name = "mat", cluster_rows = row_dend, row_dend_gp = gpar(col = "red"))

从 2.5.6 版本开始,您还可以通过设置适当的 nodePar 在树状图的节点上添加图形:

row_dend = dendrapply(row_dend, function(d) {
    attr(d, "nodePar") = list(cex = 0.8, pch = sample(201), col = rand_color(1))
    return(d)
})
Heatmap(mat, name = "mat", cluster_rows = row_dend, row_dend_width = unit(2"cm"))
树状图重新排序

row_dend_reordercolumn_dend_reorder 控制是否把树状图重新排序。如果这两个参数设置为 数字向量 ,则它们还控制重新排序的权重(它将被发送到 reorder.dendrogram()wts 参数)。可以通过设置例如:关闭重新排序 row_dend_reorder = FALSE

默认情况下,如果 cluster_rows/cluster_columns 设置为 逻辑值聚类函数,则树状图重新排序将打开。如果 cluster_rows/cluster_columns 设置为 聚类对象,则关闭:

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 包。基本上,所有这些方法仍然返回一个经过重新排序的树状图对象,因此,我们可以首先根据数据矩阵生成行或列树状图,通过某种方法重新排序,并将其分配回 cluster_rowscluster_columns

Heatmap(mat, name = "mat", column_title = "default reordering")

library(dendsort)
row_dend = dendsort(hclust(dist(mat)))
col_dend = dendsort(hclust(dist(t(mat))))
Heatmap(mat, name = "mat", cluster_rows = row_dend, cluster_columns = col_dend,
    column_title = "reorder by dendsort")

收官!


代码 我上传到 QQ 群 老俊俊生信交流群 文件夹里。欢迎加入。加我微信我也拉你进 微信群聊 老俊俊生信交流群 哦。

群二维码:


老俊俊微信:




知识星球:



所以今天你学习了吗?

欢迎小伙伴留言评论!

今天的分享就到这里了,敬请期待下一篇!

最后欢迎大家分享转发,您的点赞是对我的鼓励肯定

如果觉得对您帮助很大,赏杯快乐水喝喝吧!

推 荐 阅 读




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存