熱圖在單細(xì)胞數(shù)據(jù)分析中的應(yīng)用

什么是熱圖狭莱?

熱圖是一個(gè)以顏色變化來(lái)顯示數(shù)據(jù)的可視化矩陣鹅髓,Toussaint Loua在1873年就曾使用過(guò)熱圖來(lái)繪制對(duì)巴黎各區(qū)的社會(huì)學(xué)統(tǒng)計(jì)筐带。我們就拿這張簡(jiǎn)單樸素的熱圖來(lái)講一下熱圖怎么看彪薛。

首先映入我們眼簾的是有的地方是黑的,有的地方是白的(顏色)坯汤,每一塊顏色都有對(duì)應(yīng)的XY軸虐唠。言下之意,對(duì)象X的屬性Y的值是用顏色表征的惰聂。顏色的聚集代表相應(yīng)對(duì)象X的屬性Y具有相似性(模式疆偿,pattern)。本質(zhì)上它是表現(xiàn)一個(gè)數(shù)值矩陣庶近,圖上每一個(gè)小方格都是一個(gè)數(shù)值翁脆,按一條預(yù)設(shè)好的色彩變化尺(稱為色鍵,Color Key)鼻种,給每個(gè)數(shù)值分配顏色。

有時(shí)候我們還能看到對(duì)象X或者屬性Y的聚類結(jié)果也繪制在熱圖的旁邊沙热,但是這就不屬于熱圖的部分了叉钥,因?yàn)樗呀?jīng)不熱了(熱,就是有的地方冷篙贸,有的地方熱)投队。

熱圖能說(shuō)明哪些問題
  • 表達(dá)量

廣泛的應(yīng)用就是用熱圖來(lái)可視化表達(dá)量。我們想象一下一個(gè)9個(gè)樣本50個(gè)基因的表達(dá)譜爵川,人類一眼看過(guò)去就是一堆數(shù)字敷鸦,而表達(dá)量數(shù)值大小映射到顏色的深淺上,看起來(lái)就很清楚了寝贡。

很多時(shí)候扒披,為了同一個(gè)基因在不同樣本中的表達(dá)量有可比性,需要對(duì)表達(dá)量取對(duì)數(shù)圃泡,或取Z-score碟案,把數(shù)據(jù)標(biāo)準(zhǔn)化到一個(gè)水平上。

  • 相關(guān)性

計(jì)算兩個(gè)矩陣的相關(guān)性颇蜡,可以得到兩兩的相關(guān)性价说,這時(shí)辆亏,用熱圖的顏色來(lái)表示相關(guān)性可以看出哪些配對(duì)相關(guān)性較高。

在單細(xì)胞中的應(yīng)用
  • 表達(dá)量
seurat主題

這是一張典型的seurat做的熱圖鳖目,可以清楚地看出不同分群有著不同的表達(dá)模式扮叨。這里的每一個(gè)色塊是一個(gè)細(xì)胞某基因的表達(dá)量。cluster可以看做是細(xì)胞的聚類领迈,Y軸的基因彻磁,我們看到也是聚類了的(很可能是手動(dòng)的,每一類基因作者都給出了注釋)惦费。所以這張熱圖的關(guān)鍵是什么兵迅? 細(xì)胞和基因及其順序。選擇合適的細(xì)胞和基因(一般是每個(gè)群的差異高表達(dá)基因)后薪贫,為什么我做的圖是一團(tuán)黑恍箭?很可能是因?yàn)椋?/p>

  1. 基因的順序沒排好。
  2. 沒有標(biāo)準(zhǔn)化

人們經(jīng)常需要根據(jù)差異分析的結(jié)果來(lái)探索基因列表的排序瞧省,如SC3的策略扯夭。差異基因的計(jì)算采用非參數(shù)Kruskal-Wallis檢驗(yàn)。SC3提供了調(diào)整p值< 0.01的所有差異表達(dá)基因的列表鞍匾,并繪制了p值最低的50個(gè)基因的基因表達(dá)譜交洗。值得注意的是,聚類后的差異表達(dá)計(jì)算可能會(huì)在p值的分布中引入偏差橡淑,因此我們建議僅使用p值對(duì)基因進(jìn)行排序构拳。

SC3主題

