2013-03-19 133 views
21

在R中創建熱圖一直是許多帖子,討論和迭代的主題。我的主要問題是,將點陣levelplot()或基本圖形image()中的解決方案的視覺靈活性與基本的heatmap(),圖表的pheatmap()或gplots的heatmap.2()的輕鬆集羣相結合是非常棘手的。這是我想改變的一個小細節 - x軸標籤的對角線方向。讓我在代碼中向你展示我的觀點。熱圖中x軸上的對角標籤方向

#example data 
d <- matrix(rnorm(25), 5, 5) 
colnames(d) = paste("bip", 1:5, sep = "") 
rownames(d) = paste("blob", 1:5, sep = "") 

您可以改變方向與levelplot()容易對角線:

require(lattice) 
levelplot(d, scale=list(x=list(rot=45))) 

enter image description here

但應用該聚類似乎疼痛。其他視覺選項如在熱圖單元周圍添加邊框也是如此。現在

,轉移到實際heatmap()相關的功能,集羣和所有的基本視覺效果是超級簡單 - 幾乎無需進行調整:

heatmap(d) 

enter image description here

,因此在這裏:

require(gplots) 
heatmap.2(d, key=F) 

enter image description here

最後,我最喜歡的一個:

require(pheatmap) 
pheatmap(d) 

enter image description here

但所有這些都沒有選擇旋轉標籤pheatmap手冊建議我可以使用grid.text來定製我的標籤。這是多麼的快樂 - 特別是在聚類和改變顯示標籤的順序時。除非我在這裏失去了一些東西...

最後,有一個老好image()。我可以旋轉標籤,通常它是最可定製的解決方案,但沒有集羣選項。

image(1:nrow(d),1:ncol(d), d, axes=F, ylab="", xlab="") 
text(1:ncol(d), 0, srt = 45, labels = rownames(d), xpd = TRUE) 
axis(1, label=F) 
axis(2, 1:nrow(d), colnames(d), las=1) 

enter image description here

所以,我應該怎麼做才能讓我的理想,快速的熱圖,聚類和方向,並很好的視覺特徵黑客?我的最佳出價在某種程度上改變了heatmap()pheatmap(),因爲這兩者似乎是最全面的調整。但任何解決方案歡迎。

+0

基本圖形不允許你控制滴答標籤的旋轉到任意角度---因此你必須使用你在最後一個「圖像」例子中顯示的「text」「hack」。我可能會將'xaxt = FALSE'傳遞給我的'heatmap'調用,然後添加沒有標籤的軸,然後使用'text'添加標籤,就像使用'image'一樣。 – 2013-03-19 16:56:56

+0

@GavinSimpson這種方法的問題在於,當您正在羣集時,您必須手動定義x軸上標籤的順序。可能,但有點痛苦。不過,感謝您指出'heatmap()'是使用基本圖形而不是網格(我認爲它是像'pheatmap()'的網格)。 – 2013-03-19 17:09:50

+0

有一個解決方案 - 我有一些工作,我只是寫作答案。這比我想象的要多一點。即將推出的解決方案... – 2013-03-19 17:12:01

回答

15

要解決pheatmap,你真正想要做的是進入pheatmap:::draw_colnames和調整幾個設置在其呼叫到grid.text()。有一種方法可以使用assignInNamespace()。使用lattice::levelplotlatticeExtra::dendrogramGrob

library(grid)  ## Need to attach (and not just load) grid package 
library(pheatmap) 

## Your data 
d <- matrix(rnorm(25), 5, 5) 
colnames(d) = paste("bip", 1:5, sep = "") 
rownames(d) = paste("blob", 1:5, sep = "") 

## Edit body of pheatmap:::draw_colnames, customizing it to your liking 
draw_colnames_45 <- function (coln, ...) { 
    m = length(coln) 
    x = (1:m)/m - 1/2/m 
    grid.text(coln, x = x, y = unit(0.96, "npc"), vjust = .5, 
     hjust = 1, rot = 45, gp = gpar(...)) ## Was 'hjust=0' and 'rot=270' 
} 

