Gráfico barras animado: Primer intento

Objetivo

Se ha viralizado los gráfico de barras horizontales que van mostrando un ranking (sea de ventas, valor de acciones, goles, etc.), y se muestra una animación de cómo cambia ese ranking por año o mes.

Preliminares

Datos

Vamos a crear una estructura básica en empresas comerciales:
ALMACEN | PRODUCTO | PERIODO | VENTA.

library(tidyverse)
library(lubridate)
library(ggplot2)
library(gganimate)

set.seed(123)
df_1 <- tbl_df( data.frame(
  ALMACEN= rep(c("Mall del Sol", "Riocentro"), each= 15),
  PRODUCTO= paste("Prod", LETTERS[1:15], sep="_"),
  PERIODO= rep(seq.Date(from=as.Date("2015-01-01"), to=as.Date("2017-06-01"), by="month"), each=30),
  VTA= round(runif(n = 900, min = 1000, max= 7000),0),
  stringsAsFactors = FALSE
) )

glimpse(df_1)
## Observations: 900
## Variables: 4
## $ ALMACEN  <chr> "Mall del Sol", "Mall del Sol", "Mall del Sol", "Mall...
## $ PRODUCTO <chr> "Prod_A", "Prod_B", "Prod_C", "Prod_D", "Prod_E", "Pr...
## $ PERIODO  <date> 2015-01-01, 2015-01-01, 2015-01-01, 2015-01-01, 2015...
## $ VTA      <dbl> 2725, 5730, 3454, 6298, 6643, 1273, 4169, 6355, 4309,...

Agrupamiento

Se va a realizar un ranking de los productos por mes, eso implica que necesitamos

  1. Calcular el total de venta mensual de cada producto (lo que implica hacer un arupamiento por Producto, periodo)
  2. Obtener el ranking de los productos por mes (para ello debemos hacer un agrupamiento por periodo)

Usando el tidyverse sería:

df_resumen <- df_1 %>%
  filter(year(PERIODO)== 2015) %>% 
  group_by( PRODUCTO, PERIODO) %>%  ## Agrupar por Producto, Periodo
  summarise(VENTA= sum(VTA)) %>%    ## Sumar la venta por Producto, Periodo
  group_by( PERIODO) %>%            ## Agrupar por  Periodo
  mutate( RANKING= min_rank(-VENTA)) ## Obtener el ranking de prod por Periodo
glimpse(df_resumen)
## Observations: 180
## Variables: 4
## $ PRODUCTO <chr> "Prod_A", "Prod_A", "Prod_A", "Prod_A", "Prod_A", "Pr...
## $ PERIODO  <date> 2015-01-01, 2015-02-01, 2015-03-01, 2015-04-01, 2015...
## $ VENTA    <dbl> 9124, 8611, 7312, 8126, 9846, 10287, 9838, 7263, 9993...
## $ RANKING  <int> 8, 6, 10, 9, 2, 1, 3, 9, 4, 4, 1, 9, 10, 5, 15, 1, 6,...

Animación

Un primer gráfico

Vamos a escoger un mes en específico y armar un gráfico que será el que animaremos, entendiendo la lógica de ggplot2, requerimos:
1. En un eje el ranking (pero como el uno debe estar arriba, entonces lo ponemos en negativo), 2. En el otro eje la venta 3. Con esto se hace un gráfico de barras 4. Los labels se los agrega con geom_text 5. El gráfico de barras por default es vertical, pero lo queremos horizontal por lo que se hace un flip.

ggplot(df_resumen %>% filter(PERIODO==ymd("2015-01-01")), aes(x = -RANKING, y = VENTA, fill = PRODUCTO)) +
  geom_bar(stat = "identity") +
  labs(title = "Ranking de Productos", subtitle = "Mes: 2015-01-01") +
  geom_text(aes(label = PRODUCTO, y = VENTA + 750 ),
            position =  position_dodge(0.9), vjust = 0.35) +
  coord_flip()

Primer gráfico

Lo pulimos un poco más y con esto tenemos nuestra base para la animación

ggplot(df_resumen %>% filter(PERIODO==ymd("2015-01-01")), aes(x = -RANKING, y = VENTA, fill = PRODUCTO)) +
  geom_bar(stat = "identity") +
  labs(title = "Ranking de Productos", subtitle = "Mes: 2015-01-01") +
  geom_text(aes(label = PRODUCTO, y = VENTA + 750 ),
            position =  position_stack(vjust = 1.01)) +
  coord_flip() +
  theme(axis.ticks.y=element_blank(), 
        axis.text.y=element_blank()) 

Gráfico base para animación

Animación

La idea es generar un gráfico por periodo, por lo que se define que los estados de la transición sea Periodo, nótese la animación en el subtitulo.

gbar <- ggplot(df_resumen, aes(x = -RANKING, y = VENTA, fill = PRODUCTO)) +
  geom_bar(stat = "identity") +
  labs(title = "Ranking de Productos", subtitle = "Mes: {closest_state}") +
  geom_text(aes(label = PRODUCTO, y = VENTA + 750 ),
            position =  position_stack(vjust = 1.01)) +
  coord_flip() +
  theme(axis.ticks.y=element_blank(), 
        axis.text.y=element_blank()) +
  transition_states(states = PERIODO, transition_length = 2, state_length = 1) + 
  enter_fade() + 
  exit_shrink() +
  ease_aes('sine-in-out')

gbar_gif <- animate(gbar, width = 940, height = 480)

gbar_gif

El resultado es:

Animación final

En esta entrada se ha usado geom_bar() para la animación, pero podemos utilizar otra geometría, eso se revisará en nuestra segunda aproximación.

Deja un comentario

Tu email nunca se publicará.


Ir a la barra de herramientas