Transformar el Eje a Escala Porcentual en {ggplot2}

Cuando representamos gráficamente una variable cuya unidad de medida es porcentual es ideal que las etiquetas del eje contengan el símbolo de porcentaje (%). Así será evidente para cualquiera que vea el gráfico que lo que se refleja son porcentajes.

Para ilustrar esto vamos a crear un conjunto de datos de ejemplo.

library(dplyr)
data(mtcars)

cyl <- mtcars %>%
  count(cyl) %>%
  mutate(pct = n / sum(n) * 100) %>%
  print()
##   cyl  n    pct
## 1   4 11 34.375
## 2   6  7 21.875
## 3   8 14 43.750

Para crear una gráfico de barras de estos datos usaré mi paquete ggcharts que ofrece una interfaz de alto nivel para producir gráficos usando ggplot2

library(ggcharts)
(p <- bar_chart(cyl, cyl, pct))

Ahora vamos a tratar de cambiar las etiquetas del eje para que incluyan el símbolo de porcentaje usando la función percent()del paquete scales.

p + scale_y_continuous(labels = scales::percent)

¡Pero no está bien, 4000%? Parece un poco excesivo. El problema es que, por defecto, scales::percent() multiplica por 100 los valores de entrada. Esto se puede ajustar con el parámetro scale.

scales::percent(100, scale = 1)
## [1] "100%"

Sin embargo, scale_y_continous() espera recibir una función como entrada de su parámetro labels, no las propias etiquetas. Por lo tanto, usar percent() no es una opción válida. Afortunadamente, el paquete scalestiene una función llamada percent_format() que devuelve la función percent() con las opciones cambiadas.

pct1 <- scales::percent_format(scale = 1)
pct1(100)
## [1] "100%"

Al pasar esta función a labels obtenemos el resultado deseado.

p + scale_y_continuous(labels = scales::percent_format(scale = 1))

Otra opción es simplemente calcular la fracción en vez del porcentaje.

cyl2 <- mtcars %>%
  count(cyl) %>%
  mutate(pct = n / sum(n))

bar_chart(cyl2, cyl, pct) +
  scale_y_continuous(labels = scales::percent)

Sin embargo, ahora todas las etiquetas se reflejan con un valor decimal. Creo que esto no es adecuado dado que las etiquetas son números enteros.

Para resolver esto, usamos la función percent_format() que tiene un parámetro llamado accuracy.

bar_chart(cyl2, cyl, pct) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1))

Para mí todo esto es, por lo menos, confuso. Por eso decidí crear una mejor solución. Al final, debe ser posible determinar scale y accuracy directamente a partir de los datos, ¿no?.

Mi solución es la función scale_y_pct()que es parte de mi paquete scalesextra.

library(scalesextra)
bar_chart(cyl, cyl, pct) + scale_y_pct()

bar_chart(cyl2, cyl, pct) + scale_y_pct()

Como puedes ver, los datos se escalan correctamente independientemente de que sean una fracción de 1 o un porcentaje. Además, en ningún caso se muestran los decimales puesto que todas las etiquetas son enteros.

A scale_y_pct() se le pueden pasar cualquiera de los parámetros de scale_y_continuous(), p. ej. breaks.

bar_chart(cyl, cyl, pct) + scale_y_pct(breaks = c(12.5, 30.75))

Nótese que el número de decimales que se muestran es consistente para todas las etiquetas y se determina automáticamente a partir del valor con el mayor número de decimales. Una vez más, esto no sucede automáticamente cuando se usa percent_format().

bar_chart(cyl, cyl, pct) +
  scale_y_continuous(
    labels = scales::percent_format(scale = 1),
    breaks = c(12.5, 30.75)
  )

scalesextra está en una fase muy precoz de desarrollo y por lo tanto sólo está dispobible en GitHub. Lo puedes instalar ejecutando los siguientes comandos en la consola de R

if (!"remotes" %in% installed.packages()) {
  install.packages("remotes")
}
remotes::install_github("thomas-neitmann/scalesextra")

Por favor, prueba scale_y_pct() (y su hermana scale_x_pct()) y dime lo que opinas de ellas en los comentarios. Si encuentras algún error (lo que es muy probable dado que está en una fase de desarrollo temprana), por favor abre un issue en GitHub. Este artículo ha sido traducido del original en inglés por Gustavo Zapata Wainberg.