##Clase 3: descubriendo patrones temporales y espaciales –> lubridate

library(tidyverse)
library(ggmap)
library(lubridate)
  1. Explorar funciones de lubridate

today() –> da la fecha en la que estamos now () –> da todos los datos de ahora –> formato posix: para almacenar hora y fecha juntos with_tz() –> para elegir otros husos horarios OlsonNames() –> para buscar otros husos wday() –> qué día de la semana fue tal fecha específica La respuesta es “2”. Sin embargo, esto no me da demasiada información, ya que no tengo porque saber que significa ese “2”. Para averiguarlo podemos pedirle a R que nos agregue una etiqueta con el nombre del día:

wday(“2024-01-01”, label = TRUE)

[1] Mon

Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat

Ahora si, parecería que “2” es el orden de los días y que significa Monday (inglés) o Lunes (español).

Por último, si queremos que los nombres de los días no estén abreviados y se muestren en Español, podemos agregar 2 parámetros:

abbr=FALSE para evitar abreviaturas.
locale=“es_ES.UTF-8” para pasar al idioma español y ajustar el encoding.

wday(“2024-01-01”, label=TRUE, abbr=FALSE, locale=“es_ES.UTF-8”)

month() –> en qué mes fue o será alguna fecha específica

También podemos hacer operaciones/cálculos con lubridate. Por ejemplo, podríamos preguntarnos qué fecha fue hace 10 días:

today()-10

[1] “2025-06-20”

O qué fecha será dentro de 75 días:

today()+75

[1] “2025-09-13”

Imaginen poder aplicar todas estas funciones sobre un dataset que contenga variables temporales. Esto nos permitiría realizar múltiples operaciones y transformaciones para analizar la evolución de los datos en el tiempo, detectar patrones, comparar períodos y generar insights valiosos a partir de la dimensión temporal.

  1. Levantar la base
cdmx_transito <- read.csv("data/hechos-transito-cdmx-2024.csv", stringsAsFactors = TRUE)
  1. Revisamos cantidad de filas y columnas
dim(cdmx_transito)
## [1] 30650     6
  1. Veamos qué información contiene
names(cdmx_transito)
## [1] "folio"        "fecha_evento" "hora_evento"  "tipo_evento"  "longitud"    
## [6] "latitud"

Las 6 columnas que tiene el dataset corresponden a número de folio, fecha y hora en la que ocurrió el evento, tipo de evento y ubicación exacta (longitud y latitud).

Como verán, ¡Tenemos algunas columnas con información geográfica (coordenadas) y otras con datos temporales (fecha y hora)! Y esto resulta más que suficiente para poder encontrar patrones en los datos.

  1. Exploremos más el contenido
summary(cdmx_transito)
##                 folio           fecha_evento    hora_evento   
##   C5/20240619/04624:    1   2024-04-19:  134   09:02  :   53  
##  C2C/20240102/00031:    1   2024-02-02:  118   08:54  :   49  
##  C2C/20240104/00056:    1   2024-02-03:  114   08:03  :   47  
##  C2C/20240104/00171:    1   2024-10-10:  114   09:10  :   45  
##  C2C/20240105/00209:    1   2024-02-10:  112   08:25  :   44  
##  C2C/20240108/00100:    1   2024-06-29:  111   08:57  :   43  
##  (Other)           :30644   (Other)   :29947   (Other):30369  
##             tipo_evento       longitud         latitud     
##  ATROPELLADO      : 4822   Min.   :-99.35   Min.   :19.10  
##  CAIDA DE CICLISTA:  761   1st Qu.:-99.17   1st Qu.:19.34  
##  CAIDA DE PASAJERO:  611   Median :-99.14   Median :19.40  
##  CHOQUE           :18109   Mean   :-99.14   Mean   :19.39  
##  DERRAPADO        : 5866   3rd Qu.:-99.10   3rd Qu.:19.44  
##  VOLCADURA        :  481   Max.   :-98.95   Max.   :19.58  
## 

Podemos ver que:

El día con mayor cantidad de registros del año 2024 fue el 19/04/2024, con un total de 134.

La hora en la que más delitos se registraron en el año fue a las 09:02, con un total de 53.

