Skip to contents

Introducción

Las olas de calor están entre los eventos climáticos extremos de mayor relevancia para la salud pública, especialmente en un contexto de calentamiento global, urbanización acelerada y aumento de la vulnerabilidad socioambiental. Estos eventos se caracterizan por periodos persistentes de temperaturas anormalmente elevadas en relación con el patrón climatológico de una localidad determinada, y pueden afectar directamente el confort térmico, la demanda de servicios de salud, la mortalidad y la morbilidad por causas sensibles al calor.

En Brasil, episodios recientes de calor extremo han evidenciado la necesidad de herramientas capaces de identificar, cuantificar y visualizar olas de calor de forma estandarizada y reproducible. Esta necesidad es aún más importante en estudios aplicados al Sistema Único de Salud (SUS), en los cuales la integración entre datos meteorológicos, indicadores ambientales y desenlaces en salud permite investigar patrones de riesgo, respaldar sistemas de alerta y apoyar estrategias de vigilancia en salud ambiental.

El paquete climasus4r ofrece un pipeline integrado que va desde la descarga de datos meteorológicos horarios del INMET hasta el relleno de lagunas, el cálculo de indicadores climáticos, la detección de olas de calor y la visualización de los eventos. En este tutorial presentamos cada etapa de este proceso con ejemplos prácticos, destacando no solo la ejecución de las funciones, sino también la interpretación climatológica, epidemiológica y operacional de los resultados.

Nota sobre reproducibilidad: Todo el pipeline es determinístico — dado el mismo periodo de datos INMET y los mismos parámetros, los resultados son idénticos entre ejecuciones. Los bloques de código marcados con eval = FALSE requieren conexión a internet para la etapa de descarga (INMET) y pueden tardar algunos minutos según el periodo solicitado.

¿Qué es una ola de calor?

No existe una definición única y universalmente aceptada de ola de calor. En general, una ola de calor puede entenderse como un periodo de calor anormal, intenso y persistente, en el que la temperatura observada supera un determinado umbral de referencia durante varios días consecutivos. Este umbral puede definirse de forma absoluta, como una temperatura fija, o de forma relativa, como un percentil elevado de la distribución histórica de temperatura de una región determinada.

Esta distinción es importante porque el impacto del calor depende del contexto climático local. Una temperatura considerada extrema en una ciudad de clima más templado puede ser relativamente común en regiones tropicales o semiáridas. Por ese motivo, muchos estudios utilizan umbrales basados en percentiles, como el percentil 90 o 95, permitiendo que la definición de calor extremo se adapte a la climatología de cada localidad.

De modo general, la mayoría de las definiciones de ola de calor combinan dos componentes principales:

  1. Umbral de temperatura — la temperatura (o índice de confort térmico) debe superar determinado valor crítico, típicamente definido como un percentil alto de la distribución histórica (P90, P95) o como una desviación fija respecto a la media climatológica.
  2. Duración mínima — la condición extrema debe persistir durante al menos N días consecutivos (comúnmente 3 o 5 días), distinguiendo eventos sostenidos de picos aislados.

La ausencia de consenso no es una limitación operativa: climasus4r implementa las siete definiciones más utilizadas en la literatura (Tabla 1), permitiendo análisis de sensibilidad y comparaciones intermetodológicas.

¿Por qué comparar métodos? En regiones tropicales y subtropicales como Brasil, el método INMET —calibrado para la realidad climática nacional— tiende a detectar eventos que los métodos percentílicos genéricos pueden subestimar. Por otro lado, índices de confort térmico como UTCI y WBGT capturan la percepción fisiológica del calor de forma más completa que la temperatura del aire de forma aislada. Comparar resultados entre métodos es una buena práctica de análisis de sensibilidad.

Visión general del pipeline

1. sus_climate_inmet() → 2. sus_climate_fill_inmet() → 3. sus_climate_compute_indicators() → 4. sus_climate_compute_heatwaves() → 5. sus_climate_plot_heatwaves()

Cada etapa recibe el producto de la anterior y añade información. La función sus_climate_compute_heatwaves() espera datos horarios con columnas estandarizadas de temperatura e índices de confort térmico — exactamente lo que produce sus_climate_compute_indicators().


Configuración del entorno

# Instalar climasus4r (GitHub) se necessário
# install.packages("remotes")
# remotes::install_github("MaxAnjos/climasus4r")

library(climasus4r)
library(dplyr)

Dependencias opcionales: Las funciones de visualización requieren ggplot2, ggsci y plotly. Para gráficos interactivos, instale también htmlwidgets. La etapa de indicadores climáticos requiere slider (ventanas deslizantes) y jsonlite.

install.packages(c("ggplot2", "ggsci", "plotly", "htmlwidgets", "slider", "jsonlite"))

