ggplot2 heatmaps: usando diferentes gradientes para categorías

Esta publicación de blog de Learning R muestra cómo hacer un mapa de calor de estadísticas de baloncesto usando ggplot2. El mapa de calor terminado se ve así:

enter image description here

Mi pregunta (inspirada por Jake, quien comentó en la publicación del blog Learning R) es: ¿sería posible usar diferentes colores de degradado para diferentes categorías de estadísticas (ofensivas, defensivas, otras)?

Primero, recree el gráfico de la publicación, actualizándolo para la versión más reciente (0.9.2.1) de ggplot2 que tiene un sistema de tema diferente y adjunta menos paquetes:

 nba < - read.csv("http://datasets.flowingdata.com/ppg2008.csv") nba$Name <- with(nba, reorder(Name, PTS)) library("ggplot2") library("plyr") library("reshape2") library("scales") nba.m <- melt(nba) nba.s <- ddply(nba.m, .(variable), transform, rescale = scale(value)) ggplot(nba.s, aes(variable, Name)) + geom_tile(aes(fill = rescale), colour = "white") + scale_fill_gradient(low = "white", high = "steelblue") + scale_x_discrete("", expand = c(0, 0)) + scale_y_discrete("", expand = c(0, 0)) + theme_grey(base_size = 9) + theme(legend.position = "none", axis.ticks = element_blank(), axis.text.x = element_text(angle = 330, hjust = 0)) 

enter image description here

Usar diferentes colores de degradado para diferentes categorías no es tan sencillo. El enfoque conceptual, asignar el fill a la interaction(rescale, Category) (donde Category es Ofensiva / Defensiva / Otro, ver a continuación) no funciona porque interactuando un factor y una variable continua da una variable discreta cuyo fill no se puede mapear .

La forma de evitar esto es hacer esta interacción artificialmente, mapear rescale a rangos no superpuestos para diferentes valores de Category y luego usar scale_fill_gradientn para asignar cada una de estas regiones a diferentes gradientes de color.

Primero crea las categorías. Creo que estos se corresponden con los del comentario, pero no estoy seguro; cambiar qué variable está en qué categoría es fácil.

 nba.s$Category < - nba.s$variable levels(nba.s$Category) <- list("Offensive" = c("PTS", "FGM", "FGA", "X3PM", "X3PA", "AST"), "Defensive" = c("DRB", "ORB", "STL"), "Other" = c("G", "MIN", "FGP", "FTM", "FTA", "FTP", "X3PP", "TRB", "BLK", "TO", "PF")) 

Dado que la rescale está dentro de unos pocos (3 o 4) de 0, las diferentes categorías se pueden compensar por cien para mantenerlas separadas. Al mismo tiempo, determine dónde deben estar los puntos finales de cada gradiente de color, en términos de valores y colores reescalados.

 nba.s$rescaleoffset < - nba.s$rescale + 100*(as.numeric(nba.s$Category)-1) scalerange <- range(nba.s$rescale) gradientends <- scalerange + rep(c(0,100,200), each=2) colorends <- c("white", "red", "white", "green", "white", "blue") 

Ahora reemplace la variable de fill con rescaleoffset y cambie la escala de fill para usar scale_fill_gradientn (recordando reescalar los valores):

 ggplot(nba.s, aes(variable, Name)) + geom_tile(aes(fill = rescaleoffset), colour = "white") + scale_fill_gradientn(colours = colorends, values = rescale(gradientends)) + scale_x_discrete("", expand = c(0, 0)) + scale_y_discrete("", expand = c(0, 0)) + theme_grey(base_size = 9) + theme(legend.position = "none", axis.ticks = element_blank(), axis.text.x = element_text(angle = 330, hjust = 0)) 

enter image description here

Reordenar para obtener estadísticas relacionadas entre sí es otra aplicación de la función de reorder en las diversas variables:

 nba.s$variable2 < - reorder(nba.s$variable, as.numeric(nba.s$Category)) ggplot(nba.s, aes(variable2, Name)) + geom_tile(aes(fill = rescaleoffset), colour = "white") + scale_fill_gradientn(colours = colorends, values = rescale(gradientends)) + scale_x_discrete("", expand = c(0, 0)) + scale_y_discrete("", expand = c(0, 0)) + theme_grey(base_size = 9) + theme(legend.position = "none", axis.ticks = element_blank(), axis.text.x = element_text(angle = 330, hjust = 0)) 

enter image description here

Aquí hay una sugerencia más simple que usa la estética ggplot2 para mapear tanto los gradientes como las categorías de color. Simplemente use una alfa-estética para generar el degradado y el relleno-estético para la categoría.

Aquí está el código para hacerlo, refactorizando la respuesta de Brian Diggs:

 nba < - read.csv("http://datasets.flowingdata.com/ppg2008.csv") nba$Name <- with(nba, reorder(Name, PTS)) library("ggplot2") library("plyr") library("reshape2") library("scales") nba.m <- melt(nba) nba.s <- ddply(nba.m, .(variable), transform, rescale = scale(value)) nba.s$Category <- nba.s$variable levels(nba.s$Category) <- list("Offensive" = c("PTS", "FGM", "FGA", "X3PM", "X3PA", "AST"), "Defensive" = c("DRB", "ORB", "STL"), "Other" = c("G", "MIN", "FGP", "FTM", "FTA", "FTP", "X3PP", "TRB", "BLK", "TO", "PF")) 

Luego, normalice la variable de rescale entre 0 y 1:

 nba.s$rescale = (nba.s$rescale-min(nba.s$rescale))/(max(nba.s$rescale)-min(nba.s$rescale)) 

Y ahora, haz la conspiración:

 ggplot(nba.s, aes(variable, Name)) + geom_tile(aes(alpha = rescale, fill=Category), colour = "white") + scale_alpha(range=c(0,1)) + scale_x_discrete("", expand = c(0, 0)) + scale_y_discrete("", expand = c(0, 0)) + theme_grey(base_size = 9) + theme(legend.position = "none", axis.ticks = element_blank(), axis.text.x = element_text(angle = 330, hjust = 0)) + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) 

mapa de calor ggplot2 usando alfa estética

Tenga en cuenta el uso de alpha=rescale y luego la escala del rango alfa usando scale_alpha(range=c(0,1)) , que se puede adaptar para cambiar el rango de forma apropiada para su trazado.