Skip to contents

Introdução

As ondas de calor estão entre os eventos climáticos extremos de maior relevância para a saúde pública, especialmente em um contexto de aquecimento global, urbanização acelerada e aumento da vulnerabilidade socioambiental. Esses eventos são caracterizados por períodos persistentes de temperaturas anormalmente elevadas em relação ao padrão climatológico de uma determinada localidade, podendo afetar diretamente o conforto térmico, a demanda por serviços de saúde, a mortalidade e a morbidade por causas sensíveis ao calor.

No Brasil, episódios recentes de calor extremo têm evidenciado a necessidade de ferramentas capazes de identificar, quantificar e visualizar ondas de calor de forma padronizada e reprodutível. Essa necessidade é ainda mais importante em estudos aplicados ao Sistema Único de Saúde (SUS), nos quais a integração entre dados meteorológicos, indicadores ambientais e desfechos em saúde permite investigar padrões de risco, subsidiar sistemas de alerta e apoiar estratégias de vigilância em saúde ambiental.

O pacote climasus4r oferece um pipeline integrado que vai desde o download de dados meteorológicos horários do INMET até o preenchimento de lacunas, cálculo de indicadores climáticos, detecção de ondas de calor e visualização dos eventos. Neste tutorial, apresentamos cada etapa desse processo com exemplos práticos, destacando não apenas a execução das funções, mas também a interpretação climatológica, epidemiológica e operacional dos resultados.

Nota sobre reprodutibilidade: Todo o pipeline é determinístico — dado o mesmo período de dados INMET e os mesmos parâmetros, os resultados são idênticos entre execuções. Os blocos de código marcados com eval = FALSE precisam de conexão com a internet para a etapa de download (INMET) e podem demorar alguns minutos dependendo do período solicitado.

O que é uma onda de calor?

Não existe uma definição única e universalmente aceita para onda de calor. Em geral, uma onda de calor pode ser entendida como um período de calor anormal, intenso e persistente, no qual a temperatura observada ultrapassa um determinado limiar de referência por vários dias consecutivos. Esse limiar pode ser definido de forma absoluta, como uma temperatura fixa, ou de forma relativa, como um percentil elevado da distribuição histórica de temperatura de uma determinada região.

Essa distinção é importante porque o impacto do calor depende do contexto climático local. Uma temperatura considerada extrema em uma cidade de clima mais ameno pode ser relativamente comum em regiões tropicais ou semiáridas. Por esse motivo, muitos estudos utilizam limiares baseados em percentis, como o percentil 90 ou 95, permitindo que a definição de calor extremo seja adaptada à climatologia de cada localidade.

De modo geral, a maioria das definições de onda de calor combina dois componentes principais:

  1. Limiar de temperatura — a temperatura (ou índice de conforto térmico) deve superar determinado valor crítico, tipicamente definido como um percentil alto da distribuição histórica (P90, P95) ou como um desvio fixo em relação à média climatológica.
  2. Duração mínima — a condição extrema deve persistir por pelo menos N dias consecutivos (comumente 3 ou 5 dias), distinguindo eventos sustentados de picos isolados.

A ausência de consenso não é uma limitação operacional: o climasus4r implementa as sete definições mais utilizadas na literatura (Tabela 1), permitindo análises de sensibilidade e comparações intermetodológicas.

Por que comparar métodos? Em regiões tropicais e subtropicais como o Brasil, o método INMET — calibrado para a realidade climática nacional — tende a detectar eventos que métodos percentílicos genéricos podem subestimar. Por outro lado, índices de conforto térmico como UTCI e WBGT capturam a percepção fisiológica de calor de forma mais completa do que a temperatura do ar isolada. Comparar resultados entre métodos é uma boa prática de análise de sensibilidade.

Visão geral do 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 recebe o produto da anterior e adiciona informação. A função sus_climate_compute_heatwaves() espera dados horários com colunas padronizadas de temperatura e índices de conforto térmico — exatamente o que sus_climate_compute_indicators() produz.


Configuração do ambiente

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

library(climasus4r)
library(dplyr)

Dependências opcionais: As funções de visualização requerem ggplot2, ggsci e plotly. Para gráficos interativos, instale também htmlwidgets. A etapa de indicadores climáticos requer slider (janelas deslizantes) e jsonlite.

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