Etapa 1 — Adquisición de datos climáticos (INMET)

La red de estaciones INMET

El Instituto Nacional de Meteorología (INMET) opera la mayor red de estaciones meteorológicas automáticas de Brasil, con cobertura en todos los estados. Los datos se ponen a disposición en formato CSV con resolución horaria e incluyen temperatura del aire (bulbo seco, máxima, mínima), humedad relativa, velocidad y dirección del viento, presión atmosférica y precipitación.

La función sus_climate_inmet() automatiza la descarga, el parsing y la estandarización de estos archivos a un formato listo para el análisis.

Parámetros principales

# Estrutura da chamada completa
df_inmet <- sus_climate_inmet(
  years        = 2010:2023,   # Vetor de anos
  uf           = "RN",        # UF (sigla) para filtrar estações
  station_code = NULL,        # Código(s) específico(s) de estação (opcional)
  use_cache    = TRUE,        # Reutilizar arquivos já baixados
  cache_dir    = "~/.climasus4r_cache/climate",
  parallel     = TRUE,        # Download paralelo
  workers      = 4,           # Número de workers
  lang         = "pt",
  verbose      = TRUE
)
Parámetro Tipo Descripción
years entero o vector Años a descargar (ej.: 2010:2023)
uf character Sigla del estado para filtrar estaciones (ej.: "RN", "SP")
station_code character Código(s) específico(s) de estación INMET (ej.: "A304")
use_cache lógico Si TRUE, reutiliza archivos ya descargados en cache_dir
parallel lógico Habilita descarga paralela vía furrr/future
workers entero Número de workers para ejecución paralela

Ejemplo: estación de Natal (RN)

En este tutorial utilizamos datos de la estación automática de Natal (código INMET A304), en Rio Grande do Norte — estado del Nordeste brasileño con clima semiárido e historial de olas de calor intensas.

# Download de dados horários (2010–2023)
# A primeira execução pode levar alguns minutos; execuções subsequentes usam cache.
df_inmet <- sus_climate_inmet(
  years        = 2010:2023,
  station_code = "A304",   # Natal - RN
  use_cache    = TRUE,
  lang         = "pt",
  verbose      = TRUE
)

# Inspecionar estrutura
glimpse(df_inmet)

La salida es un data.frame con resolución horaria y columnas estandarizadas por climasus4r:

#> Rows: ~122,640  (14 anos × 365 dias × 24 horas)
#>  Columns: ~20
#> 
#>  $ date               <POSIXct>  2010-01-01 00:00:00, 2010-01-01 01:00:00 ...
#>  $ station_code       <chr>      'A304', 'A304', ...
#>  $ station_name       <chr>      'NATAL', 'NATAL', ...
#>  $ federal_unit       <chr>      'RN', 'RN', ...
#>  $ region             <chr>      'Nordeste', 'Nordeste', ...
#>  $ latitude           <dbl>      -5.84, -5.84, ...
#>  $ longitude          <dbl>      -35.21, -35.21, ...
#>  $ tair_dry_bulb_c    <dbl>      28.4, 27.9, ...
#>  $ tair_max_c         <dbl>      29.1, 28.6, ...
#>  $ tair_min_c         <dbl>      27.8, 27.3, ...
#>  $ rh_pct             <dbl>      82.0, 84.0, ...
#>  $ wind_speed_ms      <dbl>      3.2, 2.8, ...
#>  $ precip_mm          <dbl>      0.0, 0.0, ...

Origen de los datos: Los datos brutos son los archivos CSV disponibles públicamente por el INMET en https://portal.inmet.gov.br/dadoshistoricos. climasus4r realiza el parsing automático de cada archivo anual, aplica control de calidad y estandariza los nombres de las columnas. No se realiza ninguna interpolación ni modificación de valores en esta etapa.


Etapa 2 — Relleno de lagunas (gap-filling)

El problema de las lagunas en series horarias

Las estaciones automáticas del INMET presentan con frecuencia lagunas causadas por fallas de transmisión, mantenimiento de equipos o eventos climáticos extremos. La presencia de valores ausentes (NA) en columnas de temperatura puede inviabilizar el cálculo de índices de confort térmico y comprometer las estimaciones percentílicas utilizadas en la detección de olas de calor.

La función sus_climate_fill_inmet() implementa un relleno inteligente basado en modelos de regresión entrenados con covariables meteorológicas correlacionadas (temperatura del aire, humedad relativa, velocidad del viento, hora del día, estacionalidad). El relleno se realiza variable por variable y respeta un umbral máximo de lagunas (gap_percentage): si la proporción de valores ausentes en una serie determinada supera ese umbral, la estación se marca como de baja calidad y no se aplica ningún relleno.

Parámetros principales