El tipo de evento más registrado durante el período analizado fue “CHOQUE”.

Comencemos a trabajar con los datos temporales y revisemos que formato tiene la variable “fecha_evento”.

  1. Revisamos la estructura del dato
str(cdmx_transito$fecha_evento)
##  Factor w/ 366 levels "2024-01-01","2024-01-02",..: 1 1 1 1 1 1 1 1 1 1 ...

La variable está en formato factor pero nosotros queremos que esté en date entonces será necesario primero verificar el modo en que está escrita y luego hacer un mutate() y agregarle la función de lubridate correspondiente

cdmx_transito <- cdmx_transito %>%
  mutate(fecha_evento=ymd(fecha_evento))

Y volvemos a corroborar la estructura del dataset

str(cdmx_transito$fecha_evento)
##  Date[1:30650], format: "2024-01-01" "2024-01-01" "2024-01-01" "2024-01-01" "2024-01-01" ...
  1. Comencemos agregando 2 nuevas columnas a nuestro dataset donde indiquemos el mes y el día de la semana en que ocurrió cada registro.
cdmx_transito <- cdmx_transito %>%
  mutate(mes=month(fecha_evento, label = TRUE, abbr=FALSE, locale="es_ES.UTF-8"),
         dia_semana=wday(fecha_evento, label=TRUE, abbr=FALSE, locale="es_ES.UTF-8"))
  1. Vemos un resumen estadístico con los nuevos datos
summary(cdmx_transito)
##                 folio        fecha_evento         hora_evento   
##   C5/20240619/04624:    1   Min.   :2024-01-01   09:02  :   53  
##  C2C/20240102/00031:    1   1st Qu.:2024-03-29   08:54  :   49  
##  C2C/20240104/00056:    1   Median :2024-06-27   08:03  :   47  
##  C2C/20240104/00171:    1   Mean   :2024-06-30   09:10  :   45  
##  C2C/20240105/00209:    1   3rd Qu.:2024-10-04   08:25  :   44  
##  C2C/20240108/00100:    1   Max.   :2024-12-31   08:57  :   43  
##  (Other)           :30644                        (Other):30369  
##             tipo_evento       longitud         latitud             mes       
##  ATROPELLADO      : 4822   Min.   :-99.35   Min.   :19.10   noviembre: 2703  
##  CAIDA DE CICLISTA:  761   1st Qu.:-99.17   1st Qu.:19.34   octubre  : 2652  
##  CAIDA DE PASAJERO:  611   Median :-99.14   Median :19.40   mayo     : 2648  
##  CHOQUE           :18109   Mean   :-99.14   Mean   :19.39   marzo    : 2632  
##  DERRAPADO        : 5866   3rd Qu.:-99.10   3rd Qu.:19.44   febrero  : 2631  
##  VOLCADURA        :  481   Max.   :-98.95   Max.   :19.58   junio    : 2586  
##                                                             (Other)  :14798  
##      dia_semana  
##  domingo  :4442  
##  lunes    :4034  
##  martes   :4289  
##  miércoles:4131  
##  jueves   :4453  
##  viernes  :4592  
##  sábado   :4709

Observamos que el mes con mayores ocurrencias es novimebre, con 2703, y el día de la semana el sábado con 4709. Veremos la evolución en un gráfico

ggplot() + 
    geom_bar(data= cdmx_transito, aes(x = mes))

  1. Vamos a ajustar el gráfico para poder ver por tipo de evento
a <- cdmx_transito %>%
  group_by(mes, tipo_evento) %>%
  summarise(cantidad=n())

Y ahora armamos el nuevo gráfico

ggplot() +
  geom_bar(data=cdmx_transito, aes(x = mes, fill = tipo_evento), position="dodge")+
  labs(title="Evolución mensual de hechos de tránsito",
       subtitle="2024, Ciudad de México",
       fill="Tipo",
       x="Mes",
       y="Cantidad")+
  theme_minimal()

En el gráfico se observa que las distintas categorías de hechos de tránsito no presentan sus picos ni sus mínimos en los mismos meses. Cada tipo de incidente muestra su propia estacionalidad. A continuación, se detallan los meses con la mayor cantidad de casos para cada tipo de evento.