Etapa 1 — Aquisição de dados climáticos (INMET)

A rede de estações INMET

O Instituto Nacional de Meteorologia (INMET) opera a maior rede de estações meteorológicas automáticas do Brasil, com cobertura em todos os estados. Os dados são disponibilizados em formato CSV com resolução horária e incluem temperatura do ar (bulbo seco, máxima, mínima), umidade relativa, velocidade e direção do vento, pressão atmosférica e precipitação.

A função sus_climate_inmet() automatiza o download, o parsing e a padronização desses arquivos para um formato pronto para análise.

Parâmetros principais

# 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 Descrição
years inteiro ou vetor Anos a baixar (ex.: 2010:2023)
uf character Sigla do estado para filtrar estações (ex.: "RN", "SP")
station_code character Código(s) específico(s) de estação INMET (ex.: "A304")
use_cache lógico Se TRUE, reaproveita arquivos já baixados em cache_dir
parallel lógico Habilita download paralelo via furrr/future
workers inteiro Número de workers para execução paralela

Exemplo: estação de Natal (RN)

Neste tutorial, utilizamos dados da estação automática de Natal (código INMET A304), no Rio Grande do Norte — estado do Nordeste brasileiro com clima semiárido e histórico de ondas 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)

A saída é um data.frame com resolução horária e colunas padronizadas pelo 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, ...

Origem dos dados: Os dados brutos são os arquivos CSV disponibilizados publicamente pelo INMET em https://portal.inmet.gov.br/dadoshistoricos. O climasus4r faz o parsing automático de cada arquivo anual, aplica controle de qualidade e padroniza os nomes de colunas. Nenhuma interpolação ou modificação de valores é realizada nesta etapa.


Etapa 2 — Preenchimento de lacunas (gap-filling)

O problema das lacunas em séries horárias

Estações automáticas do INMET frequentemente apresentam lacunas causadas por falhas de transmissão, manutenção de equipamentos ou eventos climáticos extremos. A presença de valores ausentes (NA) em colunas de temperatura pode inviabilizar o cálculo de índices de conforto térmico e comprometer as estimativas percentílicas utilizadas na detecção de ondas de calor.

A função sus_climate_fill_inmet() implementa um preenchimento inteligente baseado em modelos de regressão treinados com covariáveis meteorológicas correlacionadas (temperatura do ar, umidade relativa, velocidade do vento, hora do dia, sazonalidade). O preenchimento é realizado variável por variável e respeita um limiar máximo de lacunas (gap_percentage): se a proporção de valores ausentes em determinada série superar esse limiar, a estação é marcada como de baixa qualidade e nenhum preenchimento é aplicado.

Parâmetros principais

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"
)

Preenchimento do conjunto completo

Na prática, aplicamos o preenchimento a cada variável de temperatura e umidade relevante antes de calcular os indicadores de conforto 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))
  )

Boa prática: Sempre aplique sus_climate_fill_inmet() antes de sus_climate_compute_heatwaves(). A função de detecção emite um aviso (cli_warn) se encontrar NAs nas colunas de temperatura, mas não os preenche automaticamente — essa decisão cabe ao analista, pois diferentes estratégias de imputação podem influenciar os resultados.


Etapa 3 — Cálculo de indicadores climáticos

Por que ir além da temperatura do ar?

A temperatura do ar (bulbo seco) é a variável meteorológica mais disponível, mas não é a melhor proxy para o estresse térmico humano. O corpo humano responde ao ambiente térmico resultante da combinação de temperatura, umidade, radiação solar e velocidade do vento. Índices de conforto térmico integram esses quatro fatores e permitem estimar a percepção fisiológica de calor de forma mais realista.

A função sus_climate_compute_indicators() calcula os principais índices utilizados nas metodologias de detecção de ondas de calor implementadas no climasus4r:

