R que R

Data Visualization: Bar chart race con {gganimate}

Thu, Oct 31, 2019
R Data Visualization
#dplyr #tidyverse #ggplot2 #Bar chart Race


Gráfico animado del VAB


Últimamente se ha hecho bastante popular en las redes sociales un gráfico animado (denominados bar chart race) donde se muestra la evolución del ranking de distintas economías, generalmente países, según su PIB o su PIB por habitante. En estos gráficos, generalmente gráficos de barras, se va observando para cada año que países ocupan los primeros puestos en el ranking y cómo han ido evolucionando a lo largo del tiempo. Suele sorprender el rápido avance que ha registrado China, país que ha sufrido grandes transformaciones económicas y sociales en las últimas décadas.


En este post vamos a mostrar cómo realizar un gráfico de estas carcterísticas. En esta ocasión vamos a mostrar la evolución del ranking de regiones peruanas según su VAB per cápita para el periodo 1996-2016. Perú está dividido en 24 regiones y una Provincia Constitucional que es El Callao (en esta ocasión Lima y El Callao se contabilizan conjuntamente). Las series históricas, que deflactamos previamente para obtener una sóla coherente para todo el periodo en miles de Soles constantes de 1994, la obtenemos del Instituto Nacional de Estadística e Informática del Perú (INEI).


Preparación del dataset


En primer lugar descargamos los siguientes paquetes en nuestra sesión:



library(readxl)
library(tidyverse)
library(gganimate)


Cargamos el dataset con read_excel() y observamos los datos, previamente deflactados, de las regiones peruanas obtenidos del INEI para el periodo de tiempo 1995-2016. Las primeras diez observaciones del dataset las podemos seleccionar con la función head()



Peru <- read_excel("./datasets/Peru_vabpc_95_16.xlsx")
head(Peru, n = 10)
## # A tibble: 10 x 24
##    Nombre Area  `1995` `1996` `1997` `1998` `1999` `2000` `2001` `2002` `2003`
##    <chr>  <chr>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
##  1 Amazo~ Selva  1680.  1853.  1824.  1924.  1840.  1863.  1835.  1910.  1996.
##  2 Áncash Sier~  3164.  3361.  3294.  3022.  3604.  3638.  4037.  4703.  4772.
##  3 Apurí~ Sier~  1349.  1413.  1447.  1355.  1436.  1397.  1216.  1278.  1334.
##  4 Arequ~ Costa  5037.  5019.  5298.  5202.  5191.  5283.  5387.  5766.  5895.
##  5 Ayacu~ Sier~  1648.  1681.  1763.  1789.  1801.  1810.  1788.  1870.  1942.
##  6 Cajam~ Sier~  1922.  1938.  2151.  2335.  2469.  2547.  2493.  2731.  2947.
##  7 Cusco  Sier~  2175.  2172.  2310.  2308.  2234.  2253.  2194.  2086.  2195.
##  8 Huanc~ Sier~  2602.  2760.  2929.  2938.  2940.  2793.  2700.  2632.  2683.
##  9 Huánu~ Sier~  1671.  1727.  1795.  1726.  1730.  1755.  1678.  1694.  1833.
## 10 Ica    Costa  4232.  4114.  4387.  4050.  4125.  4218.  4055.  4259.  4343.
## # ... with 13 more variables: `2004` <dbl>, `2005` <dbl>, `2006` <dbl>,
## #   `2007` <dbl>, `2008` <dbl>, `2009` <dbl>, `2010` <dbl>, `2011` <dbl>,
## #   `2012` <dbl>, `2013` <dbl>, `2014` <dbl>, `2015` <dbl>, `2016` <dbl>


Para transformar el formato ancho a un formato largo, más apropiado para su manejo, podemos utilizar la función gather() como se indica a continuación. El resultado serán cuatro columnas, una donde se indicará el nombre de la región, una segunda columna que indicará si la región es de Sierra, Selva o Costa (clasificación que suele utilizarse en Perú para clasificar las regiones aunque existen otras que seleccionan las regiones en un mayor número de subcategorías), una tercera columna que indicará el año que representa cada observacion y una última columna que indicará el valor del Valor Agregado Bruto por habitante para cada región en cada uno de los años del periodo.



Peru <- Peru %>% 
  gather(key= "year", value= "vabpc", 3:24 ) 
head(Peru)
## # A tibble: 6 x 4
##   Nombre    Area   year  vabpc
##   <chr>     <chr>  <chr> <dbl>
## 1 Amazonas  Selva  1995  1680.
## 2 Áncash    Sierra 1995  3164.
## 3 Apurímac  Sierra 1995  1349.
## 4 Arequipa  Costa  1995  5037.
## 5 Ayacucho  Sierra 1995  1648.
## 6 Cajamarca Sierra 1995  1922.


