online - Orientación de las etiquetas diagonales en el eje x en mapas de calor(s)
mapas de calor free (5)
La creación de mapas de calor en R ha sido un tema de muchas publicaciones, discusiones e iteraciones. Mi problema principal es que es difícil combinar la flexibilidad visual de las soluciones disponibles en el levelplot()
celosía levelplot()
o la image()
gráfica básica image()
, con un agrupamiento sin esfuerzo del heatmap()
de heatmap()
de heatmap()
, pheatmap''s pheatmap()
o gplots '' heatmap.2()
. Es un pequeño detalle que quiero cambiar: la orientación diagonal de las etiquetas en el eje x. Déjame mostrarte mi punto en el código.
#example data
d <- matrix(rnorm(25), 5, 5)
colnames(d) = paste("bip", 1:5, sep = "")
rownames(d) = paste("blob", 1:5, sep = "")
Puedes cambiar la orientación a la diagonal fácilmente con levelplot()
:
require(lattice)
levelplot(d, scale=list(x=list(rot=45)))
Pero aplicar el agrupamiento parece dolor. Lo mismo ocurre con otras opciones visuales, como agregar bordes alrededor de celdas de mapa de calor.
Ahora, cambiar a las funciones relacionadas con heatmap()
, el agrupamiento y todos los elementos visuales básicos son súper simples, casi no se requieren ajustes:
heatmap(d)
y así está aquí:
require(gplots)
heatmap.2(d, key=F)
y por último, mi favorita:
require(pheatmap)
pheatmap(d)
Pero todos ellos no tienen opción de rotar las etiquetas . El manual para pheatmap
sugiere que puedo usar grid.text
para orientar mis etiquetas a la medida. Qué alegría es, especialmente al agrupar y cambiar el orden de las etiquetas mostradas. A menos que me esté perdiendo algo aquí ...
Finalmente, hay una vieja buena image()
. Puedo rotar las etiquetas, en general es la solución más personalizable, pero no la opción de agrupamiento.
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)
Entonces, ¿qué debo hacer para obtener mi mapa de calor rápido e ideal, con agrupación y orientación, y buenas características visuales de piratería? Mi mejor oferta es cambiar heatmap()
o pheatmap()
alguna manera porque esos dos parecen ser los más versátiles en el ajuste. Pero cualquier solución bienvenida.
Es un poco más complejo de lo que presumía mi comentario, porque el heatmap
rompe la región de trazado para dibujar los dendrogramas y la última región de trazado no es el trazado de image
al que desea adjuntar las etiquetas.
Sin embargo, hay una solución, ya que heatmap
proporciona el argumento add.expr
que toma una expresión para ser evaluada cuando se dibuja la image
. También se necesita conocer el reordenamiento de las etiquetas que tiene lugar debido a la ordenación del dendrograma. El último bit involucra un poco de piratería poco elegante, ya que primero dibujaré el mapa de calor para obtener la información de reordenación y luego usaré eso para dibujar el mapa de calor correctamente con las etiquetas en ángulo.
Primero un ejemplo 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/")")
En esta etapa, las etiquetas no son como las queremos, pero hv
contiene la información que necesitamos para reordenar los colnames
de mtcars
en su componente $colInd
:
> hv$colInd
[1] 2 9 8 11 6 5 10 7 1 4 3
Usas esto como lo harías con la salida de order
por ejemplo:
> colnames(mtcars)[hv$colInd]
[1] "cyl" "am" "vs" "carb" "wt" "drat" "gear" "qsec" "mpg" "hp"
[11] "disp"
Ahora use eso para generar las etiquetas que queremos en el orden correcto:
labs <- colnames(mtcars)[hv$colInd]
Luego volvemos a llamar heatmap
pero esta vez especificamos labCol = ""
para suprimir el etiquetado de las variables de columna (usando cadenas de longitud cero). También utilizamos una llamada a text
para dibujar las etiquetas en el ángulo deseado. La llamada al text
es:
text(x = seq_along(labs), y = -0.2, srt = 45, labels = labs, xpd = TRUE)
que es esencialmente lo que tienes en tu pregunta. Juegue con el valor de y
ya que necesita ajustar esto a la longitud de las cadenas para que las etiquetas no se superpongan con el trazado de la image
. Especificamos labels = labs
para pasar las etiquetas que queremos dibujar en el orden requerido. La llamada de text
completa se pasa a add.expr
comillas. Aquí está la llamada completa:
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))
Lo que resulta en:
Para arreglar pheatmap
, todo lo que realmente quieres hacer es ir a pheatmap:::draw_colnames
y modificar un par de configuraciones en su llamada a grid.text()
. Aquí hay una forma de hacerlo, utilizando assignInNamespace()
. (Puede que necesite ajustes adicionales, pero se obtiene la imagen;):
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)
Pude tomar la respuesta de Gavin Simpson y recortarla un poco para que me funcionara con fines de creación de prototipos simples, donde data1
es el objeto read.csv (), y data1_matrix
por supuesto, la matriz producida a partir de ese
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))
¡Auge! Gracias Gavin.
Un bit clave para que esto funcione es la parte antes del bit add.expr
donde configuró labCol a "", que es necesario para evitar que las etiquetas anteriores (rectas) se superpongan con las nuevas de 45 grados
También estoy buscando un método para rotar el texto de la etiqueta con el mapa de calor. Finalmente he logrado encontrar esta solución:
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)
El argumento clave es srtCol(or srtRow for row labels)
, que se utiliza para rotar las etiquetas de columna en gplots.
Una solución que utiliza lattice::levelplot
y latticeExtra::dendrogramGrob
:
library(lattice)
library(latticeExtra)
Los datos de ejemplo:
d <- matrix(rnorm(25), 5, 5)
colnames(d) = paste("bip", 1:5, sep = "")
rownames(d) = paste("blob", 1:5, sep = "")
Debe definir los dendrogramas para filas y columnas (computados internamente en heatmap
de 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)
y levelplot
a la función dendrogramGrob
en el argumento de legend
de levelplot
.
He definido un nuevo tema con colores de RColorBrewer
y RColorBrewer
modificado el ancho y el color de los bordes de las celdas con border
y 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"))))
Incluso puede utilizar el argumento de shrink
para escalar el tamaño de las celdas proporcional a su valor.
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"))))