<div class="feature-icon">🌡️</div>
<h3>UTCI</h3>
<p><strong>Universal Thermal Climate Index.</strong> Modelo biometeorológico de referência da ISO 15743. Integra temperatura, umidade, vento e radiação em uma temperatura equivalente fisiológica (°C).</p>
<div class="feature-icon">💧</div>
<h3>WBGT</h3>
<p><strong>Wet Bulb Globe Temperature.</strong> Índice operacional amplamente utilizado em saúde ocupacional e esportes. Combina temperatura úmida, temperatura do globo negro e temperatura do ar seco.</p>
<div class="feature-icon">🥵</div>
<h3>HI</h3>
<p><strong>Heat Index (Índice de Calor).</strong> Temperatura aparente calculada a partir do bulbo seco e da umidade relativa. Indica como o calor é percebido pela população em geral.</p>
<div class="feature-icon">🌿</div>
<h3>PET</h3>
<p><strong>Physiological Equivalent Temperature.</strong> Temperatura de um ambiente de referência com as mesmas trocas de calor do corpo. Frequentemente utilizado em estudos de conforto urbano.</p>

Chamada da função

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)

Após esta etapa, o data.frame contém as colunas adicionais necessárias para a detecção de ondas de calor pelos métodos UTCI, WBGT e HI:

Coluna nova Índice Unidade
utci_c UTCI °C
wbgt_c WBGT °C
hi_c Heat Index °C
pet_c PET °C
utci_c_flag_extreme Horas com UTCI > 38°C lógico
wbgt_c_flag_extreme Horas com WBGT > 32°C lógico
hi_c_flag_extreme Horas com HI > 51°C lógico

Etapa 4 — Detecção de ondas de calor

A função sus_climate_compute_heatwaves()

Esta é a função central do módulo climático do climasus4r. Ela recebe dados horários (produto de sus_climate_compute_indicators()), os agrega para escala diária, calcula limiares históricos percentílicos por estação do ano (usando uma janela deslizante de ±15 dias ao redor de cada dia do ano), aplica cada metodologia de detecção selecionada e retorna uma lista estruturada com três componentes.

Assinatura 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
)

Metodologias implementadas

A Tabela 1 apresenta as sete metodologias implementadas, incluindo a variável-base, o critério de limiar e a duração mínima padrão.

Tabela 1 — Metodologias de detecção de ondas de calor implementadas em sus_climate_compute_heatwaves()

Método Variável-base Critério de limiar Duração mínima Referência
WHO Tmax diária Tmax > P90(Tmax) 3 dias WMO & WHO (2015)
WMO Tmax e Tmin diárias Tmax > P90(Tmax) E Tmin > P90(Tmin) 5 dias Perkins & Alexander (2013)
INMET Tmax diária Tmax > média histórica + 5°C 5 dias INMET (2009)
EHF Tmean diária EHF > 0 (fórmula composta; ver abaixo) 3 dias Nairn & Fawcett (2015)
UTCI UTCImax diário UTCImax > P90(UTCImax) 3 dias Broede et al. (2012)
WBGT WBGTmax diário WBGTmax > P90(WBGTmax) 3 dias Liljegren et al. (2008)
HI HImax diário HImax > P90(HImax) 3 dias Steadman (1979)

Suavização sazonal dos percentis: Para todos os métodos baseados em percentil, o climasus4r utiliza uma janela deslizante de ±15 dias em torno de cada dia do ano (calculada sobre o período de referência), e não um percentil fixo calculado sobre toda a série. Essa abordagem, recomendada por Fischer & Schär (2010), elimina o viés sazonal e garante que o mesmo nível de extremidade relativa seja detectado em qualquer época do ano.

Fundamentos do Excess Heat Factor (EHF)

O EHF (Nairn & Fawcett, 2015) é o único método que não utiliza percentis diretos da variável-base. Ele combina dois componentes:

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

Onde:

  • EHI_sig (índice de significância): T‾3−T95\bar{T}_3 - T_{95}, mede o quanto a temperatura média dos últimos 3 dias supera o percentil 95 climatológico da temperatura média. Captura a magnitude absoluta do calor.
  • EHI_acc (índice de aclimatação): T‾3−T‾30\bar{T}_3 - \bar{T}_{30}, mede o quanto a temperatura média dos últimos 3 dias supera a média dos 30 dias anteriores. Captura a velocidade de aquecimento e a capacidade de aclimatação da população.

Dias com EHF > 0 são classificados como dias de onda de calor. A intensidade do evento é classificada em três categorias com base no percentil 85 (EHF85) de todos os valores positivos de EHF observados na estação:

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