cdmx_transito %>%
  group_by(tipo_evento, mes) %>%
  summarise(cantidad=n()) %>%
  filter(cantidad==max(cantidad)) %>%
  arrange((desc(cantidad)))
## # A tibble: 6 × 3
## # Groups:   tipo_evento [6]
##   tipo_evento       mes       cantidad
##   <fct>             <ord>        <int>
## 1 CHOQUE            noviembre     1600
## 2 DERRAPADO         diciembre      546
## 3 ATROPELLADO       febrero        430
## 4 CAIDA DE CICLISTA marzo           87
## 5 CAIDA DE PASAJERO noviembre       62
## 6 VOLCADURA         noviembre       52

Al observar los meses con mayor cantidad de hechos según el tipo de evento, se destacan los choques, con un pico en noviembre que supera los 1.600 casos. Ese mismo mes también concentra el mayor número de caídas de pasajero (62) y volcaduras (52), lo que sugiere una posible combinación de factores estacionales o contextuales que incrementan los siniestros. En cuanto a los atropellos, el valor más alto se da en febrero (430), mientras que las caídas de ciclistas alcanzan su máximo en marzo (87). Finalmente, los derrapes registran su mayor cantidad en diciembre (546).

Mejoremos el gráfico

ggplot() +
  geom_bar(data = cdmx_transito, aes(x = mes, fill = str_to_title(tipo_evento)), position = "dodge") +
  labs(title = "Evolución mensual de hechos de tránsito",
       subtitle = "2024, Ciudad de México",
       fill = "Tipo",
       x = "Mes",
       y = "Cantidad") +
  scale_fill_manual(values = c("#f94144", "#f8961e", "#f9c74f", "#43aa8b", "#577590", "#277da1")) +
  theme_minimal(base_family = "Tahoma") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

  1. A continuación, analicemos los datos a nivel diario (en lugar de mensual) para explorar posibles patrones adicionales. Como primer paso, realizamos un conteo de hechos registrados por cada día.
cdmx_transito_dia <- cdmx_transito %>%
  group_by(fecha_evento) %>%
  summarise(cantidad=n())

Revisamos los datos

head(cdmx_transito_dia)
## # A tibble: 6 × 2
##   fecha_evento cantidad
##   <date>          <int>
## 1 2024-01-01         43
## 2 2024-01-02         64
## 3 2024-01-03         71
## 4 2024-01-04         80
## 5 2024-01-05         88
## 6 2024-01-06         88
summary(cdmx_transito_dia)
##   fecha_evento           cantidad     
##  Min.   :2024-01-01   Min.   : 43.00  
##  1st Qu.:2024-04-01   1st Qu.: 77.00  
##  Median :2024-07-01   Median : 83.00  
##  Mean   :2024-07-01   Mean   : 83.74  
##  3rd Qu.:2024-09-30   3rd Qu.: 91.00  
##  Max.   :2024-12-31   Max.   :134.00

En promedio, durante el período analizado se registraron 83 hechos de tránsito por día. Para visualizar cómo evolucionó esta cifra a lo largo del tiempo y detectar posibles picos o caídas, a continuación presentamos un gráfico de líneas con la cantidad diaria de incidentes y el promedio calculado.

ggplot() + 
  geom_line(data=cdmx_transito_dia, aes(x = fecha_evento, y = cantidad))+
  geom_hline(yintercept = 83.74, color = "red")+
  labs(title = "Evolución diaria de hechos de tránsito",
       subtitle = "2024, Ciudad de México",
       x = "Día",
       y = "Cantidad") +
  theme_minimal(base_family = "Tahoma")

Datos filtrados al mes de diciembre para mejor análisis

ggplot() + 
    geom_line(data = cdmx_transito_dia %>%
                filter(month(fecha_evento)==12), aes(x = fecha_evento, y = cantidad)) +
  labs(title = "Evolución diaria de hechos de tránsito",
       subtitle = "Diciembre 2024, Ciudad de México",
       x = "Día",
       y = "Cantidad") +
  scale_x_date(date_breaks = "1 day", date_labels = "%d-%m") +
  theme_minimal(base_family = "Tahoma") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

Ahora vamos con enero