df_filled <- sus_climate_fill_inmet(
  df               = df_inmet,
  target_var       = "tair_dry_bulb_c",  # Variável a preencher
  datetime_col     = NULL,     # Detectado automaticamente
  station_col      = NULL,     # Detectado automaticamente
  quality_threshold = 0.4,    # Máximo de NAs para aceitar a série (40%)
  run_evaluation   = FALSE,   # Se TRUE: avalia métricas de ajuste
  gap_percentage   = 0.2,     # Intervalo máximo de gap contínuo a preencher (20%)
  keep_features    = FALSE,   # Manter covariáveis auxiliares no output
  parallel         = TRUE,
  workers          = NULL,    # NULL = detectar automaticamente
  verbose          = TRUE,
  lang             = "pt"
)

Relleno del conjunto completo

En la práctica, aplicamos el relleno a cada variable de temperatura y humedad relevante antes de calcular los indicadores de confort térmico:

# Preencher temperatura do ar (bulbo seco)
df_filled <- sus_climate_fill_inmet(
  df         = df_inmet,
  target_var = "tair_dry_bulb_c",
  lang       = "pt",
  verbose    = TRUE
)

# Preencher temperatura máxima e mínima
df_filled <- sus_climate_fill_inmet(df_filled, target_var = "tair_max_c",  lang = "pt")
df_filled <- sus_climate_fill_inmet(df_filled, target_var = "tair_min_c",  lang = "pt")

# Preencher umidade relativa (necessária para UTCI, WBGT, HI)
df_filled <- sus_climate_fill_inmet(df_filled, target_var = "rh_pct",       lang = "pt")

# Verificar proporção de NAs remanescentes
df_filled |>
  summarise(
    n_total    = n(),
    na_tmax    = mean(is.na(tair_max_c)),
    na_tmin    = mean(is.na(tair_min_c)),
    na_tair    = mean(is.na(tair_dry_bulb_c)),
    na_rh      = mean(is.na(rh_pct))
  )

Buena práctica: Aplique siempre sus_climate_fill_inmet() antes de sus_climate_compute_heatwaves(). La función de detección emite un aviso (cli_warn) si encuentra NAs en las columnas de temperatura, pero no los rellena automáticamente — esa decisión corresponde al analista, ya que diferentes estrategias de imputación pueden influir en los resultados.


Etapa 3 — Cálculo de indicadores climáticos

¿Por qué ir más allá de la temperatura del aire?

La temperatura del aire (bulbo seco) es la variable meteorológica más disponible, pero no es la mejor proxy para el estrés térmico humano. El cuerpo humano responde al ambiente térmico resultante de la combinación de temperatura, humedad, radiación solar y velocidad del viento. Los índices de confort térmico integran estos cuatro factores y permiten estimar la percepción fisiológica del calor de forma más realista.

La función sus_climate_compute_indicators() calcula los principales índices utilizados en las metodologías de detección de olas de calor implementadas en climasus4r:

<div class="feature-icon">🌡️</div>
<h3>UTCI</h3>
<p><strong>Universal Thermal Climate Index.</strong> Modelo biometeorológico de referencia de la ISO 15743. Integra temperatura, humedad, viento y radiación en una temperatura equivalente fisiológica (°C).</p>
<div class="feature-icon">💧</div>
<h3>WBGT</h3>
<p><strong>Wet Bulb Globe Temperature.</strong> Índice operacional ampliamente utilizado en salud ocupacional y deportes. Combina temperatura húmeda, temperatura del globo negro y temperatura del aire seco.</p>
<div class="feature-icon">🥵</div>
<h3>HI</h3>
<p><strong>Heat Index (Índice de Calor).</strong> Temperatura aparente calculada a partir del bulbo seco y de la humedad relativa. Indica cómo percibe el calor la población en general.</p>
<div class="feature-icon">🌿</div>
<h3>PET</h3>
<p><strong>Physiological Equivalent Temperature.</strong> Temperatura de un ambiente de referencia con los mismos intercambios de calor del cuerpo. Frecuentemente utilizado en estudios de confort urbano.</p>

Llamada a la función

df_indicators <- sus_climate_compute_indicators(
  df                   = df_filled,
  indicators           = "all",      # Calcular todos os indicadores disponíveis
  region               = "auto",     # Detectar região automaticamente por metadados
  apply_validity_mask  = TRUE,       # Mascarar valores fora dos limites físicos
  verify_physics       = TRUE,       # Verificar consistência física
  keep_source_vars     = TRUE,       # Manter variáveis originais no output
  verbose              = TRUE,
  lang                 = "pt"
)

# Verificar colunas adicionadas
names(df_indicators) |> grep("utci|wbgt|hi_c|pet", x = _, value = TRUE)

Después de esta etapa, el data.frame contiene las columnas adicionales necesarias para la detección de olas de calor por los métodos UTCI, WBGT y HI:

Columna nueva Índice Unidad
utci_c UTCI °C
wbgt_c WBGT °C
hi_c Heat Index °C
pet_c PET °C
utci_c_flag_extreme Horas con UTCI > 38°C lógico
wbgt_c_flag_extreme Horas con WBGT > 32°C lógico
hi_c_flag_extreme Horas con HI > 51°C lógico

Etapa 4 — Detección de olas de calor

La función sus_climate_compute_heatwaves()

Esta es la función central del módulo climático de climasus4r. Recibe datos horarios (producto de sus_climate_compute_indicators()), los agrega a escala diaria, calcula umbrales históricos percentílicos por estación del año (usando una ventana deslizante de ±15 días alrededor de cada día del año), aplica cada metodología de detección seleccionada y devuelve una lista estructurada con tres componentes.

Firma completa

hw_result <- sus_climate_compute_heatwaves(
  data           = df_indicators,   # Output de sus_climate_compute_indicators()
  method         = c("WHO", "WMO", "INMET", "EHF", "UTCI", "WBGT", "HI"),
  baseline_start = "2010-01-01",    # Início do período de referência
  baseline_end   = "2020-12-31",    # Fim do período de referência
  percentile     = 90,              # Percentil para limiares (P90 por padrão)
  min_duration   = NULL,            # NULL = usar defaults por método
  lang           = "pt",
  verbose        = TRUE
)

Metodologías implementadas

La Tabla 1 presenta las siete metodologías implementadas, incluyendo la variable base, el criterio de umbral y la duración mínima predeterminada.

Tabla 1 — Metodologías de detección de olas de calor implementadas en sus_climate_compute_heatwaves()

Método Variable base Criterio de umbral Duración mínima Referencia
WHO Tmax diaria Tmax > P90(Tmax) 3 días WMO & WHO (2015)
WMO Tmax y Tmin diarias Tmax > P90(Tmax) Y Tmin > P90(Tmin) 5 días Perkins & Alexander (2013)
INMET Tmax diaria Tmax > media histórica + 5°C 5 días INMET (2009)
EHF Tmean diaria EHF > 0 (fórmula compuesta; ver abajo) 3 días Nairn & Fawcett (2015)
UTCI UTCImax diario UTCImax > P90(UTCImax) 3 días Broede et al. (2012)
WBGT WBGTmax diario WBGTmax > P90(WBGTmax) 3 días Liljegren et al. (2008)
HI HImax diario HImax > P90(HImax) 3 días Steadman (1979)

Suavizado estacional de los percentiles: Para todos los métodos basados en percentiles, climasus4r utiliza una ventana deslizante de ±15 días en torno a cada día del año (calculada sobre el periodo de referencia), y no un percentil fijo calculado sobre toda la serie. Este enfoque, recomendado por Fischer & Schär (2010), elimina el sesgo estacional y garantiza que el mismo nivel de extremidad relativa sea detectado en cualquier época del año.

Fundamentos del Excess Heat Factor (EHF)

El EHF (Nairn & Fawcett, 2015) es el único método que no utiliza percentiles directos de la variable base. Combina dos componentes:

EHF=EHIsig×max⁡(1,EHIacc)\text{EHF} = \text{EHI}_{sig} \times \max(1, \text{EHI}_{acc})

Donde:

  • EHI_sig (índice de significancia): T‾3−T95\bar{T}_3 - T_{95}, mide cuánto la temperatura media de los últimos 3 días supera el percentil 95 climatológico de la temperatura media. Captura la magnitud absoluta del calor.
  • EHI_acc (índice de aclimatación): T‾3−T‾30\bar{T}_3 - \bar{T}_{30}, mide cuánto la temperatura media de los últimos 3 días supera la media de los 30 días anteriores. Captura la velocidad de calentamiento y la capacidad de aclimatación de la población.

Los días con EHF > 0 se clasifican como días de ola de calor. La intensidad del evento se clasifica en tres categorías con base en el percentil 85 (EHF85) de todos los valores positivos de EHF observados en la estación:

  • Baja Intensidad (LIHW): 0 < EHF_peak < EHF85
  • Severa (SHW): EHF85 ≤ EHF_peak < 3 × EHF85
  • Extrema (EHW): EHF_peak ≥ 3 × EHF85

Método INMET: calibración para Brasil

El método INMET define una ola de calor cuando la temperatura máxima diaria supera la media climatológica de la temperatura máxima en al menos 5°C durante 5 o más días consecutivos (INMET, 2009). La media climatológica se calcula sobre el periodo de referencia definido por el usuario (se recomienda 1981–2010 o 1991–2020, según la disponibilidad de datos).

