Gráficos animados con ggplot (y algunas cosas más)

Analizar datos y representar información visualmente se ha convertido progresivamente en una parte cada vez más importante de mi trabajo, algo que desde luego no esperaba hace algunos años cuando empecé a aprender R un poco por casualidad. No ha habido una intencionalidad demasiado fuerte en el proceso. Por una parte, me gusta mucho programar y es un tipo de trabajo que me resulta entretenido. Por otra, ir aprendiendo técnicas de análisis de datos y cogiendo fluidez al aplicarlas me ha abierto una serie de puertas y posibilidades para responder a las preguntas de investigación que me planteo en mi trabajo.

Casi todo lo que sé sobre R lo he aprendido en Datacamp y/o ‘googling the error message’. Una de las cosas más maravillosas de R es que no importa qué problema estés teniendo: siempre habrá alguien que lo tuvo antes que tú, y el 99% de las veces, si sabes buscar, encontrarás a alguien que haya compartido una forma de arreglar tu código.

De un tiempo a esta parte, cada vez más gente ha empezado a hacerme preguntas sobre R, y el 90% de estas preguntas han sido sobre mis gráficos. Esto me  ha llevado a pensar que ya iba siendo hora de poner mi granito de arena al proceso del párrafo anterior, y me he decidido a iniciar una serie de posts sobre gráficos en ggplot, en la que me gustaría, básicamente, compartir algunas de las técnicas que más uso y de los recursos que más útiles me resultan en este proceso.

Si el 90% de preguntas que recibo sobre R son sobre gráficos, al menos la mitad de las mismas son sobre los gráficos en formato gif que publico a veces en Twitter.  Como el proceso de animar un gráfico es en realidad bastante sencillo, he  pensado en enseñaros alguna cosa más por el camino.

Cargando librerías y poniendo los datos en orden

Vamos a necesitar el paquete tidyverse para hacer alguna cosa a los datos y porque incluye ggplot2, ineq porque lo que vamos a representar son datos de desigualdad,y gganimate para crear los gifs. Yo voy a cargar también gameofthrones, que es un paquete con paletas de colores inspiradas en la serie y que son las que voy a usar, pero esto es obviamente opcional (si queréis descargarlo, lo tenéis aquí).

library(tidyverse)
library(ineq)
library(gganimate)
library(gameofthrones)

Para aprender a hacer las animaciones vamos a utilizar datos de renta (que son los que tenía abiertos en R cuando se me ocurrió hacer esto) provenientes de la Encuesta de Condiciones de Vida. Si os interesan, podéis descargarlos aquí. Como sería muy poco práctico ponerme a trabajar con el DataFrame completo que tengo cargado (algo más de 300.000 observaciones de 50 variables), lo primero es seleccionar lo que necesito y darle forma. Mi idea es representar la evolución del coeficiente Gini por grupos de edad en España a partir de la crisis. Para ello, voy a utilizar datos de renta neta por hogares divididos entre las unidades de consumo de los mismos.

A continuación, selecciono las variables que necesito (año, renta y grupos de edad). Después, como lo que quiero representar es la desigualdad para cada grupo de edad en cada punto del tiempo, uso group by para agrupar los datos, y con summarize y la función Gini() calculo el coeficiente Gini para cada grupo:

#Cargo mis datos
load("ecv.Rdata")

#Y les doy forma
ecv_graf %
select(year, inc_disp_hh_pc, agegroups)%>%
group_by(year, agegroups)%>%
summarize(gini_c = Gini(inc_disp_hh_pc))

Esta es la forma que tiene ahora el data frame:

df

Ahora que tenemos datos, el primer paso es representarlos. Primero vamos a hacer un gráfico básico sin muchas complicaciones para poder trabajar a partir de él, luego uno un poco más bonito y por último vamos a introducir animaciones.

Gráfico básico

Representar estos datos en ggplot es bastante sencillo. Solo tenemos que hacer geom_line(), geom_point(), elegir un tema predefinido y no hay más que pensar. El gráfico va a representar la información que queremos. Sería algo así:


ecv_graf%>%
ggplot(aes(x = year, y = gini_c, color = agegroups))+
geom_line( )+
geom_point()+
xlab("Año")+
ylab("Coeficiente Gini")+
labs(color = "Edad")+
ggtitle("Desigualdad Generacional en España")+
theme_minimal()

grafico_base

Gráfico editado

No hay nada malo per se en este gráfico, pero parece obvio que podemos mejorarlo bastante y hacerlo un poco más personal. Ggplot nos da un montón de opciones para esto. Para el siguiente gráfico, voy a coger el anterior y llevar a cabo el proceso que sigo habitualmente:

  • El tema: Los temas predefinidos de R están muy bien, pero a mí me gusta dar una cierta coherencia visual propia a mis gráficos. Con la función theme() en ggplot puedes cambiar casi todo lo que se te ocurra, así que antes del gráfico os pongo el objeto temático que suelo utilizar yo para mis gráficos. Obviamente esto es un gusto personal, pero a mí me gustan los títulos centrados, y el texto de los ejes y comentarios ligeramente más pequeño y claro que el del resto del gráfico.
  • Los colores: Los colores por defecto de R empiezan a estar algo vistos ya. Yo suelo hacer las escalas a mano, pero para este gráfico voy a utilizar la escala de Daenerys Targaryen del paquete de GOT porque me parece bonita y porque Dany es quien merece el Trono de Hierro más que nadie.
  • A vueltas con los ejes: Una vez más, esto es una opinión personal, pero no soy amiga de poner títulos a los ejes si eres capaz de incluir la información en otro sitio. En este caso, creo que en el eje x se entiende claramente que son años (aunque hay que cambiar los cortes de sitio) y voy a colocar la información relativa al eje y en un subtítulo para evitar que tengamos que estar girando la cabeza para poder leer el gráfico (otra solución sería esta).
  • La leyenda: Mi preferencia personal con las leyendas es similar a la de los ejes. Si se puede incluir la información en el gráfico, fuera. En este caso, es posible añadir los valores de los grupos de edad con anotaciones hechas a mano. Es un poco laborioso, pero a mí me gusta más el resultado.

 #Objeto modificando las características del tema

