Círculos climáticos

El clima de un lugar se suele presentar a través de climogramas que combinan la precipitación y temperatura mensual en un único gráfico. No obstante, también es interesante visualizar el clima a nivel diario mostrando la amplitud térmica y la temperatura media diaria. Para ello, se calculan las medias de cada día del año de las mínimas, máximas y medias diarias.

El ciclo anual del clima presenta una buena oportunidad para usar un gráfico radial, polar o circular lo que nos permite visualizar de forma clara los patrones estacionales.

Paquetes

Usaremos los siguientes paquetes:

Paquete Descripción
tidyverse Conjunto de paquetes (visualización y manipulación de datos): ggplot2, dplyr, purrr,etc.
fs Proporciona una interfaz uniforme y multiplataforma para las operaciones del sistema de archivos
lubridate Fácil manipulación de fechas y tiempos
janitor Funciones sencillas para examinar y limpiar datos
# instalamos los paquetes si hace falta

if(!require("tidyverse")) install.packages("tidyverse")
if(!require("fs")) install.packages("fs")
if(!require("lubridate")) install.packages("lubridate")

# paquetes

library(tidyverse)
library(lubridate)
library(fs)
library(janitor)

Preparación

Datos

Descargamos los datos de temperatura de una selección de ciudades estadounidenses descarga. Podéis descargar otras ciudades del mundo a través de los datasets WMO o GHCN en NCDC/NOAA.

Importar

Para importar las series temporales de temperatura de cada ciudad, que encontramos en varios archivos, aplicamos la función read_csv() usando map_df(). La función dir_ls() del paquete fs nos devuelve el listado de archivos con la extensión csv. El suffijo de map() indica que queremos unir todas las tablas importadas en una única. Para aquellos con menos experiencia con tidyverse, recomiendo una breve introducción en este blog post.

Después obtenemos los nombres de las estaciones meteorologicas y definimos un nuevo vector con los nuevos nombres.

# importamos los datos
meteo <- dir_ls(regexp = ".csv$") %>% 
          map_df(read_csv)

# nombres de las estaciones
stats_names <- unique(meteo$NAME)
stats_names
## [1] "CHICAGO OHARE INTERNATIONAL AIRPORT, IL US"             
## [2] "LAGUARDIA AIRPORT, NY US"                               
## [3] "MIAMI INTERNATIONAL AIRPORT, FL US"                     
## [4] "HOUSTON INTERCONTINENTAL AIRPORT, TX US"                
## [5] "ATLANTA HARTSFIELD JACKSON INTERNATIONAL AIRPORT, GA US"
## [6] "SAN FRANCISCO INTERNATIONAL AIRPORT, CA US"             
## [7] "SEATTLE TACOMA AIRPORT, WA US"                          
## [8] "DENVER INTERNATIONAL AIRPORT, CO US"                    
## [9] "MCCARRAN INTERNATIONAL AIRPORT, NV US"
# nuevos nombres de las ciudades
cities <- c("CHICAGO", "NEW YORK", "MIAMI", 
            "HOUSTON", "ATLANTA", "SAN FRANCISCO", 
            "SEATTLE", "DENVER", "LAS VEGAS")

Modificar

En el primer paso modificaremos los datos originales, 1) seleccionando únicamente las columnas de interés, 2) filtrando al período 1991-2020, 3) definiendo los nuevos nombres de las estaciones, 4) calculando la temperatura media allí donde esté ausente, 5) limpiando los nombres de las columnas, y 6) creando una nueva variable con los días del año. La función clean_names() de janitor es muy útil para obtener nombres de columnas limpios.

meteo <- select(meteo, NAME, DATE, TAVG:TMIN) %>%  
           filter(DATE >= "1991-01-01", DATE <= "2020-12-31") %>% 
            mutate(NAME = factor(NAME, stats_names, cities),
                   TAVG = ifelse(is.na(TAVG), (TMAX+TMIN)/2, TAVG),
                   yd = yday(DATE)) %>% 
            clean_names()