ggplot() + 
    geom_line(data = cdmx_transito_dia %>%
                filter(month(fecha_evento)==01), aes(x = fecha_evento, y = cantidad)) +
  labs(title = "Evolución diaria de hechos de tránsito",
       subtitle = "Enero 2024, Ciudad de México",
       x = "Día",
       y = "Cantidad") +
  scale_x_date(date_breaks = "1 day", date_labels = "%d-%m") +
  theme_minimal(base_family = "Tahoma") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

11) Aprovechemos que contamos con la variable categórica “tipo_evento” para agregar color al gráfico anterior y así visualizar cómo varía cada tipo de hecho a lo largo del tiempo. Esto puede ayudarnos a identificar patrones específicos según el tipo de incidente.

Para hacerlo, necesitamos agrupar los datos no solo por día (“fecha_evento”), sino también por “tipo_evento”. En lugar de generar un nuevo objeto intermedio, realizaremos estas operaciones directamente dentro del geom_line() utilizando group_by() y summarise().

ggplot() + 
    geom_line(data = cdmx_transito %>%
         group_by(fecha_evento, tipo_evento) %>%
         summarise(cantidad=n()),
         aes(x = fecha_evento, y = cantidad, color = str_to_title(tipo_evento)))+
  labs(title = "Evolución diaria de hechos de tránsito por tipología",
       subtitle = "2024, Ciudad de México",
       x = "Día",
       y = "Cantidad",
       color = "Tipo") +
  scale_color_manual(values = c("#f94144", "#f8961e", "#f9c74f", "#43aa8b", "#577590", "#277da1")) +
  theme_minimal(base_family = "Tahoma")

Ajustes estéticos

ggplot() + 
    geom_line(data = cdmx_transito %>%
         group_by(fecha_evento, tipo_evento) %>%
         summarise(cantidad=n()),
         aes(x = fecha_evento, y = cantidad, color = str_to_title(tipo_evento)))+
  labs(title = "Evolución diaria de hechos de tránsito por tipología",
       subtitle = "2024, Ciudad de México",
       x = "Día",
       y = "Cantidad",
       color = "Tipo") +
  scale_color_manual(values = c("#f94144", "#f8961e", "#f9c74f", "#43aa8b", "#577590", "#277da1")) +
  scale_x_date(date_breaks = "1 month", date_labels = "%d-%m")+
  theme_minimal(base_family = "Tahoma")+
  theme(legend.position="bottom",
        legend.justification = "center",
        title=element_text(size=10, face = "bold"),
        legend.text=element_text(size=7),
        axis.title.x = element_text(size = 8),
        axis.title.y = element_text(size = 8),
        axis.text.y = element_text(size = 7),
        axis.text.x = element_text(size = 7, angle = 90),
        plot.caption=element_text(face = "italic", colour = "gray35",size=7))

Ahora aprovechemos que ya agregamos el día de la semana (dia_semana) en nuestro dataset original y trabajemos con esta información.

ggplot()+
  geom_bar(data = cdmx_transito, aes(x = dia_semana), fill="#778da9")+
  theme_minimal()

Para profundizar este análisis, vamos a aprovechar la variable “mes” y generar un gráfico de barras facetado, que nos permita ver con mayor detalle cómo se distribuyen los hechos de tránsito según el mes y día de la semana.

ggplot() + 
    geom_bar(data = cdmx_transito, aes(x = dia_semana), fill="#778da9")+
  labs(title="Cantidad de hechos de tránsito por día de la semana",
       subtitle="Ciudad de México, 2024",
       fill="Tipología",
       x="Día de la semana",
       y="Cantidad") +
  facet_wrap(~mes, ncol= 4)+
  theme_minimal()+
  theme(axis.text.x = element_text(size = 7, angle = 90))

Por último, vamos a incorporar la variable “tipo_evento” y colorear las barras del gráfico para visualizar con mayor nivel de detalle cómo se distribuyen los distintos tipos de hechos de tránsito según el mes y el día de la semana. Esta visualización nos permitirá identificar si ciertos eventos, como atropellos o volcaduras, tienden a concentrarse en días o meses específicos, y si siguen o no el patrón general observado.