tema_ari %
ggplot(aes(x = year, y = gini_c, color = agegroups))+
geom_line(alpha = 0.5)+ #Pongo el alpha algo bajo para que haya más contraste con los puntos
geom_point(size = 0.9)+ 

#las siguientes líneas son las anotaciones hechas a mano:
annotate("text", x = 2009, y = 0.355, label = "0-17", color = "#792427", fontface = "bold", size = 3)+
annotate("text", x = 2012.5, y = 0.325, label = "18-35", color = "#545058", fontface = "bold", size = 3)+
annotate("text", x = 2015, y = 0.350, label = "36-64", color = "#2B818E", fontface = "bold", size = 3)+
annotate("text", x = 2015, y = 0.293, label = "65 o más", color = "#D1BDA2", fontface = "bold", size = 3)+

#Elimino la leyenda:
guides(color = FALSE)+

#Paleta de colores:
scale_color_got_d(option = "Daenerys")+

#Poniendo los cortes del eje x cada dos años
scale_x_continuous(breaks = seq(2008, 2016, by = 2))+
xlab("")+
ylab("")+
ggtitle("Desigualdad Generacional en España",
subtitle = "Coeficiente Gini por grupos de edad, 2008-2017")+
labs(caption="Ariane Aumaitre (@ariamsita) Datos: ECV (renta de hogares por unidades de consumo)")+
theme_minimal()+

#añado las características de mi tema:
tema_ari

editado.png

Animando el gráfico

Y por fin, ¿cómo convertimos esto en un gif? Partiendo del gráfico anterior, hay varias cosas a tener en cuenta:

  • La función transition_reveal() de gganimate hace que las líneas vayan apareciendo en función del argumento que les des. En el caso de los gráficos de líneas animados, este debe ser siempre el mismo que el eje x (en este caso, los años).
  • Vamos a sustituir las anotaciones en el gráfico por notas de texto que acompañen a las líneas. El primer paso para esto es crear un segmento que una las líneas con el final del gráfico: la línea con geom_segment(). Si vuestros datos están agrupados, como en este caso, debe especificarse dentro de aes() para que el resultado no de problemas. El segundo paso es, con geom_text(), añadir una anotación en el valor final. Como los datos que tenemos llegan hasta 2017, pongo el fin de ambos argumentos en 2017.5, para que las anotaciones queden fuera del ‘camino’ de las líneas, y expando el eje x hasta 2018.
  • El clip = ‘off’ en las coordenadas permite a ggplot escribir el texto de las anotaciones fuera del área del gráfico.
  • Para que los puntos del gráfico se queden en su sitio una vez que la animación pasa por allí, hay que especificar aes(group = seq_along(year)) dentro de geom_point()
  • Al generar un gif, los valores por defecto del tema que suelo usar se quedan pequeños, así que veréis que al final vuelvo a utilizar theme() para aumentar el tamaño del texto del gráfico.
  • Para generar el gif en sí, primero guardo el objeto del gráfico que he creado (g1), y después utilizo la función animate(). 
  • Si queréis que el gráfico pare tras haberse reproducido una vez, sólo tenéis que añadir renderer = gifski_renderer(loop = F) dentro de la función.

#Creando el objeto de ggplot

g1 = ecv_graf%>%
ggplot(aes(x = year, y = gini_c, color = agegroups))+
geom_line(size = 1)+
geom_point(aes(group = seq_along(year)), size = 2)+

#Los segmentos que van a unir nuestras líneas con las anotaciones:
geom_segment(aes(xend = 2017.5, yend = gini_c, group = agegroups),
linetype = 2, colour = 'grey') +

#Las anotaciones:
geom_text(aes(x = 2017.5, label = agegroups), hjust = 0)+
guides(color = FALSE)+
scale_color_got_d(option = "Daenerys")+
scale_x_continuous(breaks = seq(2008, 2018, by = 2),
limits = c(2008, 2018))+
xlab("")+
ylab("")+
ggtitle("Desigualdad Generacional en España",
subtitle = "Coeficiente Gini por grupos de edad, 2008-2017")+
labs(caption="Ariane Aumaitre (@ariamsita) Datos: ECV (renta de hogares por unidades de consumo)")+
theme_minimal()+
tema_ari+

#Agrandando el texto para adaptarlo al gif:

theme(plot.title = element_text(size = 15),
plot.subtitle = element_text(size = 12),
axis.text.x = element_text(size = 10),
plot.caption = element_text(size = 10, color = "grey40"))

#Animación:

transition_reveal(year)+
coord_cartesian(clip = 'off') +
enter_fade() +
exit_shrink()

#Animando el objeto de ggplot:

animate(g1)

ecv_animada

 

¡Y ya estaría! Si os habéis quedado con dudas o si os gustaría que compartiese algo específico estoy en Twitter o por aquí.

2 comentarios en “Gráficos animados con ggplot (y algunas cosas más)

    • Hola, Daniel. ¿Es posible que estés añadiendo ggsave() al final del código y por eso se genere tu problema? En principio el código de arriba no está hecho para guardar automáticamente, sino que tendrías que guardar el gif directamente en RStudio. Si sigues teniendo el problema puedes mandarme un mail y lo intentamos arreglar.

      Me gusta

Deja un comentario