Método INMET: calibração para o Brasil

O método INMET define onda de calor quando a temperatura máxima diária supera a média climatológica da temperatura máxima por pelo menos 5°C por 5 ou mais dias consecutivos (INMET, 2009). A média climatológica é calculada sobre o período de referência definido pelo usuário (recomenda-se 1981–2010 ou 1991–2020, conforme disponibilidade de dados).

Este critério é particularmente adequado para o contexto tropical e subtropical brasileiro, onde os valores absolutos de temperatura já são elevados e o impacto sobre a saúde está mais associado ao desvio em relação à norma local do que ao valor absoluto.

Executando a detecção

Exemplo 1: métodos baseados em temperatura do ar

# 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
)

Exemplo 2: todos os métodos (incluindo índices de conforto)

# 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
)

Exemplo 3: customizando o percentil e a duração 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álise de sensibilidade: Recomenda-se executar a detecção com diferentes combinações de percentil (P85, P90, P95) e duração mínima (3, 5, 7 dias) e comparar o número de eventos detectados. Isso permite avaliar a robustez dos resultados epidemiológicos em relação às escolhas metodológicas.

Estrutura do output

A função retorna uma lista nomeada com três componentes:

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

$events — tabela de eventos

Um data.frame com uma linha por evento de onda de calor detectado. Cada linha representa um episódio contínuo de dias com a condição de onda de calor ativa para um determinado método e estação.

# Primeiros eventos detectados
head(hw_all$events)
Coluna Tipo Descrição
event_id character Identificador único: <estação>_<método>_<N>
station_code character Código INMET da estação
method character Método de detecção (WHO, WMO, etc.)
start_date Date Data de início do evento
end_date Date Data de fim do evento
duration_days integer Duração em dias consecutivos
temp_mean double Temperatura média do período (variável do método)
temp_peak double Temperatura máxima do período
anomaly_mean double Anomalia média (temperatura - limiar)
anomaly_cumulative double Anomalia acumulada ao longo do evento
severity_index double Índice de severidade: duração × anomalia média
ehf_peak double Pico do EHF (apenas método EHF; NA para outros)
ehf_mean double Média do EHF durante o evento (apenas EHF)
intensity_class character Classificação: Low, Severe, Extreme (apenas EHF)
region character Região geográfica da estação
federal_unit character UF da estação
# 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 — série diária com flags

O data.frame diário contém uma linha por estação por dia, com as variáveis agregadas e colunas lógicas (TRUE/FALSE) indicando se aquele dia pertence a uma onda de calor segundo cada método:

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

A coluna hw_any é TRUE se qualquer método detectou onda de calor naquele dia — útil para análises de exposição sem comprometimento com um único critério.

# 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 — resumo anual

O resumo anual agrega as estatísticas por estação, método e ano, sendo o ponto de entrada natural para análises de tendência 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))
Coluna Descrição
year Ano
station_code Código da estação
method Método de detecção
n_events Número de eventos no ano
total_days_hw Total de dias de onda de calor no ano
mean_duration Duração média dos eventos (dias)
max_duration Duração do evento mais longo (dias)
mean_intensity Temperatura média nos eventos
max_intensity Temperatura de pico nos eventos
mean_anomaly Anomalia média nos eventos
severity_total Soma dos índices de severidade dos eventos no ano

Etapa 5 — Visualização de ondas de calor

A função sus_climate_plot_heatwaves()

A visualização transforma o output estruturado de sus_climate_compute_heatwaves() em gráficos interpretativos. A função oferece quatro tipos de visualização, cada um respondendo a uma pergunta analítica diferente:

<div class="feature-icon">📅</div>
<h3>timeline</h3>
<p>Diagrama de Gantt mostrando a posição temporal, duração e intensidade de cada evento. Ideal para comparar eventos entre métodos e estações.</p>
<div class="feature-icon">🗓️</div>
<h3>calendar</h3>
<p>Mapa de calor calendário que exibe a ocorrência diária de ondas de calor ao longo dos meses. Revela padrões sazonais e distribuição intra-anual.</p>
<div class="feature-icon">⚡</div>
<h3>intensity</h3>
<p>Dispersão duração × temperatura de pico, com ponto colorido por classe de intensidade. Distingue eventos longos de eventos quentes.</p>
<div class="feature-icon">📈</div>
<h3>trend</h3>
<p>Barras agrupadas do número de eventos por ano e método. Permite identificar tendências de longo prazo na frequência de ondas de calor.</p>

