Ordenar barras en el gráfico de barras ggplot2


Estoy tratando de hacer un gráfico de barras donde la barra más grande sería más cercana al eje y y la barra más corta sería más lejos. Así que esto es como la Tabla que tengo

    Name   Position
1   James  Goalkeeper
2   Frank  Goalkeeper
3   Jean   Defense
4   Steve  Defense
5   John   Defense
6   Tim    Striker

Así que estoy tratando de construir un gráfico de barras que muestre el número de jugadores de acuerdo con la posición

p <- ggplot(theTable, aes(x = Position)) + geom_bar(binwidth = 1)

Pero el gráfico muestra la barra de portero primero, luego la defensa, y finalmente el delantero. Me gustaría que el gráfico para ser ordenado de modo que la barra de defensa es más cercano al eje y, el portero uno, y finalmente el delantero uno. Gracias

Author: Roland Ewald, 2011-03-06

10 answers

La clave con el orden es establecer los niveles del factor en el orden que desee. No se requiere un factor ordenado; la información adicional en un factor ordenado no es necesaria y si estos datos se están utilizando en cualquier modelo estadístico, la parametrización incorrecta podría resultar - los contrastes polinómicos no son adecuados para datos nominales como este.

## set the levels in order we want
theTable <- within(theTable, 
                   Position <- factor(Position, 
                                      levels=names(sort(table(Position), 
                                                        decreasing=TRUE))))
## plot
ggplot(theTable,aes(x=Position))+geom_bar(binwidth=1)

figura de barplot

En el sentido más general, simplemente necesitamos establecer los niveles de factores para que estén en el orden deseado. Si se deja sin especificar, los niveles de un factor se ordenarán alfabéticamente. Sin embargo, hay varias maneras de cambiar el orden a una secuencia específica dependiendo de la situación. Por ejemplo, podríamos hacer:

levels(theTable$Position) <- c(...)

Y simplemente enumere los niveles en el orden deseado en el lado derecho. También puede especificar el orden de nivel dentro de la llamada a factor como se indica arriba:

theTable$Position <- factor(theTable$Position, levels = c(...))
 171
Author: Gavin Simpson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-27 18:48:48

@ GavinSimpson: reorder es una solución poderosa y efectiva para esto:

ggplot(theTable,
       aes(x=reorder(Position,Position,
                     function(x)-length(x)))) +
       geom_bar()
 177
Author: Alex Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-05 19:50:11

Usando scale_x_discrete (limits = ...) para especificar el orden de las barras.

positions <- c("Goalkeeper", "Defense", "Striker")
p <- ggplot(theTable, aes(x = Position)) + scale_x_discrete(limits = positions)
 112
Author: QIBIN LI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-02 16:35:27

Creo que las soluciones ya proporcionadas son demasiado detalladas. Una forma más concisa de hacer una gráfica de barras ordenada por frecuencia con ggplot es

ggplot(theTable, aes(x=reorder(Position, -table(Position)[Position]))) + geom_bar()

Es similar a lo que sugirió Alex Brown, pero un poco más corto y funciona sin una definición de función anynymous.

Update

Creo que mi antigua solución era buena en ese momento, pero hoy en día prefiero usar forcats::fct_infreq que es ordenar los niveles de factor por frecuencia:

require(forcats)

ggplot(theTable, aes(fct_infreq(Position))) + geom_bar()
 68
Author: Holger Brandl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-11 14:58:56

Solo necesita especificar la columna Position para ser un factor ordenado donde los niveles están ordenados por sus recuentos:

theTable <- transform( theTable,
       Position = ordered(Position, levels = names( sort(-table(Position)))))

(Tenga en cuenta que el table(Position) produce un recuento de frecuencias de la columna Position.)

Entonces su función ggplot mostrará las barras en orden decreciente de conteo. No se si hay una opción en geom_bar para hacer esto sin tener que crear explícitamente un factor ordenado.

 16
Author: Prasad Chalasani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 14:53:46

