Ordenar discreto x escala por frecuencia / valor

137

Estoy haciendo un gráfico de barras esquivadas usando ggplot con una escala x discreta, el eje x ahora está organizado en orden alfabético, pero necesito reorganizarlo para que esté ordenado por el valor del eje y (es decir, la barra más alta posicionarse a la izquierda).

Intenté ordenar u ordenar, pero resultó en ordenar el eje x, pero no las barras respectivamente.

¿Qué he hecho mal?

lokheart
fuente

Respuestas:

105

Intente configurar manualmente los niveles del factor en el eje x. Por ejemplo:

library(ggplot2)
# Automatic levels
ggplot(mtcars, aes(factor(cyl))) + geom_bar()    

ggplot del conjunto de datos de automóviles con niveles de factor determinados automáticamente

# Manual levels
cyl_table <- table(mtcars$cyl)
cyl_levels <- names(cyl_table)[order(cyl_table)]
mtcars$cyl2 <- factor(mtcars$cyl, levels = cyl_levels)
# Just to be clear, the above line is no different than:
# mtcars$cyl2 <- factor(mtcars$cyl, levels = c("6","4","8"))
# You can manually set the levels in whatever order you please. 
ggplot(mtcars, aes(cyl2)) + geom_bar()

ggplot del conjunto de datos de automóviles con niveles de factores reordenados manualmente

Como James señaló en su respuesta, reorderes la forma idiomática de reordenar los niveles de factores.

mtcars$cyl3 <- with(mtcars, reorder(cyl, cyl, function(x) -length(x)))
ggplot(mtcars, aes(cyl3)) + geom_bar()

ggplot del conjunto de datos de automóviles con niveles de factores reordenados utilizando la función de reordenamiento

Algodón Richie
fuente
197

La mejor manera para mí era usar el vector con categorías en orden que necesito como limitsparámetro scale_x_discrete. Creo que es una solución bastante simple y directa.

ggplot(mtcars, aes(factor(cyl))) + 
  geom_bar() + 
  scale_x_discrete(limits=c(8,4,6))

ingrese la descripción de la imagen aquí

Yuriy Petrovskiy
fuente
1
@HendyIrawan no hay leyenda a menos que tenga otras dimensiones (color, relleno) también asignadas a la misma variable.
Gregor Thomas
55
Creo que esta es la mejor respuesta. Controla el orden de los valores del eje x y no transforma ni afecta el marco de datos. El uso factory los reordercambios de las características de los datos, aunque dentro de la ggplot()llamada, hacen más de lo necesario para el problema en cuestión.
mjandrews
2
¡Esta debería ser la respuesta aceptada! ¿Por qué complicar las cosas escribiendo de 2 a 3 líneas de código para algo que puede hacer en una sola línea de código elegante (predefinida)?
SilSur
1
Esto también funcionó para mí ordenar x por valor de y: scale_x_discrete(limits = DT$x[order(-DT$y)])+
armipunk
38

Puedes usar reorder:

qplot(reorder(factor(cyl),factor(cyl),length),data=mtcars,geom="bar")

Editar:

Para tener la barra más alta a la izquierda, debes usar un poco de kludge:

qplot(reorder(factor(cyl),factor(cyl),function(x) length(x)*-1),
   data=mtcars,geom="bar")

Esperaría que esto también tenga alturas negativas, pero no lo tiene, ¡así que funciona!

James
fuente
55
Me sorprende que esta respuesta no tenga más votos a favor, el 90% de las veces esta es la forma correcta de hacerlo.
Gregor Thomas el
1
Creo que ambos factores son superfluos. Hay una llamada implícita al factor para el primer argumento y se supone que el segundo argumento es numérico.
IRTFM
Una explicación que me ayudó a descubrir qué estaban haciendo estas soluciones bajo el capó: rstudio-pubs-static.s3.amazonaws.com/…
keithpjolley
30

Hadley ha estado desarrollando un paquete llamado forcats. Este paquete hace la tarea mucho más fácil. Puede explotar fct_infreq()cuando desee cambiar el orden del eje x por la frecuencia de un factor. En el caso del mtcarsejemplo en esta publicación, desea reordenar los niveles cylpor la frecuencia de cada nivel. El nivel que aparece con mayor frecuencia permanece en el lado izquierdo. Todo lo que necesitas es el fct_infreq().

library(ggplot2)
library(forcats)

ggplot(mtcars, aes(fct_infreq(factor(cyl)))) +
geom_bar() +
labs(x = "cyl")

Si quieres ir al revés, puedes usarlo fct_rev()junto con fct_infreq().

ggplot(mtcars, aes(fct_rev(fct_infreq(factor(cyl))))) +
geom_bar() +
labs(x = "cyl") 

ingrese la descripción de la imagen aquí

jazzurro
fuente
2

Me doy cuenta de que esto es antiguo, pero tal vez esta función que creé es útil para alguien por ahí:

order_axis<-function(data, axis, column)
{
  # for interactivity with ggplot2
  arguments <- as.list(match.call())
  col <- eval(arguments$column, data)
  ax <- eval(arguments$axis, data)

  # evaluated factors
  a<-reorder(with(data, ax), 
             with(data, col))

  #new_data
  df<-cbind.data.frame(data)
  # define new var
  within(df, 
         do.call("<-",list(paste0(as.character(arguments$axis),"_o"), a)))
}

Ahora, con esta función, puede trazar interactivamente con ggplot2, así:

ggplot(order_axis(df, AXIS_X, COLUMN_Y), 
       aes(x = AXIS_X_o, y = COLUMN_Y)) +
        geom_bar(stat = "identity")

Como se puede ver, la order_axisfunción crea otro marco de datos con una nueva columna llamada igual pero con un _oal final. Esta nueva columna tiene niveles en orden ascendente, por lo que ggplot2 traza automáticamente en ese orden.

Esto es algo limitado (solo funciona para caracteres o factores y combinaciones numéricas de columnas y en orden ascendente) pero aún lo encuentro muy útil para trazar sobre la marcha.

eflores89
fuente
Creo que no veo la ventaja de esto en comparación con solo usarlo reorderdirectamente. ¿No ggplot(df, aes(x = reorder(AXIS_X, COLUMN_Y), y = COLUMN_Y)) + ...hace lo mismo, de manera concisa, y sin la función auxiliar?
Gregor Thomas el