Creating heatmaps in R has been a topic of many posts, discussions and iterations. My main problem is that it's tricky to combine visual flexibility of solutions available in lattice levelplot()
or basic graphics image()
, with effortless clustering of basic's heatmap()
, pheatmap's pheatmap()
or gplots' heatmap.2()
. It's a tiny detail I want to change - diagonal orientation of labels on x-axis. Let me show you my point in the code.
#example data
d <- matrix(rnorm(25), 5, 5)
colnames(d) = paste("bip", 1:5, sep = "")
rownames(d) = paste("blob", 1:5, sep = "")
You can change orientation to diagonal easily with levelplot()
:
require(lattice)
levelplot(d, scale=list(x=list(rot=45)))
but applying the clustering seems pain. So does other visual options like adding borders around heatmap cells.
Now, shifting to actual heatmap()
related functions, clustering and all basic visuals are super-simple - almost no adjustment required:
heatmap(d)
and so is here:
require(gplots)
heatmap.2(d, key=F)
and finally, my favourite one:
require(pheatmap)
pheatmap(d)
But all of those have no option to rotate the labels. Manual for pheatmap
suggests that I can use grid.text
to custom-orient my labels. What a joy it is - especially when clustering and changing the ordering of displayed labels. Unless I'm missing something here...
Finally, there is an old good image()
. I can rotate labels, in general it' most customizable solution, but no clustering option.
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)
So what should I do to get my ideal, quick heatmap, with clustering and orientation and nice visual features hacking? My best bid is changing heatmap()
or pheatmap()
somehow because those two seem to be most versatile in adjustment. But any solutions welcome.
To fix pheatmap
, all you really want to do is to go into pheatmap:::draw_colnames
and tweak a couple of settings in its call to grid.text()
. Here's one way to do that, using assignInNamespace()
. (It may need additional adjustments, but you get the picture ;):
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)