## For pheatmap_1.0.8 and later: 
draw_colnames_45 <- function (coln, gaps, ...) { 
    coord = pheatmap:::find_coordinates(length(coln), gaps) 
    x = coord$coord - 0.5 * coord$size 
    res = textGrob(coln, x = x, y = unit(1, "npc") - unit(3,"bigpts"), vjust = 0.5, hjust = 1, rot = 45, gp = gpar(...)) 
    return(res)} 

## 'Overwrite' default draw_colnames with your own version 
assignInNamespace(x="draw_colnames", value="draw_colnames_45", 
ns=asNamespace("pheatmap")) 

## Try it out 
pheatmap(d) 

enter image description here

+1

那麼,對你來說這是一個小小的調整,對我來說這是一大步。在一天結束時,你是網格的主人;)謝謝喬希! – 2013-03-19 17:55:25

+0

@GeekOnAcid - 好的,像往常一樣感謝有趣的問題!實際上,這是我第一次使用'assignInNamespace()',並且它和'pheatmap'都是很好的發現。我首先做了trace(pheatmap ::: draw_colnames,edit = TRUE)'嘗試了幾件事情,但是一旦我找到修復,就想要一些不那麼具有交互性的東西。原來'assignInNamespace()'是票據,而且我會在將來使用它。乾杯。 – 2013-03-19 18:04:52

+0

+1當然,對於'heatmap'版本也可以做同樣的事情,但在這種情況下,只需運行plot調用兩次並使用'add.expr'就容易了。 – 2013-03-19 19:16:22

7

這比我推薦的評論稍微複雜一些,因爲heatmap爲了繪製樹狀圖而劃分了繪圖區域,最後一個繪圖區域不是您想要附加標籤的image繪圖。

雖然有一個解決方案,但heatmap提供了add.expr參數,該參數在繪製image時需要評估一個表達式。還需要知道由於樹狀圖排序而發生的標籤重新排序。最後一點涉及到一些不雅行爲,因爲我將首先繪製熱圖以獲取重新排序的信息,然後使用它來正確繪製熱成像圖與傾斜標籤。

首先從?heatmap

x <- as.matrix(mtcars) 
rc <- rainbow(nrow(x), start = 0, end = .3) 
cc <- rainbow(ncol(x), start = 0, end = .3) 
hv <- heatmap(x, col = cm.colors(256), scale = "column", 
       RowSideColors = rc, ColSideColors = cc, margins = c(5,10), 
       xlab = "specification variables", ylab = "Car Models", 
       main = "heatmap(<Mtcars data>, ..., scale = \"column\")") 

在這個階段爲例,該標籤是不是我們想要他們,但是hv包含的信息,我們需要重新排序的mtcarscolnames在其組件$colInd

> hv$colInd 
[1] 2 9 8 11 6 5 10 7 1 4 3 

您使用此類似於order的輸出,例如:

> colnames(mtcars)[hv$colInd] 
[1] "cyl" "am" "vs" "carb" "wt" "drat" "gear" "qsec" "mpg" "hp" 
[11] "disp" 

現在用它來產生我們要以正確的順序標籤:

labs <- colnames(mtcars)[hv$colInd] 

然後我們再打電話heatmap但這次我們指定labCol = ""打壓列變量的標籤(使用零長度字符串)。我們還使用致電text以所需角度繪製標籤。到text電話是:

text(x = seq_along(labs), y = -0.2, srt = 45, labels = labs, xpd = TRUE) 

基本上是你有你的問題。如果您需要將此值調整爲字符串的長度以使標籤與image圖不重疊,請使用y的值。我們指定labels = labs按照需要的順序傳遞我們想要繪製的標籤。整個text調用傳遞給add.expr未加引號。這裏是整個呼叫:

hv <- heatmap(x, col = cm.colors(256), scale = "column", 
       RowSideColors = rc, ColSideColors = cc, margins = c(5,10), 
       xlab = "specification variables", ylab = "Car Models", 
       labCol = "", 
       main = "heatmap(<Mtcars data>, ..., scale = \"column\")", 
       add.expr = text(x = seq_along(labs), y = -0.2, srt = 45, 
           labels = labs, xpd = TRUE)) 