En el siguiente paso calculamos el promedio de las máximas, mínimas y media diarias para cada día del año. Después únicamente falta por convertir los días del año en una fecha dummy. Aquí usamos el año 2000 dado que es bisiesto y tenemos en total 366 días.

# estimamos los promedios diarios
meteo_yday <- group_by(meteo, name, yd) %>% 
                  summarise(ta = mean(tavg, na.rm = TRUE),
                            tmx = mean(tmax, na.rm = TRUE),
                            tmin = mean(tmin, na.rm = TRUE))
## `summarise()` has grouped output by 'name'. You can override using the
## `.groups` argument.
meteo_yday
## # A tibble: 3,294 x 5
## # Groups:   name [9]
##    name       yd    ta    tmx  tmin
##    <fct>   <dbl> <dbl>  <dbl> <dbl>
##  1 CHICAGO     1 -3.77  0.537 -7.86
##  2 CHICAGO     2 -2.64  1.03  -6.68
##  3 CHICAGO     3 -2.88  0.78  -6.93
##  4 CHICAGO     4 -2.86  0.753 -7.10
##  5 CHICAGO     5 -4.13 -0.137 -8.33
##  6 CHICAGO     6 -4.50 -1.15  -8.05
##  7 CHICAGO     7 -4.70 -0.493 -8.57
##  8 CHICAGO     8 -3.97  0.147 -8.02
##  9 CHICAGO     9 -3.47  0.547 -7.49
## 10 CHICAGO    10 -3.41  1.09  -7.64
## # ... with 3,284 more rows
# convertimos los días del año en una fecha dummy
meteo_yday <- mutate(meteo_yday, yd = as_date(yd, origin = "1999-12-31"))

Cear los círculos climáticos

Predefiniciones

Definimos un vector divergente de varios colores.

col_temp <- c("#cbebf6","#a7bfd9","#8c99bc","#974ea8","#830f74",
              "#0b144f","#0e2680","#223b97","#1c499a","#2859a5",
              "#1b6aa3","#1d9bc4","#1ca4bc","#64c6c7","#86cabb",
              "#91e0a7","#c7eebf","#ebf8da","#f6fdd1","#fdeca7",
              "#f8da77","#fcb34d","#fc8c44","#f85127","#f52f26",
              "#d10b26","#9c042a","#760324","#18000c")

Creamos una tabla con las líneas de la rejilla en sentido eje x.

grid_x <- tibble(x = seq(ymd("2000-01-01"), ymd("2000-12-31"), "month"), 
                 y = rep(-10, 12), 
                 xend = seq(ymd("2000-01-01"), ymd("2000-12-31"), "month"), 
                 yend = rep(41, 12))

Definimos todos los elementos de estilo del gráfico en nuestro propio tema theme_cc().

theme_cc <- function(){ 
  
 theme_minimal(base_family = "Montserrat") %+replace%
  theme(plot.title = element_text(hjust = 0.5, colour = "white", size = 30, margin = margin(b = 20)),
        plot.caption = element_text(colour = "white", size = 9, hjust = .5, vjust = -30),
        plot.background = element_rect(fill = "black"),
        plot.margin = margin(1, 1, 2, 1, unit = "cm"),
  
        axis.text.x = element_text(face = "italic", colour = "white"),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        
        legend.title = element_text(colour = "white"),
        legend.position = "bottom",
        legend.justification = 0.5,
        legend.text = element_text(colour = "white"),
       
        
        strip.text = element_text(colour = "white", face = "bold", size = 14),
        
        panel.spacing.y = unit(1, "lines"),
        panel.background = element_rect(fill = "black"),
        panel.grid = element_blank()
      ) 
}

Gráfico

Empezamos por crear un gráfico únicamente para la ciudad de Nueva York. Usaremos geom_linerange() definiendo el rango con las máximas y mínimas. Además, dibujaremos las líneas de rango en función de la temperatura media. Podemos ajustar alpha y size para obtener un aspecto más bonito.

