La création de heatmaps dans R a fait l'objet de nombreux articles, discussions et itérations. Mon principal problème est qu'il est difficile de combiner la flexibilité visuelle des solutions disponibles dans treillis levelplot()
ou graphiques de base image()
, avec un regroupement sans effort de base de heatmap()
, de pheatmap's pheatmap()
ou gplots 'heatmap.2()
. C'est un petit détail que je veux changer - l'orientation diagonale des étiquettes sur l'axe des x. Permettez-moi de vous montrer mon point dans le code.
#example data
d <- matrix(rnorm(25), 5, 5)
colnames(d) = paste("bip", 1:5, sep = "")
rownames(d) = paste("blob", 1:5, sep = "")
Vous pouvez facilement changer l'orientation en diagonale avec levelplot()
:
require(lattice)
levelplot(d, scale=list(x=list(rot=45)))
mais appliquer le clustering semble douloureux. Il en va de même pour d'autres options visuelles comme l'ajout de bordures autour des cellules de la carte thermique.
Maintenant, passer aux fonctions liées à heatmap()
, au clustering et à tous les visuels de base est super simple - presque aucun ajustement requis:
heatmap(d)
et il en est de même ici:
require(gplots)
heatmap.2(d, key=F)
et enfin mon préféré:
require(pheatmap)
pheatmap(d)
Mais tous ceux-ci ont pas d'option pour faire pivoter les étiquettes. Le manuel de pheatmap
suggère que je peux utiliser grid.text
Pour orienter mes étiquettes de manière personnalisée. Quelle joie c'est - en particulier lors du regroupement et de la modification de l'ordre des étiquettes affichées. À moins que je manque quelque chose ici ...
Enfin, il y a un bon vieux image()
. Je peux faire pivoter les étiquettes, en général c'est la solution la plus personnalisable, mais pas d'option de clustering.
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)
Alors, que dois-je faire pour obtenir ma carte thermique idéale et rapide, avec le clustering et l'orientation et le piratage des fonctionnalités visuelles Nice? Ma meilleure offre est de modifier heatmap()
ou pheatmap()
d'une manière ou d'une autre, car ces deux semblent être les plus polyvalents en termes d'ajustement. Mais toutes les solutions sont les bienvenues.
Pour corriger pheatmap
, tout ce que vous voulez vraiment faire est d'aller dans pheatmap:::draw_colnames
Et de modifier quelques paramètres dans son appel à grid.text()
. Voici une façon de le faire, en utilisant assignInNamespace()
. (Cela peut nécessiter des ajustements supplémentaires, mais vous obtenez l'image;):
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)
C'est un peu plus complexe que mon commentaire ne le supposait, car heatmap
décompose la région de traçage afin de dessiner les dendrogrammes et la dernière région de tracé n'est pas le image
auquel vous voulez attacher les étiquettes.
Il existe cependant une solution car heatmap
fournit le add.expr
argument qui prend une expression à évaluer lorsque le image
est dessiné. Il faut également connaître la réorganisation des étiquettes qui a lieu en raison de la commande du dendrogramme. Le dernier bit implique un peu de piratage inélégant car je vais d'abord dessiner la carte thermique pour obtenir les informations de réorganisation, puis l'utiliser pour dessiner correctement la carte thermique avec les étiquettes inclinées.
D'abord un exemple de ?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\")")
À ce stade, les étiquettes ne sont pas comme nous les voulons, mais hv
contient les informations dont nous avons besoin pour réorganiser le colnames
de mtcars
dans son composant $colInd
:
> hv$colInd
[1] 2 9 8 11 6 5 10 7 1 4 3
Vous l'utilisez comme vous le feriez avec la sortie de order
par exemple:
> colnames(mtcars)[hv$colInd]
[1] "cyl" "am" "vs" "carb" "wt" "drat" "gear" "qsec" "mpg" "hp"
[11] "disp"
Maintenant, utilisez-le pour générer les étiquettes que nous voulons dans le bon ordre:
labs <- colnames(mtcars)[hv$colInd]
Ensuite, nous rappelons heatmap
mais cette fois nous spécifions labCol = ""
pour supprimer l'étiquetage des variables de colonne (en utilisant des chaînes de longueur nulle). Nous utilisons également un appel à text
pour dessiner les étiquettes à l'angle souhaité. L'appel à text
est:
text(x = seq_along(labs), y = -0.2, srt = 45, labels = labs, xpd = TRUE)
c'est essentiellement ce que vous avez dans votre question. Jouez avec la valeur de y
car vous devez l'ajuster à la longueur des chaînes afin que les étiquettes ne se chevauchent pas avec le tracé image
. Nous spécifions labels = labs
pour passer les étiquettes que nous voulons dessiner dans l'ordre requis. L'appel text
entier est passé à add.expr
sans guillemets. Voici l'appel complet:
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))
Ce qui se traduit par:
Je recherche également une méthode pour faire pivoter le texte de l'étiquette avec une carte thermique. Finalement, j'ai réussi à trouver cette solution:
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)
L'argument clé est srtCol(or srtRow for row labels)
, qui est utilisé pour faire pivoter les étiquettes des colonnes dans les gplots.
Une solution utilisant lattice::levelplot
et latticeExtra::dendrogramGrob
:
library(lattice)
library(latticeExtra)
Les données d'exemple:
d <- matrix(rnorm(25), 5, 5)
colnames(d) = paste("bip", 1:5, sep = "")
rownames(d) = paste("blob", 1:5, sep = "")
Vous devez définir les dendrogrammes pour les lignes et les colonnes (calculées en interne dans 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)
et passez-les à la fonction dendrogramGrob
dans l'argument legend
de levelplot
.
J'ai défini un nouveau thème avec des couleurs de RColorBrewer
, et modifié la largeur et la couleur des bordures des cellules avec border
et 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"))))
Vous pouvez même utiliser l'argument shrink
pour mettre à l'échelle la taille des cellules proportionnellement à leur valeur.
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"))))
La dernière version de pheatmap
(1.0.12) publiée le 2019-01-04 le prend en charge avec l'argument 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)
J'ai créé un package sur GitHub avec une version améliorée de la fonction heatmap.2
. Cela prend en charge l'ajustement des étiquettes d'axe, y compris l'argument srtCol
qui est passé à la fonction axis
. Il peut être installé à partir de: 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)
Depuis version 2.12.1 de gplots
, la fonction heatmap.2
Prend également en charge l'argument srtCol
.
library("gplots")
heatmap.2(d, scale = "none", trace = "none", srtCol = 45)
J'ai pu prendre la réponse de Gavin Simpson et la réduire un peu pour travailler pour moi à des fins de prototypage simple, où data1
est l'objet read.csv () et data1_matrix
bien sûr la matrice produite à partir de cette
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))
Boom! Merci Gavin.
Un élément clé pour que cela fonctionne est la partie avant le add.expr
bit où il a défini le labCol sur "", ce qui est nécessaire pour éviter que les anciennes étiquettes (droites) se chevauchent avec les nouvelles 45 degrés