Este criterio es particularmente adecuado para el contexto tropical y subtropical brasileño, donde los valores absolutos de temperatura ya son elevados y el impacto sobre la salud está más asociado a la desviación respecto a la norma local que al valor absoluto.

Ejecutando la detección

Ejemplo 1: métodos basados en temperatura del aire

# Métodos que requerem apenas temperatura do ar (Tmax, Tmin, Tmean)
hw_temp <- sus_climate_compute_heatwaves(
  data           = df_indicators,
  method         = c("WHO", "WMO", "INMET", "EHF"),
  baseline_start = "2010-01-01",
  baseline_end   = "2020-12-31",
  percentile     = 90,
  lang           = "pt",
  verbose        = TRUE
)

Ejemplo 2: todos los métodos (incluyendo índices de confort)

# Todos os métodos — requer colunas utci_c, wbgt_c, hi_c
hw_all <- sus_climate_compute_heatwaves(
  data           = df_indicators,
  method         = "all",          # Equivale a c("WHO","WMO","INMET","EHF","UTCI","WBGT","HI")
  baseline_start = "2010-01-01",
  baseline_end   = "2020-12-31",
  percentile     = 90,
  lang           = "pt",
  verbose        = TRUE
)

Ejemplo 3: personalizando el percentil y la duración mínima

# Critério mais conservador: P95 e mínimo de 5 dias para todos os métodos
hw_strict <- sus_climate_compute_heatwaves(
  data           = df_indicators,
  method         = c("WHO", "INMET"),
  baseline_start = "2010-01-01",
  baseline_end   = "2020-12-31",
  percentile     = 95,       # Limiar mais alto → menos eventos, mais intensos
  min_duration   = 5,        # Substitui os defaults por método
  lang           = "pt",
  verbose        = TRUE
)

Análisis de sensibilidad: Se recomienda ejecutar la detección con diferentes combinaciones de percentil (P85, P90, P95) y duración mínima (3, 5, 7 días) y comparar el número de eventos detectados. Esto permite evaluar la robustez de los resultados epidemiológicos frente a las decisiones metodológicas.

Estructura del output

La función devuelve una lista con nombre con tres componentes:

# Inspecionar o output
names(hw_all)
#> [1] "events"  "daily"   "summary"

$events — tabla de eventos

Un data.frame con una fila por evento de ola de calor detectado. Cada fila representa un episodio continuo de días con la condición de ola de calor activa para un método y estación determinados.

# Primeiros eventos detectados
head(hw_all$events)
Columna Tipo Descripción
event_id character Identificador único: <estación>_<método>_<N>
station_code character Código INMET de la estación
method character Método de detección (WHO, WMO, etc.)
start_date Date Fecha de inicio del evento
end_date Date Fecha de fin del evento
duration_days integer Duración en días consecutivos
temp_mean double Temperatura media del periodo (variable del método)
temp_peak double Temperatura máxima del periodo
anomaly_mean double Anomalía media (temperatura - umbral)
anomaly_cumulative double Anomalía acumulada a lo largo del evento
severity_index double Índice de severidad: duración × anomalía media
ehf_peak double Pico del EHF (solo método EHF; NA para otros)
ehf_mean double Media del EHF durante el evento (solo EHF)
intensity_class character Clasificación: Low, Severe, Extreme (solo EHF)
region character Región geográfica de la estación
federal_unit character UF de la estación
# Filtrar os 10 eventos mais severos pelo índice de severidade
hw_all$events |>
  arrange(desc(severity_index)) |>
  select(event_id, method, start_date, end_date, duration_days,
         temp_peak, anomaly_mean, severity_index) |>
  head(10)
# Contar eventos por método
hw_all$events |>
  count(method, name = "n_eventos") |>
  arrange(desc(n_eventos))

$daily — serie diaria con flags

El data.frame diario contiene una fila por estación por día, con las variables agregadas y columnas lógicas (TRUE/FALSE) que indican si ese día pertenece a una ola de calor según cada método:

# Inspecionar colunas de flags
hw_all$daily |>
  select(station_code, date_day, tmax, tmean, starts_with("hw_")) |>
  head(10)

La columna hw_any es TRUE si cualquier método detectó ola de calor ese día — útil para análisis de exposición sin compromiso con un único criterio.

# Dias com onda de calor ativa por pelo menos um método
hw_all$daily |>
  filter(hw_any == TRUE) |>
  select(date_day, tmax, tmean, hw_who, hw_inmet, hw_ehf, hw_utci) |>
  head(20)