# filtramos Nueva York
ny_city <- filter(meteo_yday, name == "NEW YORK") 

# gráfico
ggplot(ny_city) + 
  geom_linerange(aes(yd, 
                     ymax = tmx, 
                     ymin = tmin, 
                     colour = ta),
                 size=0.5, 
                 alpha = .7) + 
  scale_y_continuous(breaks = seq(-30, 50, 10), 
                     limits = c(-11, 42), 
                     expand = expansion()) +
  scale_colour_gradientn(colours = col_temp, 
                         limits = c(-12, 35), 
                         breaks = seq(-12, 34, 5)) + 
  scale_x_date(date_breaks = "month",
               date_labels = "%b") +
  labs(title = "CLIMATE CIRCLES", 
       colour = "Daily average temperature") 

Para conseguir el gráfico polar únicamente haría falta añadir la función coord_polar().

# gráfico polar
ggplot(ny_city) + 
  geom_linerange(aes(yd, 
                     ymax = tmx, 
                     ymin = tmin, 
                     colour = ta),
                 size=0.5, 
                 alpha = .7) + 
  scale_y_continuous(breaks = seq(-30, 50, 10), 
                     limits = c(-11, 42), 
                     expand = expansion()) +
  scale_colour_gradientn(colours = col_temp, 
                         limits = c(-12, 35), 
                         breaks = seq(-12, 34, 5)) + 
  scale_x_date(date_breaks = "month",
               date_labels = "%b") +
  coord_polar() +
  labs(title = "CLIMATE CIRCLES", 
       colour = "Daily average temperature") 

Cambiamos la lengua del sistema operativo para obtener los nombres de meses en inglés. Para volver a la lengua de origen podemos usar simplemente la función Sys.setlocale("LC_TIME", old_lc).

old_lc <- Sys.getlocale("LC_TIME")

Sys.setlocale("LC_TIME", "English")
## [1] "English_United States.1252"

En el gráfico final añadimos la rejilla definiendo las líneas en el eje y con geom_hline(), y aquellas del eje x con geom_segement(). Lo más importante aquí es la función facet_wrap(), la que permite la creación de múltiples facetas de gráficos. Se usa el formato de fórmula para especificar de que forma se crean las facetas: fila ~ columna. En caso de que no dispongamos de una segunda variable, se indica en la fórmula un punto .. Además, hacemos cambios de aspecto en la barra de color con guides() y guide_colourbar(), e incluimos los estilos theme_cc().

ggplot(meteo_yday) + 
  geom_hline(yintercept = c(-10, 0, 10, 20, 30, 40), 
             colour = "white", 
             size = .4) +
  geom_segment(data = grid_x , 
               aes(x = x, 
                   y = y, 
                   xend = xend, 
                   yend = yend), 
               linetype = "dashed", 
               colour = "white", 
               size = .2) +
  geom_linerange(aes(yd, 
                     ymax = tmx, 
                     ymin = tmin, 
                     colour = ta),
                 size=0.5, 
                 alpha = .7) + 
  scale_y_continuous(breaks = seq(-30, 50, 10), 
                     limits = c(-11, 42), 
                     expand = expansion())+
  scale_colour_gradientn(colours = col_temp, 
                         limits = c(-12, 35), 
                         breaks = seq(-12, 34, 5)) + 
  scale_x_date(date_breaks = "month", 
               date_labels = "%b") +
  guides(colour = guide_colourbar(barwidth = 15,
                                  barheight = 0.5, 
                                  title.position = "top")
         ) +
  facet_wrap(~name, nrow = 3) +
  coord_polar() + 
  labs(title = "CLIMATE CIRCLES", 
       colour = "Daily average temperature") +
  theme_cc()

Buy Me A Coffee

Dr. Dominic Royé
Dr. Dominic Royé
Investigador y responsable de ciencia de datos

Relacionado