creando un “gráfico de radar” (también conocido como “ttwig de estrellas”, diagtwig de araña) usando ggplot2 en R

Quiero crear una ttwig como la siguiente:

enter image description here

Sé que puedo usar la función del fmsb desde el paquete fmsb . Me pregunto si ggplot2 puede hacerlo, ¿usando coordenadas polares? Gracias.

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 ttwig. 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) 

enter image description here 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 

Radar de radar

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:

  1. Le permite transportar su solución también a otros paquetes de trazado, p. plotly ., De forma plotly .
  2. 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.
  3. Puedes extender y personalizar la ttwig como quieras; ¡demonios, puedes usarla con cualquier paquete de trazado disponible en R!
  4. 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.

Una posible implementación

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:

  1. El primer problema con este enfoque es que las líneas no permanecen rectas.
  2. El coord_polar() no se traduce, por ejemplo, en plotly.
  3. 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.

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()