# Concordância entre métodos: proporção de dias classificados por cada um
hw_all$daily |>
  summarise(
    pct_who   = mean(hw_who,   na.rm = TRUE) * 100,
    pct_wmo   = mean(hw_wmo,   na.rm = TRUE) * 100,
    pct_inmet = mean(hw_inmet, na.rm = TRUE) * 100,
    pct_ehf   = mean(hw_ehf,   na.rm = TRUE) * 100,
    pct_utci  = mean(hw_utci,  na.rm = TRUE) * 100,
    pct_wbgt  = mean(hw_wbgt,  na.rm = TRUE) * 100,
    pct_hi    = mean(hw_hi,    na.rm = TRUE) * 100,
    pct_any   = mean(hw_any,   na.rm = TRUE) * 100
  )

$summary — resumen anual

El resumen anual agrega las estadísticas por estación, método y año, siendo el punto de entrada natural para análisis de tendencia temporal:

# Resumo anual
hw_all$summary |>
  filter(method == "INMET") |>
  select(year, station_code, n_events, total_days_hw,
         mean_duration, max_duration, mean_anomaly, severity_total) |>
  arrange(desc(year))
Columna Descripción
year Año
station_code Código de la estación
method Método de detección
n_events Número de eventos en el año
total_days_hw Total de días de ola de calor en el año
mean_duration Duración media de los eventos (días)
max_duration Duración del evento más largo (días)
mean_intensity Temperatura media en los eventos
max_intensity Temperatura de pico en los eventos
mean_anomaly Anomalía media en los eventos
severity_total Suma de los índices de severidad de los eventos del año

Etapa 5 — Visualización de olas de calor

La función sus_climate_plot_heatwaves()

La visualización transforma el output estructurado de sus_climate_compute_heatwaves() en gráficos interpretativos. La función ofrece cuatro tipos de visualización, cada uno respondiendo a una pregunta analítica diferente:

<div class="feature-icon">📅</div>
<h3>timeline</h3>
<p>Diagrama de Gantt que muestra la posición temporal, duración e intensidad de cada evento. Ideal para comparar eventos entre métodos y estaciones.</p>
<div class="feature-icon">🗓️</div>
<h3>calendar</h3>
<p>Mapa de calor tipo calendario que muestra la ocurrencia diaria de olas de calor a lo largo de los meses. Revela patrones estacionales y distribución intraanual.</p>
<div class="feature-icon">⚡</div>
<h3>intensity</h3>
<p>Dispersión duración × temperatura de pico, con punto coloreado según la clase de intensidad. Distingue eventos largos de eventos cálidos.</p>
<div class="feature-icon">📈</div>
<h3>trend</h3>
<p>Barras agrupadas del número de eventos por año y método. Permite identificar tendencias de largo plazo en la frecuencia de olas de calor.</p>

Firma completa

p <- sus_climate_plot_heatwaves(
  hw_result     = hw_all,          # Output de sus_climate_compute_heatwaves()
  type          = "timeline",      # "timeline" | "calendar" | "intensity" | "trend"
  station_code  = NULL,            # Filtrar por estação específica
  method        = NULL,            # Filtrar por método (ex.: "INMET", "EHF")
  year          = NULL,            # Filtrar por ano (útil para "calendar")
  interactive   = TRUE,            # TRUE = plotly; FALSE = ggplot2 estático
  color_palette = "npg",           # Paleta ggsci: "npg", "lancet", "jama", etc.
  lang          = "pt",            # "pt" | "en" | "es"
  save_plot     = NULL             # Caminho para salvar (HTML ou PNG)
)
Parámetro Opciones Efecto
type "timeline", "calendar", "intensity", "trend" Tipo de gráfico
interactive TRUE (plotly), FALSE (ggplot2) Interactividad
color_palette cualquier paleta del paquete ggsci Esquema de colores
lang "pt", "en", "es" Idioma de las etiquetas
save_plot ruta .html o .png Guardar el gráfico en disco

Plot 1: Línea del tiempo (timeline)

El gráfico de línea del tiempo presenta cada evento como un segmento horizontal (estilo Gantt), con espesor proporcional a la duración y color que indica la clase de intensidad (relevante para EHF; para otros métodos, todos los eventos se clasifican como “desconocido” en la leyenda de intensidad).

# Linha do tempo de todos os eventos — todos os métodos
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "timeline",
  interactive = TRUE,
  lang        = "pt"
)
# Filtrar apenas eventos pelo método INMET
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "timeline",
  method      = "INMET",
  interactive = TRUE,
  lang        = "pt"
)
# Versão estática para publicação
p_timeline <- sus_climate_plot_heatwaves(
  hw_result     = hw_all,
  type          = "timeline",
  method        = c("WHO", "INMET", "EHF"),
  interactive   = FALSE,        # ggplot2 puro
  color_palette = "lancet",     # Paleta Lancet (jornais biomédicos)
  lang          = "pt",
  save_plot     = "timeline_ondas_calor.png"  # Salvar em PNG
)
print(p_timeline)