Assinatura 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 Opções Efeito
type "timeline", "calendar", "intensity", "trend" Tipo de gráfico
interactive TRUE (plotly), FALSE (ggplot2) Interatividade
color_palette qualquer paleta do pacote ggsci Esquema de cores
lang "pt", "en", "es" Idioma dos rótulos
save_plot caminho .html ou .png Salvar o gráfico em disco

Plot 1: Linha do tempo (timeline)

O gráfico de linha do tempo apresenta cada evento como um segmento horizontal (estilo Gantt), com espessura proporcional à duração e cor indicando a classe de intensidade (relevante para EHF; para outros métodos, todos os eventos são classificados como “desconhecido” na legenda de intensidade).

# 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)

Interpretação: Segmentos mais longos indicam eventos mais duradouros; a espessura reforça visualmente a duração. Observe que o método WMO (duplo limiar: Tmax E Tmin) tende a gerar menos eventos e de maior duração que o WHO (apenas Tmax), pois exige que tanto o dia quanto a noite sejam excepcionalmente quentes.

Plot 2: Calendário (calendar)

O calendário exibe cada dia do ano em células coloridas — vermelho para dias de onda de calor, cinza para dias normais. É o gráfico mais intuitivo para comunicar a sazonalidade dos eventos ao público não 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"
)

Interpretação: Observe a concentração de dias de onda de calor nos meses de verão austral (dezembro–março) no Nordeste. Anos com múltiplos blocos vermelhos consecutivos merecem atenção especial: nesses períodos, o excesso de mortalidade no SUS tende a ser maior (Fiocruz, 2025).

Plot 3: Intensidade vs. duração (intensity)

Este gráfico de dispersão posiciona cada evento no plano cartesiano duração × temperatura de pico. A coloração por classe de intensidade EHF (quando disponível) permite identificar eventos que combinam longa duração e alta temperatura — os de maior risco 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"
)

Interpretação: Eventos no quadrante superior direito (longa duração + alta temperatura) são os mais perigosos do ponto de vista de saúde pública. Eventos no quadrante inferior direito (longa duração + temperatura moderada) podem ser igualmente perigosos para populações sem aclimatação. O EHF captura essa nuance através do componente EHI_acc (aclimatação), penalizando eventos que ocorrem após período anormalmente frio.

Plot 4: Tendência anual (trend)

O gráfico de tendência mostra o número de eventos detectados por ano para cada método, permitindo identificar se a frequência de ondas de calor está aumentando ao longo do período analisado — uma das principais previsões dos cenários de mudança climática para o 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"
)

Interpretação: Se a tendência de frequência for crescente, isso é consistente com o aquecimento regional. Compare os padrões entre métodos: o método INMET tende a ser mais restritivo em regiões já quentes (pois exige +5°C sobre a média histórica), enquanto os métodos percentílicos capturam aumentos relativos mesmo em regiões onde as temperaturas absolutas são elevadas durante todo o ano.

Salvando 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álise avançada dos resultados

Integrando eventos ao calendário epidemiológico

O componente $daily com a coluna hw_any pode ser diretamente cruzado com dados de mortalidade e morbidade do SUS para calcular excesso de óbitos e internações durante ondas 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álise externa

# 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álise de concordância 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))

A análise de concordância responde a uma pergunta central da epidemiologia ambiental: em quantos dos dias classificados como onda de calor há consenso entre os métodos? Alta concordância aumenta a confiança nos resultados; baixa concordância sugere que o impacto em saúde pode variar significativamente dependendo do critério adotado.


Referências

Conceitos gerais e framework de percentis

  • 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 e WMO

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

Método INMET

  • INMET — Instituto Nacional de Meteorologia (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. Organização Internacional de Normalização.

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 e saúde pública brasileira

  • 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).

Informações da sessão


climasus4r · Análise integrada saúde–clima–ambiente no Brasil

Encontrou um problema ou tem sugestões para este tutorial?

🐛 Reportar no GitHub