graphs - creando un "gráfico de radar"(también conocido como "trama de estrellas", diagrama de araña) usando ggplot2 en R
radar chart r (4)
Aquí hay una respuesta que casi lo hace en ggplot.
No reclamo nada más que poner el ejemplo aquí, se basa en lo que Hadley mostró aquí https://github.com/hadley/ggplot2/issues/516
Todo lo que hice fue usar deployer / tidyr en su lugar y elegir solo 3 autos para simplificar
los problemas pendientes son 1) el último y el primer punto no están conectados, esto es obvio si se ve el coord_polar como un ajuste del eje x tradicional. No hay ninguna razón por la cual deberían estar conectados. Pero así es como normalmente se muestran los gráficos de radar 2) para hacer eso, necesita agregar un segmento manualmente entre esos 2 puntos. Una pequeña manipulación y algunas capas más deberían hacerlo. Trataré de trabajar en eso si tengo algo de tiempo
library(dplyr);library(tidyr);library(ggplot2)
#make some data
data = mtcars[c(27,19,16),]
data$model=row.names(data)
#connvert data to long format and also rescale it into 0-1 scales
data1 <- data %>% gather(measure,value,-model) %>% group_by(measure) %>% mutate(value1=(value-min(value))/(max(value)-min(value)))
is.linear.polar <- function(coord) TRUE
ggplot(data1,aes(x=measure,y=value1,color=model,group=model))+geom_line()+coord_polar()
Quiero crear una trama como la siguiente:
Sé que puedo usar la función del fmsb
desde el paquete fmsb
. Me pregunto si ggplot2
puede hacerlo, ¿usando coordenadas polares? Gracias.
Pasé varios días sobre este problema y al final decidí construir mi propio paquete encima de ggradar
. El núcleo de la misma es una versión mejorada de la función de @Tony M.
CalculateGroupPath4 <- function(df) {
angles = seq(from=0, to=2*pi, by=(2*pi)/(ncol(df)-1)) # find increment
xx<-c(rbind(t(plot.data.offset[,-1])*sin(angles[-ncol(df)]),
t(plot.data.offset[,2])*sin(angles[1])))
yy<-c(rbind(t(plot.data.offset[,-1])*cos(angles[-ncol(df)]),
t(plot.data.offset[,2])*cos(angles[1])))
graphData<-data.frame(group=rep(df[,1],each=ncol(df)),x=(xx),y=(yy))
return(graphData)
}
CalculateGroupPath5 <- function(mydf) {
df<-cbind(mydf[,-1],mydf[,2])
myvec<-c(t(df))
angles = seq(from=0, to=2*pi, by=(2*pi)/(ncol(df)-1)) # find increment
xx<-myvec*sin(rep(c(angles[-ncol(df)],angles[1]),nrow(df)))
yy<-myvec*cos(rep(c(angles[-ncol(df)],angles[1]),nrow(df)))
graphData<-data.frame(group=rep(mydf[,1],each=ncol(mydf)),x=(xx),y=(yy))
return(graphData)
}
microbenchmark::microbenchmark(CalculateGroupPath(plot.data.offset),
CalculateGroupPath4(plot.data.offset),
CalculateGroupPath5(plot.data.offset), times=1000L)
Unit: microseconds
expr min lq mean median uq max neval
CalculateGroupPath(plot.data.offset) 20768.163 21636.8715 23125.1762 22394.1955 23946.5875 86926.97 1000
CalculateGroupPath4(plot.data.offset) 550.148 614.7620 707.2645 650.2490 687.5815 15756.53 1000
CalculateGroupPath5(plot.data.offset) 577.634 650.0435 738.7701 684.0945 726.9660 11228.58 1000
Tenga en cuenta que en realidad he comparado más funciones en este benchmark , entre otras funciones de ggradar
. En general, la solución de @Tony M está bien escrita, en el sentido de la lógica, y puede usarla en muchos otros idiomas, como por ejemplo Javascript, con algunos ajustes. Sin embargo, R
vuelve mucho más rápido si vectoriza las operaciones. Por lo tanto, la ganancia masiva en tiempo de cálculo con mi solución.
Todas las respuestas excepto @Tony M.''s han usado la coord_polar
coord_polar de ggplot2
. Hay cuatro ventajas de permanecer dentro del sistema de coordenadas cartesianas:
- Le permite transportar su solución también a otros paquetes de trazado, p.
plotly
., De formaplotly
. - Todos los que tienen alguna comprensión del coseno estándar y la función sinusal pueden comprender cómo funciona la transformación de datos.
- Puedes extender y personalizar la trama como quieras; ¡demonios, puedes usarla con cualquier paquete de trazado disponible en R!
- No necesita cargar ninguno excepto su paquete de trazado. Sin embargo, tiene sentido cambiar la escala de sus datos, por ejemplo, con el paquete de
scales
de Hadley.
Si, como yo, no sabes nada acerca de cómo hacer trazados de radar cuando encuentras este hilo : El coord_polar()
podría crear buenas coord_polar()
radar. Sin embargo, la implementación es algo complicada. Cuando lo probé, tuve varios problemas:
- El primer problema con este enfoque es que las líneas no permanecen rectas.
- El
coord_polar()
no se traduce, por ejemplo, en plotly. - El sistema de coordenadas polares dificulta la personalización detallada, ya que las anotaciones y otras características se incluirán también en las coordenadas polares.
Este tipo hizo una buena gráfica de radar usando coord_polar
.
Sin embargo, dadas mis experiencias, prefiero no usar el coord_polar()
-trick. En cambio, si está buscando una ''manera fácil'' de crear un ggplot-radar estático, tal vez use el gran ggforce
para dibujar círculos del radar. No hay garantías de que esto sea más fácil que usar mi paquete, pero desde la adaptabilidad parece más coord_polar
que coord_polar
. La desventaja aquí es que, por ejemplo, plotly
no admite la ggforce -extention.
EDITAR: Ahora encontré buen ejemplo con coord_polar de ggplot2 que revisó mi opinión un poco.
Primero, cargamos algunos paquetes.
library(reshape2)
library(ggplot2)
library(scales)
Aquí están los datos del ejemplo de radarchart al que se ha vinculado.
maxmin <- data.frame(
total = c(5, 1),
phys = c(15, 3),
psycho = c(3, 0),
social = c(5, 1),
env = c(5, 1)
)
dat <- data.frame(
total = runif(3, 1, 5),
phys = rnorm(3, 10, 2),
psycho = c(0.5, NA, 3),
social = runif(3, 1, 5),
env = c(5, 2.5, 4)
)
Necesitamos un poco de manipulación para que sean adecuados para ggplot.
Normalícelos, agregue una columna de identificación y conviértelos a formato largo.
normalised_dat <- as.data.frame(mapply(
function(x, mm)
{
(x - mm[2]) / (mm[1] - mm[2])
},
dat,
maxmin
))
normalised_dat$id <- factor(seq_len(nrow(normalised_dat)))
long_dat <- melt(normalised_dat, id.vars = "id")
ggplot también ajusta los valores para que coincidan el primero y el último factor. Agregamos un nivel de factor adicional para evitar esto. Esto ya no es verdad.
niveles (long_dat $ variable) <- c (niveles (long_dat $ variable), "")
Aquí está la trama. No es lo mismo, pero debería comenzar.
ggplot(long_dat, aes(x = variable, y = value, colour = id, group = id)) +
geom_line() +
coord_polar(theta = "x", direction = -1) +
scale_y_continuous(labels = percent)
Tenga en cuenta que cuando usa coord_polar
, las líneas son curvas. Si quieres líneas rectas, tendrás que probar una técnica diferente.
Si buscas una versión de coordenadas no polares, creo que la siguiente función te ayudará:
###################################
##Radar Plot Code
##########################################
##Assumes d is in the form:
# seg meanAcc sdAcc meanAccz sdAccz meanSpd sdSpd cluster
# 388 -0.038 1.438 -0.571 0.832 -0.825 0.095 1
##where seg is the individual instance identifier
##cluster is the cluster membership
##and the variables from meanACC to sdSpd are used for the clustering
##and thus should be individual lines on the radar plot
radarFix = function(d){
##assuming the passed in data frame
##includes only variables you would like plotted and segment label
d$seg=as.factor(d$seg)
##find increment
angles = seq(from=0, to=2*pi, by=(2*pi)/(ncol(d)-2))
##create graph data frame
graphData= data.frame(seg="", x=0,y=0)
graphData=graphData[-1,]
for(i in levels(d$seg)){
segData= subset(d, seg==i)
for(j in c(2:(ncol(d)-1))){
##set minimum value such that it occurs at 0. (center the data at -3 sd)
segData[,j]= segData[,j]+3
graphData=rbind(graphData, data.frame(seg=i,
x=segData[,j]*cos(angles[j-1]),
y=segData[,j]*sin(angles[j-1])))
}
##completes the connection
graphData=rbind(graphData, data.frame(seg=i,
x=segData[,2]*cos(angles[1]),
y=segData[,2]*sin(angles[1])))
}
graphData
}
Si está trazando por clúster o grupo, puede usar lo siguiente:
radarData = ddply(clustData, .(cluster), radarFix)
ggplot(radarData, aes(x=x, y=y, group=seg))+
geom_path(alpha=0.5,colour="black")+
geom_point(alpha=0.2, colour="blue")+
facet_wrap(~cluster)
Esto debería funcionar con la siguiente muestra de datos:
seg meanAccVs sdAccVs meanSpd sdSpd cluster
1470 1.420 0.433 -0.801 0.083 1
1967 -0.593 0.292 1.047 0.000 3
2167 -0.329 0.221 0.068 0.053 7
2292 -0.356 0.214 -0.588 0.056 4
2744 0.653 1.041 -1.039 0.108 5
3448 2.189 1.552 -0.339 0.057 8
7434 0.300 0.250 -1.009 0.088 5
7764 0.607 0.469 -0.035 0.078 2
7942 0.124 1.017 -0.940 0.138 5
9388 0.742 1.289 -0.477 0.301 5