這類圖無(wú)疑反映了某geneList在某cluster的表達(dá)情況。如果巧了梁棠,這個(gè)geneList是某個(gè)細(xì)胞類型的marker基因置森,或者是某個(gè)功能的主要集合,熱圖有助于細(xì)胞群功能和類型的鑒定符糊。熱圖很好地將對(duì)象(X凫海,一般是我們的細(xì)胞)與它的屬性(Y,一般是我們的基因)聯(lián)系起來(lái)男娄。

scanpy主題

在monocle2 中我們還看到一種熱圖將基因的表達(dá)情況與細(xì)胞發(fā)育軌跡結(jié)合到一起行贪。可視化所有明顯依賴于分支的基因的變化(如果愿意也可以自己定義geneList)模闲。這張熱圖同時(shí)顯示了兩種命運(yùn)的變化建瘫,它還要求選擇分支點(diǎn)(branch_point )。列是偽時(shí)間中的點(diǎn)围橡,行是基因暖混,偽時(shí)間的開始在熱圖的中間。當(dāng)你從熱圖的中間讀到右邊的時(shí)候翁授,你正在跟隨一個(gè)偽時(shí)間譜系拣播。當(dāng)你讀到左邊時(shí)晾咪,另一個(gè)。這些基因是分層聚類的贮配,因此您可以可視化具有類似的依賴于序列的基因模塊.

monocle2 主題
  • logFC
    有時(shí)候?yàn)榱送怀稣故救号c群之間的差異基因,可以把差異分析的指標(biāo)反映在熱圖上谍倦,如10X的loup軟件那樣:

Question 2: Which genes are displayed in the Loupe Cell Browser heatmap? How can I export the list of genes displayed?

Answer: In Loupe Cell Browser (version 2.0.0), the heatmap is a compact display of a subset of differentially expressed genes per cluster. Specifically, the gene list is the union of the top 120/N upregulated genes for each cluster ranked by log2 fold-change (N=total number of clusters).The gene names are on the plot when you export the heatmap. However, as of version 2.0.0, there is no 1-click function to export the associated information for the subset of heatmap genes.

cloup 主題
  • 相關(guān)性

提到相關(guān)性,我們很容易注意到WGCNA(weighted correlation network analysis泪勒,加權(quán)基因共表達(dá)網(wǎng)絡(luò)分析), 用于提取與性狀或臨床特征相關(guān)的基因模塊昼蛀,解析與表達(dá)量相關(guān)生物學(xué)過(guò)程。這是除了富集分析之外另一個(gè)尋找好的geneList的方法圆存。這里的顏色不再是表達(dá)量的度量而是相似性的度量叼旋。

WGCNA主題
ComplexHeatmap在單細(xì)胞數(shù)據(jù)可視化中的應(yīng)用

人們針對(duì)單細(xì)胞發(fā)展了相應(yīng)的數(shù)據(jù)結(jié)構(gòu)如seurat的S4類,monocle的CDS沦辙,SingleCellExperiment的sce,scanpy的anndata等夫植,可見單細(xì)胞的故事遠(yuǎn)大于一張二維的表達(dá)譜。那么一張熱圖往往也不能完全的說(shuō)明問題油讯,于是我們希望能夠靈活地操縱熱圖來(lái)講更多的故事详民。于是,我們發(fā)現(xiàn)ComplexHeatmap這個(gè)R包真的是熱圖神器陌兑。

ComplexHeatmap 主題
library(gdata)
library(ComplexHeatmap)
library(GetoptLong)
library(circlize)

getwd()
#?read.xls
expr <-readxl::read_excel("ComplexHeatmap//data//41587_2015_BFnbt3102_MOESM18_ESM.xlsx",sheet=2)
#View(expr)
#expr  <- as.matrix(expr)
expr = expr[!duplicated(expr[[1]]), ]
rownames(expr) = expr[[1]]
#expr = expr[-1]
colnames(expr<-as.data.frame(expr))
expr = expr[,-1]
expr = t(expr)
#expr = expr[-1,]
expr[1:3,1:3];dim(expr)
       Cell 1  Cell 2 Cell 3
Gnai3 3.23220 1.98320 2.2482
Cdc45 3.19810 1.17300 3.1705
Narf  0.29411 0.49389 1.6279
[1] 7073   81
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)
mat[1:4,1:4];dim(mat)
       Cell 1 Cell 2 Cell 3 Cell 4