Como reorder() en la respuesta de Alex Brown, también podríamos usar forcats::fct_reorder(). Básicamente ordenará los factores especificados en el 1er arg, de acuerdo con los valores en el 2do arg después de aplicar una función especificada (default = median, que es lo que usamos aquí ya que solo tenemos un valor por nivel de factor).

Es una pena que en la pregunta del OP, el orden requerido también sea alfabético, ya que es el orden de clasificación predeterminado cuando crea factores, por lo que ocultará lo que esta función está haciendo realmente. A que quede más claro, voy a reemplazar "Portero"con " Zoalkeeper".

library(tidyverse)
library(forcats)

theTable <- data.frame(
                Name = c('James', 'Frank', 'Jean', 'Steve', 'John', 'Tim'),
                Position = c('Zoalkeeper', 'Zoalkeeper', 'Defense',
                             'Defense', 'Defense', 'Striker'))

theTable %>%
    count(Position) %>%
    mutate(Position = fct_reorder(Position, n, .desc = TRUE)) %>%
    ggplot(aes(x = Position, y = n)) + geom_bar(stat = 'identity')

introduzca la descripción de la imagen aquí

 16
Author: user2739472,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-08 13:35:47

Un simple reordenamiento de factores basado en dplyr puede resolver este problema:

library(dplyr)

#reorder the table and reset the factor to that ordering
theTable %>%
  group_by(Position) %>%                              # calculate the counts
  summarize(counts = n()) %>%
  arrange(-counts) %>%                                # sort by counts
  mutate(Position = factor(Position, Position)) %>%   # reset factor
  ggplot(aes(x=Position, y=counts)) +                 # plot 
    geom_bar(stat="identity")                         # plot histogram
 15
Author: zach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-04 14:32:17

Estoy de acuerdo con zach en que contar dentro de dplyr es la mejor solución. He encontrado que esta es la versión más corta:

dplyr::count(theTable, Position) %>%
          arrange(-n) %>%
          mutate(Position = factor(Position, Position)) %>%
          ggplot(aes(x=Position, y=n)) + geom_bar(stat="identity")

Esto también será significativamente más rápido que reordenar los niveles de factor de antemano, ya que el recuento se realiza en dplyr no en ggplot o utilizando table.

 9
Author: Alexandru Papiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-04 16:29:43

Además De forcats::fct_infreq, mencionado por @HolgerBrandl, está forcats:: fct_rev, que invierte el orden de los factores.

theTable <- data.frame(
    Position= 
        c("Zoalkeeper", "Zoalkeeper", "Defense",
          "Defense", "Defense", "Striker"),
    Name=c("James", "Frank","Jean",
           "Steve","John", "Tim"))

p1 <- ggplot(theTable, aes(x = Position)) + geom_bar()
p2 <- ggplot(theTable, aes(x = fct_infreq(Position))) + geom_bar()
p3 <- ggplot(theTable, aes(x = fct_rev(fct_infreq(Position)))) + geom_bar()

gridExtra::grid.arrange(p1, p2, p3, nrow=3)             

salida de gplot

 9
Author: Robert McDonald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-25 20:19:04

Si las columnas del gráfico provienen de una variable numérica como en el dataframe a continuación, puede usar una solución más simple:

ggplot(df, aes(x = reorder(Colors, -Qty, sum), y = Qty)) 
+ geom_bar(stat = "identity")  

El signo menos antes de la variable de ordenación (- Qty) controla la dirección de ordenación (ascendente/descendente)

Aquí hay algunos datos para probar:

df <- data.frame(Colors = c("Green","Yellow","Blue","Red","Yellow","Blue"),  
                 Qty = c(7,4,5,1,3,6)
                )

**Sample data:**
  Colors Qty
1  Green   7
2 Yellow   4
3   Blue   5
4    Red   1
5 Yellow   3
6   Blue   6

Cuando encontré este hilo, esa era la respuesta que estaba buscando. Espero que sea útil para otros.

 3
Author: JColares,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-03 07:17:19