热图中 x 轴上的对角线标签方向

Posted

技术标签:

【中文标题】热图中 x 轴上的对角线标签方向【英文标题】:Diagonal labels orientation on x-axis in heatmap(s) 【发布时间】:2013-03-08 11:43:24 【问题描述】:

在 R 中创建热图已成为许多帖子、讨论和迭代的主题。我的主要问题是,将 lattice levelplot() 或基本图形 image() 中可用解决方案的视觉灵活性与基本 heatmap()、pheatmap 的 pheatmap() 或 gplots 的 heatmap.2() 的轻松聚类相结合是很棘手的。这是我想要更改的一个小细节 - 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)))

但应用聚类似乎很痛苦。其他视觉选项也是如此,例如在热图单元格周围添加边框。

现在,转移到实际的heatmap() 相关功能、聚类和所有基本视觉效果都非常简单——几乎不需要调整:

heatmap(d)

这里也是这样:

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

最后,我最喜欢的一个:

require(pheatmap)
pheatmap(d) 

但是所有这些都没有旋转标签的选项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)

那么我应该怎么做才能获得理想的、快速的热图、集群和方向以及漂亮的视觉特征黑客?我的最佳出价是更改 heatmap()pheatmap() 不知何故,因为这两个似乎在调整方面最通用。但欢迎任何解决方案。

【问题讨论】:

基础图形不允许您将刻度标签旋转到任意角度 --- 因此您必须使用在上一个 image 示例中显示的 text "hack" .我可能会将xaxt = FALSE 传递给我的heatmap 调用,然后添加不带标签的轴,然后使用text 添加标签,就像使用image 一样。 @GavinSimpson 这种方法的问题是,当您进行聚类时,您必须手动定义 x 轴上的标签顺序。可能,但有点痛苦。不过,感谢您向我指出 heatmap() 是使用基本图形而不是网格构建的(我认为它是像 pheatmap() 这样的网格)。 有一个解决方案 - 我有一些工作,我只是写出来作为答案。这比我想象的要复杂一些。解决方案即将推出... +1 既有趣又好问题。 【参考方案1】:

要修复pheatmap,您真正想做的就是进入pheatmap:::draw_colnames 并在调用grid.text() 时调整几个设置。这是使用assignInNamespace() 的一种方法。 (它可能需要额外的调整,但你明白了;):

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)

【讨论】:

嗯,对你来说这是一个小调整,对我来说是一大步。归根结底,您是网格大师;)谢谢乔希! @GeekOnAcid -- 好吧,像往常一样感谢这个有趣的问题!事实上,这是我第一次使用assignInNamespace(),它和pheatmap 都是不错的发现。我第一次使用trace(pheatmap:::draw_colnames, edit=TRUE) 尝试了一些事情,但是一旦我找到了解决办法,我就想要一些比这更少互动的东西。原来assignInNamespace() 是票,我会在以后使用它。干杯。 +1 当然,heatmap 版本也可以这样做,但在这种情况下,只需运行两次绘图调用并使用 add.expr 会更容易。 如果标签很长并且离开左侧,您知道如何增加边距吗? 不再需要此解决方法。 angle_col 参数在 pheatmap 1.0.12 版本中受支持(有关详细信息,请参阅下面的答案)。【参考方案2】:

它比我的评论假设的要复杂一些,因为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 包含我们需要在其组件$colInd 中重新排序mtcarscolnames 的信息:

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

这本质上就是您的问题。使用y 的值,因为您需要将其调整为字符串的长度,以使标签不与image 绘图重叠。我们指定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))

结果:

【讨论】:

不错的一个。谢谢。获取标签位置至关重要,所以感谢这个解决方案,但它是“粗鲁的”:) 是的,非常好。就在上个月我从你那里了解到plot(..., panel.last),现在这里是heatmap(..., add.expr)。很好的提醒,我应该更好地关注那些方便的论点(或者,也许更好,去扫描你的一些回帖以寻找类似的宝石)。【参考方案3】:

我也在寻找使用热图旋转标签文本的方法。最终我设法找到了这个解决方案:

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中的列标签。

【讨论】:

不,当我将示例数据与您的解决方案一起使用时,它不起作用。它给了我一个错误"srtCol" is not a graphical parameter【参考方案4】:

pheatmap (1.0.12) released on 2019-01-04 的最新版本通过 angle_col 参数支持这一点。

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

#update to latest version on CRAN
install.packages("pheatmap")
library("pheatmap")
pheatmap(d, angle_col = 45)

我在 GitHub 上创建了一个包,其中包含 heatmap.2 函数的改进版本。这支持调整轴标签,包括传递给axis 函数的srtCol 参数。可以从以下位置安装:https://github.com/TomKellyGenetics/heatmap.2x

library("devtools")
install_github("TomKellyGenetics/heatmap.2x")
library("heatmap.2x")

heatmap.2x(d, scale = "none", trace = "none", col = heat.colors, srtCol = 45)

截至version 2.12.1 或gplotsheatmap.2 函数也支持srtCol 参数。

library("gplots")
heatmap.2(d, scale = "none", trace = "none", srtCol = 45)

【讨论】:

【参考方案5】:

使用lattice::levelplotlatticeExtra::dendrogramGrob 的解决方案:

library(lattice)
library(latticeExtra)

示例数据:

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

您必须为行和列定义树状图(计算 内部在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)

并将它们传递给legend 中的dendrogramGrob 函数 levelplot 的参数。

我用RColorBrewer 的颜色定义了一个新主题,并且 用border修改了单元格边框的宽度和颜色 和border.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"))))

您甚至可以使用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"))))

【讨论】:

【参考方案6】:

我能够接受 Gavin Simpson 的回答并将其剪裁一些,以便为我工作以进行简单的原型设计,其中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度标签重叠所必需的

【讨论】:

以上是关于热图中 x 轴上的对角线标签方向的主要内容,如果未能解决你的问题,请参考以下文章

ZJNU 1138 - 小兔的棋盘——中级

Bitmap的内存计算方式

对角线运动

如何在 R 中成对图的对角线上打印希腊字母?

五子棋的斜对角方向上的规则 -- java编程(简单粗暴版)

已知图中每行每列以及每条对角线上的三个数的和都相等,那么x应该等于多少?