ggplot(cdmx_transito) + 
    geom_bar(aes(x = dia_semana, fill=str_to_title(tipo_evento)))+
  labs(title="Cantidad de hechos de tránsito por día y tipo",
       subtitle="Ciudad de México, 2019-2020",
       fill="Tipología",
       x="Día de la semana",
       y="Cantidad") +
  scale_fill_manual(values = c("#f94144", "#f8961e", "#f9c74f", "#43aa8b", "#577590", "#277da1")) +
  facet_wrap(~mes, ncol= 4) +
  theme_minimal() +
  theme(axis.text.x = element_text(size = 7, angle = 90))

#Análisis espacial

Hasta acá, detectamos varios patrones temporales muy interesantes en nuestros datos, pero todavía nos queda ver una “dimensión” muy relevante a la hora de analizar este tipo de información: la ubicación en el espacio.

Comencemos viendo como se ubican todos los datos en el territorio.

ggplot()+
  geom_point(data = cdmx_transito, aes(x= longitud, y= latitud))

Como vimos la clase pasada, alguien ya se cruzó con esta pregunta y diseñó una librería que nos soluciona el problema y se llama ggmap. Ya la hemos activado al inicio de la clase, así que el siguiente paso, al igual que en la clase anterior, es determinar cuál es la “bounding box” o caja delimitadora de coordenadas de mi dataset. Pero nótese que esta vez no tengo un dato geoespacial para utlizar st_bbox(), y por lo tanto aplicaremos la función make_bbox() sobre las coordenadas de las columnas “longitud” y “latitud” del dataset original:

cdmx_bbox <- make_bbox(cdmx_transito$longitud, cdmx_transito$latitud)
cdmx_bbox
##      left    bottom     right       top 
## -99.36838  19.07799 -98.92832  19.60033

Bien, ya tengo los 4 valores que delimitan nuestra bounding box, ahora vamos a usar get_stadiamap() para descargar de internet el “mapa base”. En este caso utilizaremos un mapa de tipo “alidade_smooth”.

register_stadiamaps("96e8da08-2cda-466f-beeb-f3517aa6c989", write = TRUE)
## ℹ Replacing old key (96e8da08) with new key in /home/tormenta/.Renviron
mapa_base <- get_stadiamap(bbox = cdmx_bbox,
                           maptype = "alidade_smooth",
                           zoom = 11)
ggmap(mapa_base)

Ahora vamos a ver nuestros datos en este mapa base

ggmap(mapa_base)+
  geom_point(data=cdmx_transito, aes(x=longitud, y=latitud, color=tipo_evento))

Vamos a hacer un facetado para que se vea mejor la distribución

ggmap(mapa_base)+
  geom_point(data=cdmx_transito, aes(x=longitud, y=latitud, color=tipo_evento))+
  facet_wrap(~tipo_evento)

Por suerte tenemos una solución dentro del mismísimo ggplot() que es lo que llamamos Mapas de Densidad y podemos realizarlos a partir de geom_bin2d(). Veamos de que se trata.

ggmap(mapa_base) +
    geom_bin2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud))

Vamos a mejorarlo agregando más binds y otra escala de color

ggmap(mapa_base) +
    geom_bin2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud), bins=50)+
  scale_fill_viridis_c(direction=-1)

Ahora lo mismo pero facetado por tipo de evento

ggmap(mapa_base) +
    geom_bin2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud), bins=50)+
  scale_fill_viridis_c(direction=-1)+
  facet_wrap(~tipo_evento)

#Análisis temporal y espacial

Hasta acá vimos por un lado el análisis temporal y por el otro, el análisis espacial. Ahora veamos ambos análisis juntos y busquemos por ejemplo, un patrón espacial según el día de la semana.

ggmap(mapa_base) +
    geom_bin2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud), bins=50, show.legend = FALSE)+
  labs(title="Densidad de hechos de tránsito en 2024",
       subtitle="Ciudad de México")+
  scale_fill_viridis_c(direction=-1)+
  facet_wrap(~dia_semana, ncol=4)+
  theme_void()

Según el mes

