我們今天學(xué)習(xí)如何利用complexheatmap添加縮放和鏈接注釋服鹅,以及如何加入詞云圖等逻卖。
前面我們測(cè)試過(guò)粘捎,熱圖中有很多行或列形纺,但是我們只想標(biāo)記其中的一些情況丘侠,用的是anno_mark。anno_mark()用于標(biāo)記行或列的子集并用線連接到標(biāo)簽挡篓。anno_mark()至少需要兩個(gè)參數(shù):at、labels帚称,其中at是原始矩陣的索引和labels相應(yīng)的文本官研。
library(ComplexHeatmap)
library(circlize)
library(dendextend)
library(patchwork)
library(wordcloud)
library(simplifyEnrichment)
m = matrix(rnorm(1000), nrow = 100)
rownames(m) = 1:100
ha = rowAnnotation(foo = anno_mark(at = c(1:4, 20, 60, 97:100), labels = month.name[1:10]))
Heatmap(m, name = "mat", cluster_rows = FALSE, right_annotation = ha,
? ? row_names_side = "left", row_nam
但是,anno_mark()將熱圖上的單行或單列連接到標(biāo)簽闯睹,如果我們想多行或者多列鏈接到標(biāo)簽怎么辦戏羽? 注釋功能anno_link()將行或列的子集連接到可以添加更全面圖形的繪圖區(qū)域。
set.seed(123)
m = matrix(rnorm(100*10), nrow = 100)
subgroup = sample(letters[1:3], 100, replace = TRUE, prob = c(1, 5, 10))
rg = range(m)
panel_fun = function(index, nm) {
? ? pushViewport(viewport(xscale = rg, yscale = c(0, 2)))
? ? grid.rect()
? ? grid.xaxis(gp = gpar(fontsize = 8))
? ? grid.boxplot(m[index, ], pos = 1, direction = "horizontal")
? ? popViewport()
}
anno = anno_link(align_to = subgroup, which = "row", panel_fun = panel_fun,
? ? size = unit(2, "cm"), gap = unit(1, "cm"), width = unit(4, "cm"))
Heatmap(m, name = "mat", right_annotation = rowAnnotation(foo = anno), row_split = subgroup)
anno_link()的重要參數(shù)是:
align_to:它定義了繪圖區(qū)域(或框)如何對(duì)應(yīng)于熱圖中的行或列楼吃。如果該值是一個(gè)索引列表始花,則每個(gè)框?qū)?yīng)于列表中一個(gè)向量中帶有索引的行或列妄讯。如果該值是與熱圖中的行或列具有相同長(zhǎng)度的分類變量(例如因子或字符向量),則每個(gè)框?qū)?yīng)于分類變量中每個(gè)級(jí)別的行/列酷宵。
panel_fun: 自定義函數(shù)亥贸,定義如何在框中繪制圖形。該函數(shù)必須有一個(gè)index參數(shù)浇垦,它是框?qū)?yīng)的行/列的索引炕置。它可以有第二個(gè)參數(shù)nm,即熱圖中所選部分的“名稱”男韧。如果將其指定為分類變量或帶有名稱的列表朴摊,則對(duì)應(yīng)的值nm來(lái)自align_to。
size: 盒子的大小此虑。它們可以是純數(shù)字甚纲,它們被視為熱圖總高度/寬度的相對(duì)分?jǐn)?shù)。size的值也可以是絕對(duì)單位朦前。
gap: 盒子之間的間隙介杆。它應(yīng)該是一個(gè)unit對(duì)象。
=======詞云圖======
set.seed(123)
words = sapply(1:30, function(x) strrep(sample(letters, 1), sample(3:10, 1)))
fontsize = runif(30, min = 5, max = 30)
library(grid)
gb = word_cloud_grob(words, fontsize = fontsize, max_width = unit(100, "mm"))
grid.newpage()
grid.draw(gb)
grid.rect(width = grobWidth(gb), height = grobHeight(gb), gp = gpar(fill = NA))
#上面是個(gè)最基本的詞云圖况既。單詞按字體的大小排序这溅,隨機(jī)分配顏色。這里的max_width參數(shù)控制框的“最大寬度”棒仍。
#可以通過(guò)col來(lái)改變顏色
gb = word_cloud_grob(words, fontsize = fontsize, max_width = unit(100, "mm"), col = 1:30)
grid.newpage()
grid.draw(gb)
grid.rect(width = grobWidth(gb), height = grobHeight(gb), gp = gpar(fill = NA))
#可以自己制定任何形式的col
library(circlize)
col_fun = colorRamp2(c(5, 17, 30), c("blue", "black", "red"))
gb = word_cloud_grob(words, fontsize = fontsize, max_width = unit(100, "mm"),
? ? col = col_fun)
grid.newpage()
grid.draw(gb)
grid.rect(width = grobWidth(gb), height = grobHeight(gb), gp = gpar(fill = NA))
=====詞云圖作為heatmap注釋======
gb = word_cloud_grob(words, fontsize = fontsize, max_width = unit(100, "mm"))
gb_h = grobHeight(gb)? ?#獲得詞云圖的高度
gb_w = grobWidth(gb)? #獲得詞云圖的寬度
m = matrix(rnorm(100), 10)
ht = Heatmap(m, cluster_rows = FALSE)
ht
panel_fun = function(index, nm) {
? ? grid.rect(gp = gpar(fill = "#EEEEEE", col = NA))
? ? grid.draw(gb)
}
ht + rowAnnotation(word_cloud = anno_link(align_to = 1:3, which = "row",
? ? ? ? panel_fun = panel_fun, size = gb_h,
? ? ? ? width = gb_w + unit(5, "mm"), # the link is 5mm
? ? ? ? link_gp = gpar(fill = "#EEEEEE", col = NA)
? ? ))
=========實(shí)例測(cè)試=========
tmp_file = tempfile()
download.file("https://jokergoo.github.io/word_cloud_annotation_example.RData", destfile = tmp_file, quiet = TRUE)
load(tmp_file)
mat[1:6, 1:6]
#先做一個(gè)基本的heatmap
Heatmap(mat, col = colorRamp2(c(0, 1), c("white", "red")),
? ? name = "Similarity",
? ? show_row_names = FALSE, show_column_names = FALSE,
? ? show_row_dend = FALSE, show_column_dend = FALSE,
? ? row_split = cl, column_split = cl,
? ? border = "#404040", row_title = NULL, column_title = NULL,
? ? row_gap = unit(0, "mm"), column_gap = unit(0, "mm"))
ht = Heatmap(mat, col = colorRamp2(c(0, 1), c("white", "red")),
? ? name = "Similarity",
? ? show_row_names = FALSE, show_column_names = FALSE,
? ? show_row_dend = FALSE, show_column_dend = FALSE,
? ? row_split = cl, column_split = cl,
? ? border = "#404040", row_title = NULL, column_title = NULL,
? ? row_gap = unit(0, "mm"), column_gap = unit(0, "mm"))
#首先獲得分組信息
align_to = split(seq_len(nrow(mat)), cl)
align_to = align_to[names(align_to) != "0"]
align_to = align_to[names(align_to) %in% names(keywords)]
align_to
#獲得每個(gè)組的注釋信息
fontsize_range = c(4, 16)
gbl = lapply(names(align_to), function(nm) {
? ? kw = keywords[[nm]][, 1]
? ? freq = keywords[[nm]][, 2]
? ? fontsize = scale_fontsize(freq, rg = c(1, max(10, freq)), fs = fontsize_range)
? ? word_cloud_grob(text = kw, fontsize = fontsize)
})
names(gbl) = names(align_to)
gbl
#獲得每個(gè)組的寬度和高度信息
margin = unit(8, "pt")
gbl_h = lapply(gbl, function(x) convertHeight(grobHeight(x), "cm") + margin)
gbl_h = do.call(unit.c, gbl_h)
gbl_w = lapply(gbl, function(x) convertWidth(grobWidth(x), "cm"))
gbl_w = do.call(unit.c, gbl_w)
gbl_w = max(gbl_w) + margin
panel_fun = function(index, nm) {
? ? # background
? ? grid.rect(gp = gpar(fill = "#DDDDDD", col = NA))
? ? # border
? ? grid.lines(c(0, 1, 1, 0), c(0, 0, 1, 1), gp = gpar(col = "#AAAAAA"),
? ? ? ? default.units = "npc")
? ? gb = gbl[[nm]]
? ? # a viewport within the margins
? ? pushViewport(viewport(x = margin/2, y = margin/2,
? ? ? ? width = grobWidth(gb), height = grobHeight(gb),
? ? ? ? just = c("left", "bottom")))
? ? grid.draw(gb)
? ? popViewport()
}
ht = ht + rowAnnotation(keywords = anno_link(align_to = align_to,
? ? which = "row", panel_fun = panel_fun,
? ? size = gbl_h, gap = unit(2, "mm"),
? ? width = gbl_w + unit(5, "mm"), # 5mm for the link
? ? link_gp = gpar(fill = "#DDDDDD", col = "#AAAAAA"),
? ? internal_line = FALSE)) # you can set it to TRUE to see what happens
draw(ht, ht_gap = unit(2, "pt"))