2013-03-19 129 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