Interpretación: Los segmentos más largos indican eventos más duraderos; el espesor refuerza visualmente la duración. Observe que el método WMO (doble umbral: Tmax Y Tmin) tiende a generar menos eventos y de mayor duración que el WHO (solo Tmax), pues exige que tanto el día como la noche sean excepcionalmente cálidos.

Plot 2: Calendario (calendar)

El calendario muestra cada día del año en celdas coloreadas — rojo para días de ola de calor, gris para días normales. Es el gráfico más intuitivo para comunicar la estacionalidad de los eventos al público no técnico.

# Calendário para um ano específico — método WHO
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "calendar",
  method      = "WHO",
  year        = 2023,
  interactive = TRUE,
  lang        = "pt"
)
# Calendário com hw_any (qualquer método) — todos os anos
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "calendar",
  method      = NULL,          # NULL → usa hw_any (qualquer método)
  interactive = FALSE,
  lang        = "pt"
)

Interpretación: Observe la concentración de días de ola de calor en los meses de verano austral (diciembre–marzo) en el Nordeste. Los años con múltiples bloques rojos consecutivos merecen atención especial: en esos periodos, el exceso de mortalidad en el SUS tiende a ser mayor (Fiocruz, 2025).

Plot 3: Intensidad vs. duración (intensity)

Este gráfico de dispersión ubica cada evento en el plano cartesiano duración × temperatura de pico. La coloración por clase de intensidad EHF (cuando está disponible) permite identificar eventos que combinan larga duración y alta temperatura — los de mayor riesgo epidemiológico.

# Intensidade EHF (com classificação Low / Severe / Extreme)
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "intensity",
  method      = "EHF",
  interactive = TRUE,
  lang        = "pt"
)
# Todos os métodos juntos (sem classificação de intensidade EHF)
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "intensity",
  method      = NULL,
  interactive = FALSE,
  lang        = "pt"
)

Interpretación: Los eventos en el cuadrante superior derecho (larga duración + alta temperatura) son los más peligrosos desde el punto de vista de la salud pública. Los eventos en el cuadrante inferior derecho (larga duración + temperatura moderada) pueden ser igualmente peligrosos para poblaciones sin aclimatación. El EHF captura este matiz a través del componente EHI_acc (aclimatación), penalizando eventos que ocurren tras un periodo anormalmente frío.

Plot 4: Tendencia anual (trend)

El gráfico de tendencia muestra el número de eventos detectados por año para cada método, permitiendo identificar si la frecuencia de olas de calor está aumentando a lo largo del periodo analizado — una de las principales previsiones de los escenarios de cambio climático para Brasil.

# Tendência anual — todos os métodos
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "trend",
  interactive = TRUE,
  lang        = "pt"
)
# Tendência apenas para WHO e INMET (comparação de sensibilidade)
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "trend",
  method      = c("WHO", "INMET"),
  interactive = FALSE,
  lang        = "pt",
  save_plot   = "tendencia_ondas_calor.png"
)

Interpretación: Si la tendencia de frecuencia es creciente, esto es consistente con el calentamiento regional. Compare los patrones entre métodos: el método INMET tiende a ser más restrictivo en regiones ya cálidas (pues exige +5°C sobre la media histórica), mientras que los métodos percentílicos capturan aumentos relativos incluso en regiones donde las temperaturas absolutas son elevadas durante todo el año.

Guardando gráficos

# Gráfico interativo → arquivo HTML autossuficiente
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "timeline",
  interactive = TRUE,
  lang        = "pt",
  save_plot   = "ondas_calor_timeline.html"
)

# Gráfico estático → PNG de alta resolução (300 dpi)
sus_climate_plot_heatwaves(
  hw_result   = hw_all,
  type        = "trend",
  interactive = FALSE,
  lang        = "pt",
  save_plot   = "ondas_calor_tendencia.png"   # ggsave com dpi=300
)

Análisis avanzado de los resultados

Integrando eventos al calendario epidemiológico

El componente $daily con la columna hw_any puede cruzarse directamente con datos de mortalidad y morbilidad del SUS para calcular el exceso de defunciones e ingresos hospitalarios durante olas de calor:

# Exemplo conceitual: cruzamento com dados de mortalidade SIM
# (após completar o pipeline de importação dos dados SIM)

# 1. Preparar a série diária de mortalidade cardiovascular
# df_sim_diario <- sus_data_aggregate(df_sim, by = "day") |>
#   filter(cid_grupo == "I" | cid_grupo == "J")  # Cardiovascular + Respiratório

# 2. Adicionar flag de onda de calor
# df_analise <- df_sim_diario |>
#   left_join(
#     hw_all$daily |> select(date_day, hw_any, hw_inmet, tmax),
#     by = c("date" = "date_day")
#   )