Como el objetivo es realizar un gráfico que muestre el ranking de regiones por cada año según su VAB por habitante lo primero que debemos realizar es identificar el puesto ocupa cada región para cada año según dicho indicador. Para ello utilizamos la función rank() de la siguiente forma:



Peru_rangos <- Peru %>%
  group_by(year) %>%
  mutate(rango = rank(-vabpc),
         labels = paste0(" ", round(vabpc)))


Si ordenamos nuestro nuevo data set por año y rango con la función arrange() del paquete tidyverse podemos observar el resultado del ranking realizado. Se comprueba que para el año inicial, 1995, la región de Moquegua, una región costera pequeña situada en el sur del país, lidera el ranking seguido por las regiones de Tacna (costa), Lima (costa), Madre de Dios (selva) y Pasco (sierra). Esta clasificación se ha realizado para cada uno de los años del periodo.



Peru_rangos %>%
  arrange(year, rango) 
## # A tibble: 528 x 6
## # Groups:   year [22]
##    Nombre        Area   year  vabpc rango labels 
##    <chr>         <chr>  <chr> <dbl> <dbl> <chr>  
##  1 Moquegua      Costa  1995  8780.     1 " 8780"
##  2 Tacna         Costa  1995  6555.     2 " 6555"
##  3 Lima          Costa  1995  6382.     3 " 6382"
##  4 Madre de Dios Selva  1995  5325.     4 " 5325"
##  5 Pasco         Sierra 1995  5122.     5 " 5122"
##  6 Arequipa      Costa  1995  5037.     6 " 5037"
##  7 Ica           Costa  1995  4232.     7 " 4232"
##  8 Tumbes        Costa  1995  3170.     8 " 3170"
##  9 Áncash        Sierra 1995  3164.     9 " 3164"
## 10 Junín         Sierra 1995  3127.    10 " 3127"
## # ... with 518 more rows


Gráfico animado con gganimate


Una vez hemos preparado el dataset procedemos a realizar el gráfico animado. Llamaremos al gráfico plot_peru y lo guardamos con dicho nombre. Utilizaremos el color azul para identificar las regiones mayoritariamente costeras, el color verde las regiones selváticas y el color marrón indicará las regiones cuyo territorio es mayoritariamente de sierra o montañoso. El nombre de los colores utilizados, seleccionados con la función scale_fill_manual() se han obtenido del siguiente link: http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf



plot_peru <- ggplot(Peru_rangos, aes(rango, group = Nombre, 
                            fill = Area)) +
  geom_col(aes(y = vabpc), alpha = 0.9, color = "white") +
  coord_flip(clip = "off", expand = FALSE) +
  geom_text(aes(y = 0, label = paste(Nombre, " ")), vjust = 0.2, hjust = 1) +
  geom_text(aes(y= vabpc, label = labels, hjust = 0)) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse() +
  scale_fill_manual(values=c("cornflowerblue", "green3", "darkorange")) +
  guides(color = FALSE, fill = FALSE) +
  transition_states(year, transition_length = 1, state_length = 1, wrap= F) + 
  labs(title = 'Perú. Regiones según su VAB per cápita',  
       subtitle  =  "Año : {closest_state}",
       caption  = "Miles de Soles constantes de 1994 | Fuente: INEI") +
  theme(
    legend.position="none",
    plot.title=element_text(size=18, hjust=0.5, face="bold", colour="grey20", vjust=-1),
    plot.subtitle=element_text(size = 18, hjust=0.5, face="plain", color="grey20"),
    plot.caption =element_text(size = 10, hjust=0.5, face="plain", color="grey20"),
    axis.line=element_blank(),
    plot.margin = margin(2,2, 2, 4, "cm"), 
    plot.background=element_blank(),
    axis.text.x=element_blank(),
    axis.text.y=element_blank(),
    axis.ticks=element_blank(),
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    panel.grid.minor=element_blank(),
    panel.grid.major=element_blank(),
    panel.background=element_blank(),
    panel.border=element_blank(),
    panel.grid.major.x = element_line( size=.1, color="grey80", linetype = "dashed" ),
    panel.grid.minor.x = element_line( size=.1, color="grey80", linetype = "dashed" )
  )


Una vez tenemos el código representamos el gráfico animado con animate().



animate(plot_peru, width = 600, height = 600, fps = 5)


