R que R

Data Visualization: gráficos de barras animados con {gganimate}

Mon, Oct 14, 2019
R Data Visualization
#gganimate #dplyr #tidyverse #ggplot2 #babynames


¿Qué es {gganimate}?


{gganimate} es una extensión del paquete {ggplot2} diseñado para crear gráficos de ggplot animados. De esta forma podemos ver de forma dinámica en un mismo gráfico, por ejemplo, cómo la información ha ido evolucionando con el paso de los años. A modo de ejemplo vamos a crear tres gráficos, utilizando de nuevo el dataframe babynames, que servirán como continuación del post anterior donde expusimos las principales funcionalidades del paquete {dplyr}.


Generamos un nuevo data frame con {dplyr}


Empezamos descargando los siguientes paquetes:



library(tidyverse)
library(lubridate)
library(gganimate)
library(png)
library(gifski)
library(babynames)


En primer lugar identificamos la cantidad de registros de la tarjeta de la Seguridad Social en Estados Unidos por año y por sexo utilizando la función group_by() y summarize() del paquete {dplyr} tal y como vimos en el post previo. De esta forma, sumando el número de registros de cada nombre por sexo y año obtenemos un nuevo data frame del total de solicitudes por año desde 1880 hasta 2017. Llamaremos al nuevo data frame babynames_year.



babynames_year <- babynames %>%
  group_by(year, sex) %>%
  summarize(suma=sum(n))
## `summarise()` regrouping output by 'year' (override with `.groups` argument)


Las primeras filas del nuevo data frame son, por tanto, las siguientes:



head(babynames_year)
## # A tibble: 6 x 3
## # Groups:   year [3]
##    year sex     suma
##   <dbl> <chr>  <int>
## 1  1880 F      90993
## 2  1880 M     110491
## 3  1881 F      91953
## 4  1881 M     100743
## 5  1882 F     107847
## 6  1882 M     113686


Vemos que el dataframe babynames_year muestra para cada año del periodo (1880-2017) la suma de los registros para el sexo femenino (F) y para el sexo masculino (M). Utilizaremos este data frame para la realización de los gráficos en los siguientes apartados.


Gráficos de barras animados con {gganimate}

 

Para hacer un primer gráfico dinámico donde podamos identificar dos columnas paralelas para cada uno de los sexos podemos utilizar un código similar al siguiente:



# En primer lugar guardamos el gráfico con el nombre plot_babynames_dodge

plot_babynames_dodge <- babynames_year %>%
  ggplot(aes(x = sex, 
             y = suma, 
             fill= sex )) +
  geom_bar(stat= "identity", 
           color = "white", 
           show.legend = FALSE) +
  geom_text(aes(label = as.numeric(suma)), 
            position = position_dodge(0.9), 
            vjust= 1.2, 
            size = 5, 
            color = "white")+
  scale_fill_manual(values = c("orange", "darkgrey")) +
  scale_y_continuous(labels = scales::comma) +
  theme_minimal()+
  enter_appear() +
  transition_states(year, 
                    transition_length = 1.5, 
                    state_length = 2) +
  labs(title = " Recién nacidos en EE.UU por sexo \n Year : {closest_state}", 
       subtitle = "Solicitudes de la tarjeta de la Seguridad Social",
       y = "",
       x = "", 
       caption = "US Social Security Administration") +
  theme(panel.grid.major.x = element_blank(),
        plot.title = element_text(size = 18, 
                                  face = "bold", 
                                  hjust = 0.5),
        plot.subtitle = element_text(size=14, 
                                     face = "plain", 
                                     hjust = 0.5)) 


Graficamos el primer plot con animate()



animate(plot_babynames_dodge, nframes= 300, width = 600, height= 600, fps = 10)


# guardamos el gráfico en formato .gif

anim_save("plot_babynames_dodge.gif")


Para hacer un segundo gráfico dinámico donde podamos identificar en una sola columna los dos géneros (stacked) podemos realizar las siguientes modificaciones al gráfico original:



# En primer lugar guardamos el gráfico con el nombre plot_babynames_stack

plot_babynames_stack <- babynames_year %>%
  ggplot(aes(x = " ", 
             y = suma, 
             fill= sex )) +
  geom_bar(stat= "identity", 
           color = "white", 
           show.legend = TRUE) +
  geom_text(aes(label = as.factor(suma)), 
            position = position_stack(vjust = 0.5), 
            size = 5, 
            color = "white")+
  scale_fill_manual(values = c("orange", "darkgrey")) +
  scale_y_continuous(labels = scales::comma) +
  enter_appear() +
  transition_states(year, 
                    transition_length = 1.5, 
                    state_length = 2) +
  labs(title = " Recién nacidos en EE.UU por sexo \n Year : {closest_state}", 
       subtitle = "Solicitudes de la tarjeta de la Seguridad Social",
       y = "",
       x = "", 
       caption = "US Social Security Administration") +
  theme_minimal() +
  theme(panel.grid.major.x = element_blank(),
        plot.title = element_text(size = 18, 
                                  face = "bold", 
                                  hjust = 0.5),
        plot.subtitle = element_text(size=14, 
                                     face = "plain", 
                                     hjust = 0.5)) 