Sdhd   3.7634 2.7851 3.0983 3.9585
Ccnd2  3.5098 4.2493 3.7505 4.5186
Dazap2 2.9348 2.0173 3.0520 4.7106
Lck    3.8987 1.8177 3.6390 4.2300
[1] 722  81

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)
mat2[1:4,1:4]

           Cell 1     Cell 2      Cell 3   Cell 4
Sdhd    1.4222656 -0.1033475  0.38507327 1.458445
Ccnd2  -1.1291769  0.8112796 -0.49757737 1.517926
Dazap2 -0.2861832 -1.5546649 -0.05732535 1.585296
Lck     0.5384592 -1.5226640 -0.13645403 1.399448
base_mean = rowMeans(mat)
cc = readRDS("ComplexHeatmap//data//mouse_cell_cycle_gene.rds")

head(cc)
ENSMUSG00000019256 ENSMUSG00000021866 ENSMUSG00000017716 ENSMUSG00000007815 ENSMUSG00000034218 ENSMUSG00000042750 
             "Ahr"           "Anxa11"            "Birc5"             "Rhoa"              "Atm"             "Bex2" 
ccl = rownames(mat) %in% cc
table(cc1)
cc_gene = rownames(mat)[ccl]
rp = readRDS("ComplexHeatmap//data//mouse_ribonucleoprotein.rds")

head(rp)
ENSMUSG00000029580 ENSMUSG00000028427 ENSMUSG00000067274 ENSMUSG00000000568 ENSMUSG00000022557 ENSMUSG00000017146 
            "Actb"             "Aqp7"            "Rplp0"           "Hnrnpd"             "Bop1"            "Brca1" 

rpl = rownames(mat) %in% rp
ht_list = Heatmap(mat2, col = 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 = 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))
})

dev.off()

數(shù)據(jù)可視化的過(guò)程就是一段探索意義的旅程沈跨,給每一種顏色、每一種形狀兔综、每一種聚集和離散找到一種生物學(xué)意義饿凛。這讓我想起海子的《面朝大海,春暖花開》:

給每一條河每一座山取一個(gè)溫暖的名字
陌生人软驰,我也為你祝福
愿你有一個(gè)燦爛的前程
愿你有情人終成眷屬
愿你在塵世獲得幸福
我只愿面朝大海笤喳,春暖花開

ComplexHeatmap
R數(shù)據(jù)可視化3:熱圖
如何畫熱圖
10秒鐘-完美掌握-熱圖(heatmap)繪制 - 所有人都可以!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碌宴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蒙畴,更是在濱河造成了極大的恐慌贰镣,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膳凝,死亡現(xiàn)場(chǎng)離奇詭異碑隆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蹬音,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門上煤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人著淆,你說(shuō)我怎么就攤上這事劫狠∷┌蹋” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵独泞,是天一觀的道長(zhǎng)呐矾。 經(jīng)常有香客問我,道長(zhǎng)懦砂,這世上最難降的妖魔是什么蜒犯? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮荞膘,結(jié)果婚禮上罚随,老公的妹妹穿的比我還像新娘。我一直安慰自己羽资,他們只是感情好淘菩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著削罩,像睡著了一般瞄勾。 火紅的嫁衣襯著肌膚如雪擎鸠。 梳的紋絲不亂的頭發(fā)上废亭,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音萝衩,去河邊找鬼微服。 笑死趾疚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的以蕴。 我是一名探鬼主播糙麦,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼丛肮!你這毒婦竟也來(lái)了赡磅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宝与,失蹤者是張志新(化名)和其女友劉穎焚廊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體习劫,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咆瘟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诽里。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袒餐。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灸眼,到底是詐尸還是另有隱情卧檐,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布幢炸,位于F島的核電站泄隔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宛徊。R本人自食惡果不足惜佛嬉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望闸天。 院中可真熱鬧暖呕,春花似錦、人聲如沸苞氮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)笼吟。三九已至库物,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贷帮,已是汗流浹背戚揭。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撵枢,地道東北人民晒。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像锄禽,于是被迫代替她去往敵國(guó)和親潜必。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容