導致:

enter image description here

+0

不錯的。謝謝。獲得標籤的位置是至關重要的,所以感謝這個解決方案,但是'原油'它是:) – 2013-03-19 17:27:48

+0

是的,非常好。上個月,我從你那裏瞭解到了「plot(...,panel.last)」,現在是'heatmap(...,add.expr)'。好的提醒,我應該更好地注意那些方便的論點(或者更好的是,去掃描一些你的後面的帖子尋找類似的寶石)。 – 2013-03-20 03:01:58

4

:A液:

library(lattice) 
library(latticeExtra) 

的示例數據:

d <- matrix(rnorm(25), 5, 5) 
colnames(d) = paste("bip", 1:5, sep = "") 
rownames(d) = paste("blob", 1:5, sep = "") 
;(這可能需要額外的調整,但是你得到的圖片)

您必須爲行和公司定義樹狀圖lumns(內部在heatmap計算 ):

dd.row <- as.dendrogram(hclust(dist(d))) 
row.ord <- order.dendrogram(dd.row) 

dd.col <- as.dendrogram(hclust(dist(t(d)))) 
col.ord <- order.dendrogram(dd.col) 

,並將它們傳遞到dendrogramGrob功能中的levelplotlegend 參數。

我從RColorBrewer定義顏色一個新的主題,並 修飾細胞邊框的寬度和顏色與borderborder.lwd

myTheme <- custom.theme(region=brewer.pal(n=11, 'RdBu')) 

levelplot(d[row.ord, col.ord], 
      aspect = "fill", xlab='', ylab='', 
      scales = list(x = list(rot = 45)), 
      colorkey = list(space = "bottom"), 
      par.settings=myTheme, 
      border='black', border.lwd=.6, 
      legend = 
      list(right = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.col, ord = col.ord, 
         side = "right", 
         size = 10)), 
       top = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.row, 
         side = "top")))) 

levelplot with dendrogram

你甚至可以使用shrink參數來縮放與其值成比例的單元大小 。

levelplot(d[row.ord, col.ord], 
      aspect = "fill", xlab='', ylab='', 
      scales = list(x = list(rot = 45)), 
      colorkey = list(space = "bottom"), 
      par.settings=myTheme, 
      border='black', border.lwd=.6, 
      shrink=c(.75, .95), 
      legend = 
      list(right = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.col, ord = col.ord, 
         side = "right", 
         size = 10)), 
       top = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.row, 
         side = "top")))) 

levelplot with dendrogram and scaled cell sizes

+0

非常整齊,歡呼聲奧斯卡! – 2013-03-21 00:05:43

2

我能夠採取加文·辛普森的答案,並修剪下來了一點工作對我來說簡單的原型設計,其中data1是read.csv()對象,當然data1_matrix由此產生的矩陣

heatmap(data_matrix, Rowv=NA, Colv=NA, col=heat.colors(64), scale='column', margins=c(5,10), 
    labCol="", add.expr = text(x = seq_along(colnames(data1)), y=-0.2, srt=45, 
    labels=colnames(data1), xpd=TRUE)) 

熱潮!謝謝加文。

對於這項工作的一個關鍵位是add.expr位在那裏設置labCol爲「」,這是必要的,以防止前(直降)的標籤從與新的45周的人重疊之前的部分

5

我也在尋找使用熱圖旋轉標籤文本的方法。最後,我設法找到這一解決方案:

library(gplots) 

library(RColorBrewer) 

heatmap.2(x,col=rev(brewer.pal(11,"Spectral")),cexRow=1,cexCol=1,margins=c(12,8),trace="none",srtCol=45) 

的關鍵參數是srtCol(or srtRow for row labels),這是用來在gplots旋轉列標籤。

+0

不,當我使用我的示例數據與您的解決方案,它不起作用。它給了我一個錯誤,「srtCol」不是一個圖形參數。 – 2013-11-18 13:12:40