# 3. Comparar mortalidade em dias com/sem onda de calor
# df_analise |>
#   group_by(hw_any) |>
#   summarise(
#     n_dias       = n(),
#     obitos_medio = mean(n_obitos, na.rm = TRUE),
#     sd           = sd(n_obitos, na.rm = TRUE)
#   )

Exportando eventos para análisis externo

# Exportar tabela de eventos para CSV
write.csv(
  hw_all$events,
  file      = "eventos_ondas_calor_A304_2010_2023.csv",
  row.names = FALSE,
  fileEncoding = "UTF-8"
)

# Exportar resumo anual
write.csv(
  hw_all$summary,
  file      = "resumo_anual_ondas_calor_A304.csv",
  row.names = FALSE,
  fileEncoding = "UTF-8"
)

Análisis de concordancia entre métodos

# Proporção de dias classificados como onda de calor por N métodos simultaneamente
hw_all$daily |>
  mutate(
    n_methods = rowSums(
      across(c(hw_who, hw_wmo, hw_inmet, hw_ehf, hw_utci, hw_wbgt, hw_hi)),
      na.rm = TRUE
    )
  ) |>
  count(n_methods) |>
  mutate(pct = round(n / sum(n) * 100, 1))

El análisis de concordancia responde a una pregunta central de la epidemiología ambiental: ¿en cuántos de los días clasificados como ola de calor hay consenso entre los métodos? Una alta concordancia aumenta la confianza en los resultados; una baja concordancia sugiere que el impacto en salud puede variar significativamente según el criterio adoptado.


Referencias

Conceptos generales y marco de percentiles

  • Perkins, S.E. (2015). A review on the scientific understanding of heatwaves — their measurement, driving mechanisms, and changes at the global scale. Atmospheric Research, 164–165, 242–267. https://doi.org/10.1016/j.atmosres.2015.05.009
  • Perkins, S.E. & Alexander, L.V. (2013). On the measurement of heat waves. Journal of Climate, 26(13), 4500–4517.
  • Fischer, E.M. & Schär, C. (2010). Consistent geographical patterns of changes in high-impact European heatwaves. Nature Geoscience, 3, 398–403.

Métodos WHO y WMO

  • WMO & WHO (2015). Heatwaves and Health: Guidance on Warning-System Development. Organización Meteorológica Mundial, Ginebra.
  • WMO (2021). Guidelines on the Definition and Monitoring of Extreme Weather and Climate Events. Organización Meteorológica Mundial.

Método INMET

  • INMET — Instituto Nacional de Meteorología (2009). Normais Climatológicas do Brasil 1961–1990. Brasília: MAPA/INMET.
  • MCTI/Gov.br (2025). Relatórios de ondas de calor no Brasil (online).

EHF (Excess Heat Factor)

  • Nairn, J.R. & Fawcett, R.J.B. (2015). The Excess Heat Factor: A metric for heatwave intensity and its use in classifying heatwave severity. International Journal of Environmental Research and Public Health, 12(1), 227–253. https://doi.org/10.3390/ijerph120100227

UTCI (Universal Thermal Climate Index)

  • Broede, P., Fiala, D., Blazejczyk, K., Holmer, I., Jendritzky, G., Kampmann, B., Tinz, B. & Havenith, G. (2012). Deriving the operational procedure for the Universal Thermal Climate Index (UTCI). International Journal of Biometeorology, 56(3), 481–494. https://doi.org/10.1007/s00484-011-0454-1

WBGT (Wet Bulb Globe Temperature)

  • Liljegren, J.C., Carhart, R.A., Lawday, P., Tschopp, S. & Sharp, R. (2008). Modeling the wet bulb globe temperature using standard meteorological measurements. Journal of Occupational and Environmental Hygiene, 5(10), 645–655.
  • ISO 7243:2017. Ergonomics of the thermal environment — Assessment of heat stress using the WBGT index. Organización Internacional de Normalización.

HI (Heat Index)

  • Steadman, R.G. (1979). The assessment of sultriness. Part I: A temperature-humidity index based on human physiology and clothing science. Journal of Applied Meteorology, 18(7), 861–873.
  • Steadman, R.G. (1984). A universal scale of apparent temperature. Journal of Applied Meteorology and Climatology, 23(12), 1674–1687.

Contexto SUS y salud pública brasileña

  • Fiocruz (2025). Excess cardiovascular mortality associated with extreme heatwaves in Southeast Brazil, 2014–2023. Cadernos de Saúde Pública.
  • Observatório do Clima (2024). Mortalidade excessiva durante ondas de calor em áreas urbanas brasileiras (2000–2018).

Información de la sesión


climasus4r · Análisis integrado salud–clima–ambiente en Brasil

¿Encontró un problema o tiene sugerencias para este tutorial?

🐛 Reportar en GitHub