Vemos claramente la totalidad de regiones y cómo van evolucionando en el ranking a lo largo de los años. Entre ellas la región de Moquegua mantiene claramente una posición privilegiada a lo largo de todo el periodo. No obstante, se observa también que otro conjunto de regiones, principalmente regiones costeras como Lima, Arequipa, Ica o Tacna, han ido con el paso de los años acercando su nivel de renta per cápita con respecto al VAB por habitante de Moquegua. Por el contrario, en la parte inferior del ranking, un conjunto de regiones, principalmente regiones andinas, parecen consolidarse en las posiciones más desfavorables con respecto al resto de regiones peruanas. Sorprende especialmente el caso de Apurímac, región que se sitúa en la última posición a lo largo de la mayor parte del periodo analizado, pero que en 2016 mejora notablemente su posición en el ranking sitúandose en el quinto puesto. En este sentido conviene tener en cuenta el papel de la minería, actividad económica de gran productividad que representa una gran parte del VAB total en algunas regiones, especialmente en aquellas con economías menos desarrolladas y con una menor participación de actividades de servicios. El notable cambio sufrido por la región de Apurímac habrá tenido que ver, sin duda, con un incremento importante de la actividad extractiva en estos últimos años, lo que habrá contribuido sustancialmente al incremento del Valor Agregado Bruto de esta región. Consecuentemente, un posible análisis para un futuro post consistirá en identificar qué porcentaje del VAB por habitante de cada región responde a la actividad extractiva y en qué medida dicho sector influye en la posición relativa de las regiones mineras en el ranking que refleja nuestro gráfico.


Otra dinámica que podemos extraer de la evolución que refleja el gráfico es la creciente brecha existente entre las regiones peruanas en términos de VAB por habitante a lo largo de las últimas décadas. Sin duda, las regiones costeras del país, especialmente aquellas que por lo general presentan economías más diversificadas y modernas, han ido incrementando a lo largo de los años su VAB por habitante en gran medida, especialmente en relación con la mayor parte de regiones de sierra y selva del país. Todo parece indicar que las disparidades territoriales presentes históricamente en el país, especialmente aquellas disparidades existentes entre algunas de las regiones del litoral peruano y el resto del país, se han incrementado a lo largo del periodo analizado. El llamado milagro peruano no parece haber sido un fenómeno territorialmente equilibrado sino que parece haber contribuido a incrementar los desequilibrios regionales existentes en el país latinoamericano.


Por último, supongamos que queremos seleccionar únicamente los primeros puestos en el ranking. Para ello podemos filtrar nuestras observaciones con la función filter() de dplyr para reducir el número de observaciones a tener en cuenta en el gráfico final. A modo de ejemplo seleccionamos los diez primeros puestos del ranking tal y como vemos en el código siguiente.



Peru_rangos_top <- Peru %>%
  group_by(year) %>%
  mutate(rango = rank(-vabpc),
         labels = paste0(" ", round(vabpc))) %>%
  group_by(Nombre) %>%
  filter(rango <=10) %>%
  ungroup()


Consecuentemente, utilizando el nuevo dataframe Peru_rangos_top, y realizando pequeñas modificaciones al código anterior podemos visualizar la evolución de las regiones que ocupaban los primeros diez puestos en el ranking según su VAB por habitante. En esta ocasión cambiamos los colores utilizados en el gráfico previo, cambiamos el título, el subtítulo y algún otro aspecto del nuevo gráfico. Cómo hicimos previamente guardamos el nuevo gráfico, en este caso como plot_peru_top, y posteriormente procedemos a realizar la animación correspondiente con animate().



plot_peru_top <- ggplot(Peru_rangos_top, aes(rango, group = Nombre, 
                            fill = Area)) +
  geom_col(aes(y = vabpc), alpha = 0.9, color = "grey20") +
  coord_flip(clip = "off", expand = FALSE) +
  geom_text(aes(y = 0, label = paste(Nombre, " ")), vjust = 0.2, hjust = 1) +
  geom_text(aes(y= vabpc, label = labels, hjust = 0, size = 1)) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse() +
  scale_fill_manual(values=c("royalblue", "limegreen", "goldenrod4")) +
  guides(color = FALSE, fill = FALSE) +
  transition_states(year, transition_length = 1, state_length = 1, wrap= F) + 
  labs(title = 'Perú. Regiones según su VAB per cápita (Top 10)',  
       subtitle  =  "Año : {closest_state}",
       caption  = "Miles de Soles constantes de 1994 | Fuente: INEI") +
  theme(
    legend.position="none",
    plot.title=element_text(size=18, hjust=0.5, face="bold", colour="grey20", vjust=-1),
    plot.subtitle=element_text(size = 26, hjust=0.5, face="bold", color="grey20"),
    plot.caption =element_text(size = 10, hjust=0.5, face="plain", color="grey20"),
    axis.line=element_blank(),
    plot.margin = margin(2,2, 2, 4, "cm"), 
    plot.background=element_blank(),
    axis.text.x=element_blank(),
    axis.text.y=element_blank(),
    axis.ticks=element_blank(),
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    panel.grid.minor=element_blank(),
    panel.grid.major=element_blank(),
    panel.background=element_blank(),
    panel.border=element_blank(),
    panel.grid.major.x = element_line( size=.1, color="grey80", linetype = "dashed" ),
    panel.grid.minor.x = element_line( size=.1, color="grey80", linetype = "dashed" )
  )



animate(plot_peru_top, width = 600, height = 600, fps = 7)