Graficamos el segundo plot con animate()



animate(plot_babynames_stack, nframes= 300, width = 600, height = 600, fps = 10) 


# guardamos el gráfico en formato .gif

anim_save("plot_babynames_stack.gif")


Transición con {gganimate}


{gganimate} permite también visualizar la transición de las observaciones a lo largo del tiempo. Para explicar esta nueva aplicación de {gganimate} partimos del siguiente gráfico (utilizado en un post previo) donde se muestra la evolución del número total de registros de solicitud de la tarjeta de la Seguridad Social en Estados Unidos desde 1880 hasta 2017:



babynames %>%
  group_by(year) %>% 
  summarise(suma = sum(n)) %>%
  ggplot(aes(x= year, y = suma, fill = "orange")) +
  geom_col() +
  scale_y_continuous(labels = scales::comma) + 
  theme_minimal() +
  guides(fill=F) +
  labs( x= "year", 
        y= " ",
        title = "Número de personas recién nacidas en Estados Unidos desde 1880 hasta 2017",
        subtitle = "Estimado en base al número de solicitudes de la tarjeta de la Seguridad Social",
        caption =  "US Social Security Administration") +
  theme(plot.title = element_text(size = 16, 
                                  face = "bold", 
                                  hjust = 0.5),
        plot.subtitle = element_text(size=12, 
                                     face = "plain", 
                                     hjust = 0.5))
## `summarise()` ungrouping output (override with `.groups` argument)


Partiendo de este gráfico podemos utilizar {gganimate} para visualizar la transición año tras año a lo largo del periodo utilizando la siguiente orden:



plot_babynames_transition <- babynames %>%
  group_by(year) %>% 
  summarise(suma = sum(n)) %>%
  ggplot(aes(x= year, y = suma, fill = "orange")) +
  geom_col() +
  scale_y_continuous(labels = scales::comma) + 
  theme_minimal() +
  guides(fill=F) +
  labs( x= "year", 
        y= " ",
        title = "Número de personas recién nacidas en Estados Unidos desde 1880 hasta 2017 \n Year : {closest_state}", 
        subtitle = "Estimado en base al número de solicitudes de la tarjeta de la Seguridad Social",
        caption =  "US Social Security Administration") +
  transition_states(year, wrap = F) +
  shadow_mark() +
  enter_grow() +
  enter_fade() +
  theme(plot.title = element_text(size = 18, 
                                  face = "bold", 
                                  hjust = 0.5),
        plot.subtitle = element_text(size=14, 
                                     face = "plain", 
                                     hjust = 0.5))
## `summarise()` ungrouping output (override with `.groups` argument)


Graficamos el tercer plot con animate()



animate(plot_babynames_transition, nframes= 300, width = 900, height = 500, fps = 10)


# guardamos el gráfico en archivo .gif

anim_save("plot_babynames_transition.gif")


Seleccionando un menor número de años se puede observar mejor como {gganimate} visualiza la transición entre años. Seleccionamos del conjunto del dataframe, por ejemplo, los primeros años del siglo XX, periodo en el que tuvieron lugar hechos históricos importantes con un importante impacto sobre la natalidad de Estados Unidos.



plot_babynames_transition_2 <- babynames %>%
  filter(year > 1910 & year < 1951) %>%
  group_by(year) %>% 
  summarise(suma = sum(n)) %>%
  ggplot(aes(x= year, y = suma, fill = "orange")) +
  geom_col() +
  scale_y_continuous(labels = scales::comma) + 
  theme_minimal() +
  guides(fill=F) +
  labs( x= "year", 
        y= " ",
        title = "Número de personas recién nacidas en Estados Unidos desde 1910 hasta 1950 \n Year : {closest_state}", 
        subtitle = "Estimado en base al número de solicitudes de la tarjeta de la Seguridad Social",
        caption =  "US Social Security Administration") +
  transition_states(year, wrap = F) +
  shadow_mark() +
  enter_grow() +
  enter_fade() +
  theme(plot.title = element_text(size = 18, 
                                  face = "bold", 
                                  hjust = 0.5),
        plot.subtitle = element_text(size=14, 
                                     face = "plain", 
                                     hjust = 0.5))
## `summarise()` ungrouping output (override with `.groups` argument)


Graficamos el nuevo plot con animate()



animate(plot_babynames_transition_2, nframes= 150, width = 900, height = 500, fps = 10)


# guardamos el gráfico en archivo .gif

anim_save("plot_babynames_transition_2.gif")