ggmap(mapa_base) +
    geom_bin2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud), bins=50, show.legend=FALSE)+
  labs(title="Densidad de hechos de tránsito en 2020",
       subtitle="Ciudad de México")+
  scale_fill_viridis_c(direction=-1)+
  facet_wrap(~mes, ncol=6)+
  theme_void()

Otra función muy útil para este tipo de visualizaciones espaciales es stat_density_2d(), que genera curvas de densidad (contornos) a partir de un conjunto de puntos georreferenciados, utilizando un proceso llamado estimación de densidad por núcleo (Kernel Density Estimation, KDE).

Lo que hace, en términos simples, es estimar cuántos puntos hay en cada zona del espacio, no solo contando puntos exactos, sino suavizando esa información en el entorno de cada uno. Imaginemos que cada punto “irradiara” influencia alrededor suyo, y que esas influencias se sumaran en una grilla invisible que cubre todo el mapa. Donde más puntos hay cercanos entre sí, mayor es la densidad estimada.

El resultado son curvas similares a las de un mapa topográfico, pero en este caso representan concentración de eventos, no altura. Las zonas con mayor densidad aparecen más intensas visualmente (o con colores más cálidos, si usás un mapa de calor), y permiten detectar puntos críticos o áreas de riesgo sin necesidad de agrupar manualmente.

ggmap(mapa_base) +
    stat_density2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud, fill = after_stat(level)), geom = "polygon", alpha=0.75)+
  labs(title="Densidad de hechos de tránsito",
       subtitle="Ciudad de México")+
  scale_fill_distiller(palette = "Spectral")+
  theme_void()

Ahora desagregada en día y mes

ggmap(mapa_base) +
    stat_density2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud, fill = after_stat(level)), geom = "polygon", alpha=0.75)+
  labs(title="Densidad de hechos de tránsito en 2020",
       subtitle="Ciudad de México")+
  scale_fill_distiller(palette = "Spectral")+
  facet_wrap(~dia_semana, ncol=4)+
  theme_void()

ggmap(mapa_base) +
    stat_density2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud, fill = after_stat(level)), geom = "polygon", alpha=0.75)+
  labs(title="Densidad de hechos de tránsito en 2020",
       subtitle="Ciudad de México")+
  scale_fill_distiller(palette = "Spectral")+
  facet_wrap(~mes, ncol=6)+
  theme_void()

Como habrán notado, la información es la misma que la de geom_bin2d() pero visualizada de otra forma.

#Mapas animados

Hasta acá hemos visto una serie de gráficos y mapas donde detectamos algunos patrones temporales a partir de la visualización de variables de tiempo (mes, día de la semana, etc.) con la función facet_wrap().

Sin embargo, esta no es la única forma de incluir variables temporales a nuestros gráficos ya que, por ejemplo cuando las variables tienen muchas opciones posibles, la lectura del gráfico se hace cada vez más compleja.

Para esto sirven las visualizaciones animadas o “GIF” que podemos realizar a partir de 2 librerías llamadas gganimate y gifski.

install.packages("gganimate")
install.packages("gifski")
library(gifski)
library(gganimate)
mapa_animado_2024 <-ggmap(mapa_base) +
    stat_density2d(data = cdmx_transito, 
               aes(x = longitud, y = latitud, fill = after_stat(level)), geom = "polygon", alpha=0.5)+
  scale_fill_distiller(palette = "Spectral")+
  labs(title="Densidad de hechos de tránsito en 2024",
       subtitle = "CDMX | Mes: {closest_state}")+
  transition_states(mes)
animate(mapa_animado_2024, renderer = gifski_renderer())

mapa_animado_diciembre <- ggmap(mapa_base) +
  stat_density2d(data = cdmx_transito %>% filter(mes=="diciembre"), 
               aes(x = longitud, y = latitud, fill = after_stat(level)), geom = "polygon", alpha=0.5)+
  scale_fill_distiller(palette = "Spectral")+
  labs(title="Densidad de hechos de tránsito en diciembre 2024",
       subtitle = "CDMX | Dia: {frame_time}")+
  transition_time(fecha_evento)
animate(mapa_animado_diciembre, renderer = gifski_renderer())

Por último, ára descargar los gif vamos a usar la función anim_save()

anim_save("mapa_animado_2024.gif", mapa_animado_2024)