Tutorial: Análise de Temperatura ERA5 para Favelas

Um Guia Passo a Passo para Buscar e Analisar Dados Climáticos com R

Published

November 25, 2025

Introdução

Este tutorial demonstra como buscar, processar e visualizar dados de temperatura do ERA5, a mais moderna reanálise climática global do ECMWF (Centro Europeu de Previsões Meteorológicas de Médio Prazo). Vamos cruzar esses dados com as coordenadas geográficas de favelas para extrair a temperatura em cada local, incluindo uma série histórica dos últimos 10 anos.

🎯 Objetivo

Extrair a temperatura do ar (a 2 metros de altura) para uma lista de favelas, usando suas latitudes e longitudes, e visualizar os resultados ao longo de uma série histórica de 10 anos (2016-2026).

🛠️ Ferramentas Utilizadas

  • Linguagem R: Uma linguagem poderosa para análise estatística e visualização de dados.
  • Pacote ecmwfr: Para conectar e baixar dados da API do Climate Data Store (CDS).
  • Pacote terra: Para manipular os dados climáticos em formato raster.
  • Pacotes tidyverse: Para manipulação e visualização de dados em geral.
  • Pacote jsonlite: Para exportar dados em formato JSON para sistemas web.

Passo 1: Preparação do Ambiente

O primeiro passo é garantir que todos os pacotes necessários estejam instalados e carregados no R.

1.1. Instalação dos Pacotes

O código abaixo verifica se os pacotes necessários já estão instalados e, caso contrário, os instala automaticamente. Execute este chunk apenas uma vez.

Mostrar/Ocultar Código
# Lista de pacotes necessários
pacotes_necessarios <- c(
  "ecmwfr",    # Interface para a API do CDS
  "tidyverse", # Manipulação e visualização de dados (inclui ggplot2, dplyr, etc.)
  "ncdf4",     # Leitura de arquivos NetCDF (formato dos dados do ERA5)
  "terra",     # Processamento de dados raster (geográficos)
  "sf",        # Manipulação de dados espaciais vetoriais
  "viridis",   # Paletas de cores para gráficos
  "jsonlite"   # Exportação de dados em formato JSON
)

# Função para instalar pacotes apenas se não estiverem presentes
instalar_se_necessario <- function(pacotes) {
  novos_pacotes <- pacotes[!(pacotes %in% installed.packages()[, "Package"])]
  if (length(novos_pacotes)) {
    install.packages(novos_pacotes, dependencies = TRUE, repos = "https://cloud.r-project.org/")
  }
}

# Executa a instalação
instalar_se_necessario(pacotes_necessarios)
cat("Todos os pacotes necessários estão instalados!\n")

1.2. Carregamento dos Pacotes

Agora, vamos carregar os pacotes que usaremos ao longo do tutorial.

Mostrar/Ocultar Código
# Carrega os pacotes de forma silenciosa
suppressPackageStartupMessages({
  library(ecmwfr)
  library(tidyverse)
  library(ncdf4)
  library(terra)
  library(sf)
  library(viridis)
  library(jsonlite)
})

cat("✓ Pacotes carregados com sucesso!\n")
✓ Pacotes carregados com sucesso!

Passo 2: Configuração da API do CDS

Para baixar dados do ERA5, você precisa de uma conta gratuita no Climate Data Store (CDS) e de uma chave de API.

2.1. Como Obter sua Chave de API

  1. Crie uma conta: Acesse o site cds.climate.copernicus.eu e registre-se.
  2. Acesse seu perfil: Após o login, clique no seu nome no canto superior direito e vá para “Your profile”.
  3. Copie sua chave: Na parte inferior da página, você encontrará sua API key. Ela se parece com isto: 12345:abcdef-1234-5678-90ab-cdef12345678.

2.2. Configurando a Chave no R

O pacote ecmwfr precisa saber sua chave. A função abaixo configura a chave para a sessão atual. Substitua SUA_API_KEY_AQUI pela sua chave real.

Mostrar/Ocultar Código
# Insira sua chave de API aqui
minha_api_key <- "8d9e5944-896a-4584-a7ef-136ede4aa1d2"

# Configura a chave para a sessão atual
# A nova API usa a chave completa no campo 'user' e 'key'
wf_set_key(user = "8d9e5944-896a-4584-a7ef-136ede4aa1d2", key = "8d9e5944-896a-4584-a7ef-136ede4aa1d2")

cat("✓ Cliente CDS configurado com sucesso!\n")

# IMPORTANTE: Aceite os termos de uso!
# Antes de prosseguir, acesse o link abaixo, faça login e aceite os termos de uso do dataset.
# Link: https://cds.climate.copernicus.eu/cdsapp#!/datasets/reanalysis-era5-single-levels

Aviso: Antes de baixar os dados, você precisa aceitar os termos de uso do dataset ERA5. Acesse o link do dataset, faça login, vá para a aba “Download data” e aceite os termos. Você só precisa fazer isso uma vez.


Passo 3: Carregar e Preparar os Dados das Favelas

Agora, vamos carregar o arquivo CSV com os dados das favelas e prepará-lo para a análise.

3.1. Carregando o Arquivo CSV

Vamos carregar o arquivo Favelas_Municipais.csv. Certifique-se de que este arquivo esteja no mesmo diretório do seu script R ou forneça o caminho completo.

Mostrar/Ocultar Código
# Caminho para o arquivo de dados
arquivo_favelas <- "Escolas_Municipais.csv"

# Carrega os dados
df_favelas <- read.csv(arquivo_favelas, fileEncoding = "UTF-8")

# Remove o caractere BOM (Byte Order Mark) que às vezes aparece no início
names(df_favelas)[1] <- gsub("^\uFEFF", "", names(df_favelas)[1])

cat(sprintf("✓ Dados carregados: %d favelas\n", nrow(df_favelas)))
✓ Dados carregados: 12741 favelas
Mostrar/Ocultar Código
# Exibe as primeiras linhas e a estrutura dos dados
head(df_favelas)
  gid      cd_fcu                                       nm_fcu cd_uf
1   1 35503080069                              Jardim Miliunas    35
2   2 42024040016                               Rua Araranguá    42
3   3 33045570554                                        Tiqui    33
4   4 33045570104                Parque Nossa Senhora da Penha    33
5   5 35095020135 Núcleo Residencial Jardim das Andorinhas II    35
6   6 33033020044                          Morro do Peixe Galo    33
           nm_uf sigla_uf  cd_mun         nm_mun cod_prov  latitude longitude
1     São Paulo       SP 3550308     São Paulo     4500 -23.49953 -46.37127
2 Santa Catarina       SC 4202404       Blumenau     8175 -26.93605 -49.05292
3 Rio de Janeiro       RJ 3304557 Rio de Janeiro     9521 -22.88999 -43.48308
4 Rio de Janeiro       RJ 3304557 Rio de Janeiro     7217 -22.87610 -43.21633
5     São Paulo       SP 3509502       Campinas     6648 -22.91879 -47.01470
6 Rio de Janeiro       RJ 3303302       Niterói     6070 -22.93630 -43.11104

3.2. Limpeza e Validação das Coordenadas

É uma boa prática limpar os dados, garantindo que não há coordenadas ausentes ou inválidas.

Mostrar/Ocultar Código
# Filtra favelas com coordenadas válidas para o Rio de Janeiro
df_favelas_clean <- df_favelas %>%
  # Remove linhas onde latitude ou longitude são nulas
  filter(!is.na(latitude) & !is.na(longitude)) %>%
  # Garante que as coordenadas são numéricas
  mutate(latitude = as.numeric(latitude), longitude = as.numeric(longitude)) 
  # Filtra coordenadas que estão fora da área esperada para o RJ
  #filter(latitude >= -23.5 & latitude <= -22.5,
  #       longitude >= -44.0 & longitude <= -43.0)

cat(sprintf("✓ Pré-processamento concluído: %d favelas válidas restantes.\n", nrow(df_favelas_clean)))
✓ Pré-processamento concluído: 12741 favelas válidas restantes.

Passo 4: Baixar os Dados de Temperatura do ERA5 (Série Histórica)

Com as coordenadas limpas, podemos definir a área de interesse e baixar os dados de temperatura para os últimos 10 anos.

4.1. Definindo a Área de Download (Bounding Box)

Para otimizar o download, criamos uma “caixa” (bounding box) um pouco maior que a área coberta por todas as favelas.

Mostrar/Ocultar Código
# Adiciona uma margem de 0.1 graus (~11 km) para garantir a cobertura
lat_min <- min(df_favelas_clean$latitude) - 0.1
lat_max <- max(df_favelas_clean$latitude) + 0.1
lon_min <- min(df_favelas_clean$longitude) - 0.1
lon_max <- max(df_favelas_clean$longitude) + 0.1

cat("Área de interesse para download (Bounding Box):\n")
Área de interesse para download (Bounding Box):
Mostrar/Ocultar Código
cat(sprintf("  Latitude: [%.4f, %.4f]\n", lat_min, lat_max))
  Latitude: [-32.1637, 2.9822]
Mostrar/Ocultar Código
cat(sprintf("  Longitude: [%.4f, %.4f]\n", lon_min, lon_max))
  Longitude: [-72.7888, -34.6963]

4.2. Criando a Requisição e Baixando os Dados (Últimos 10 Anos)

Agora, montamos a requisição para a API do CDS. Vamos pedir a temperatura (2m_temperature) para cada mês dos últimos 10 anos (2016-2026).

Mostrar/Ocultar Código
# Define os anos para a série histórica (últimos 10 anos)
anos <- 2016:2025

# Função para fazer download dos dados para cada ano
baixar_dados_serie_historica <- function(anos, lat_max, lon_min, lat_min, lon_max, minha_api_key) {
  
  lista_arquivos <- list()
  
  for (ano in anos) {
    cat(sprintf("\n📥 Baixando dados para o ano %d...\n", ano))
    
    # Define os parâmetros da requisição
    request <- list(
      dataset_short_name = "reanalysis-era5-single-levels-monthly-means",
      product_type       = "monthly_averaged_reanalysis",
      variable           = "2m_temperature",
      year               = as.character(ano),
      month              = c("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"),
      time               = "00:00",
      area               = c(lat_max, lon_min, lat_min, lon_max), # Formato: Norte, Oeste, Sul, Leste
      format             = "netcdf",
      target             = sprintf("era5_temperatura_favelas_%d.nc", ano) # Nome do arquivo de saída
    )
    
    # Executa a requisição
    arquivo_era5 <- wf_request(
      user    = minha_api_key,
      request = request,
      transfer = TRUE,
      path    = ".",
      verbose = TRUE
    )
    
    lista_arquivos[[as.character(ano)]] <- arquivo_era5
    cat(sprintf("✓ Download concluído para %d! Arquivo: %s\n", ano, arquivo_era5))
  }
  
  return(lista_arquivos)
}

# Executa o download para todos os anos
arquivos_era5 <- baixar_dados_serie_historica(anos, lat_max, lon_min, lat_min, lon_max, minha_api_key)

cat("\n✓ Todos os downloads foram concluídos!")

Nota: O download pode demorar bastante tempo, pois estamos baixando 10 anos de dados. O status da sua requisição pode ser acompanhado em cds.climate.copernicus.eu/cdsapp/yourrequests.


Passo 5: Extrair a Temperatura para Cada Favela (Série Histórica)

Com os arquivos de dados climáticos (.nc) baixados, vamos abri-los e extrair a temperatura para a localização exata de cada favela ao longo do tempo.

Mostrar/Ocultar Código
# Função para extrair temperatura de um arquivo NetCDF
extrair_temperatura_arquivo <- function(arquivo_nc, df_favelas_clean, ano) {
  
  # Carrega o arquivo NetCDF como um objeto raster
  raster_temp <- rast(arquivo_nc)
  
  # Converte a temperatura de Kelvin para Celsius
  raster_temp_celsius <- raster_temp - 273.15
  
  # Converte o dataframe das favelas para um objeto espacial
  pontos_favelas <- vect(
    df_favelas_clean,
    geom = c("longitude", "latitude"),
    crs = "EPSG:4326" # Sistema de coordenadas padrão (WGS84)
  )
  
  # Extrai os valores de temperatura para cada ponto (favela)
  # O método 'bilinear' faz uma interpolação suave entre os pixels do raster
  temperaturas_extraidas <- extract(raster_temp_celsius, pontos_favelas, method = "bilinear")
  
  # Cria um dataframe com os resultados
  df_resultado <- df_favelas_clean %>%
    mutate(
      ano = ano,
      temperatura_c = temperaturas_extraidas[, 2]
    )
  
  return(df_resultado)
}

# Extrai temperatura de todos os arquivos
lista_resultados <- list()

for (ano in anos) {
  arquivo <- arquivos_era5[[as.character(ano)]]
  
  cat(sprintf("📊 Extraindo temperatura para o ano %d...\n", ano))
  
  df_ano <- extrair_temperatura_arquivo(arquivo, df_favelas_clean, ano)
  lista_resultados[[as.character(ano)]] <- df_ano
}

# Combina todos os resultados em um único dataframe
df_final_serie <- bind_rows(lista_resultados)

cat("✓ Temperaturas extraídas com sucesso para toda a série histórica!\n")

# Exibe as primeiras linhas do resultado final
head(df_final_serie, 20)

Passo 6: Visualizar os Resultados da Série Histórica

A melhor forma de entender os dados é visualizando-os. Vamos criar visualizações para ver a distribuição espacial e temporal da temperatura.

6.1. Mapa de Calor Espacial

Mostrar/Ocultar Código
# Filtra dados do ano mais recente para visualização espacial
df_recente <- df_final_serie %>%
  filter(ano == max(ano))

# Cria o mapa de calor
ggplot(df_recente, aes(x = longitude, y = latitude, color = temperatura_c)) +
  # Adiciona os pontos no mapa
  geom_point(size = 3, alpha = 0.8) +
  # Define a paleta de cores (de azul/frio para amarelo/quente)
  scale_color_viridis_c(option = "spectrum", name = "Temp. (°C)") +
  # Adiciona títulos e rótulos
  labs(
    title = "Temperatura do Ar (ERA5) nas Favelas do Rio de Janeiro",
    subtitle = sprintf("Ano: %d", max(df_recente$ano)),
    x = "Longitude",
    y = "Latitude"
  ) +
  # Usa um tema limpo para o gráfico
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Salva o gráfico em um arquivo
ggsave("mapa_temperatura_favelas_espacial.png", width = 10, height = 12, dpi = 300)

6.2. Série Temporal

Mostrar/Ocultar Código
# Calcula a temperatura média por ano
df_media_temporal <- df_final_serie %>%
  group_by(ano) %>%
  summarise(
    temperatura_media = mean(temperatura_c, na.rm = TRUE),
    temperatura_min = min(temperatura_c, na.rm = TRUE),
    temperatura_max = max(temperatura_c, na.rm = TRUE),
    .groups = 'drop'
  )

# Cria o gráfico de série temporal
ggplot(df_media_temporal, aes(x = ano, y = temperatura_media)) +
  # Adiciona a linha de tendência
  geom_line(size = 1, color = "#2E86AB") +
  # Adiciona os pontos
  geom_point(size = 3, color = "#2E86AB") +
  # Adiciona intervalo de confiança (min-max)
  geom_ribbon(aes(ymin = temperatura_min, ymax = temperatura_max), 
              alpha = 0.2, fill = "#2E86AB") +
  # Adiciona títulos e rótulos
  labs(
    title = "Série Histórica de Temperatura (2016-2026)",
    subtitle = "Favelas do Rio de Janeiro - Dados ERA5",
    x = "Ano",
    y = "Temperatura Média (°C)"
  ) +
  # Usa um tema limpo
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Salva o gráfico
ggsave("serie_temporal_temperatura_favelas.png", width = 10, height = 6, dpi = 300)

Passo 7: Exportar os Dados em Formato Empilhado para Sistemas Web

Por fim, vamos exportar os dados em formato JSON empilhado (stacked), ideal para consumo por aplicações web e dashboards interativos.

7.1. Exportar em Formato JSON (Stacked)

Mostrar/Ocultar Código
# Cria a estrutura empilhada para JSON
dados_empilhados <- df_final_serie %>%
  # Seleciona as colunas relevantes
  select(
    id_favela = id,
    nome_favela = nome,
    estado = estado,
    cidade = cidade,
    latitude,
    longitude,
    ano,
    temperatura_c
  ) %>%
  # Converte para lista aninhada
  nest(dados_temperatura = -c(id_favela, nome_favela, estado, cidade, latitude, longitude)) %>%
  mutate(
    dados_temperatura = map(dados_temperatura, ~list(
      historico = .x %>% 
        arrange(ano) %>% 
        pmap(function(ano, temperatura_c) {
          list(ano = ano, temperatura_celsius = temperatura_c)
        })
    ))
  )

# Exporta para JSON
json_output <- toJSON(dados_empilhados, pretty = TRUE, auto_unbox = TRUE)
write(json_output, "favelas_temperatura_stacked.json")

cat("✓ Dados exportados em formato JSON empilhado: 'favelas_temperatura_stacked.json'\n")

7.2. Exportar em Formato CSV (Tradicional)

Mostrar/Ocultar Código
# Salva o dataframe final em um arquivo CSV
write.csv(df_final_serie, "favelas_com_temperatura_serie_historica.csv", 
          row.names = FALSE, fileEncoding = "UTF-8")

cat("✓ Resultados finais exportados para 'favelas_com_temperatura_serie_historica.csv'\n")

7.3. Exportar em Formato JSON (Formato Tabular)

Mostrar/Ocultar Código
# Exporta em formato tabular (mais simples para web)
json_tabular <- toJSON(df_final_serie, pretty = TRUE)
write(json_tabular, "favelas_temperatura_tabular.json")

cat("✓ Dados exportados em formato JSON tabular: 'favelas_temperatura_tabular.json'\n")

7.4. Criar Resumo Estatístico para Dashboard

Mostrar/Ocultar Código
# Cria um resumo estatístico por favela
resumo_favelas <- df_final_serie %>%
  group_by(id, nome, estado, cidade, latitude, longitude) %>%
  summarise(
    temperatura_media = mean(temperatura_c, na.rm = TRUE),
    temperatura_min = min(temperatura_c, na.rm = TRUE),
    temperatura_max = max(temperatura_c, na.rm = TRUE),
    desvio_padrao = sd(temperatura_c, na.rm = TRUE),
    n_observacoes = n(),
    .groups = 'drop'
  )

# Exporta o resumo em JSON
json_resumo <- toJSON(resumo_favelas, pretty = TRUE)
write(json_resumo, "favelas_temperatura_resumo.json")

cat("✓ Resumo estatístico exportado: 'favelas_temperatura_resumo.json'\n")

Passo 8: Validação e Qualidade dos Dados

Antes de usar os dados em produção, é importante validar a qualidade.

Mostrar/Ocultar Código
# Verifica valores ausentes
cat("📊 Análise de Qualidade dos Dados:\n")
cat(sprintf("Total de registros: %d\n", nrow(df_final_serie)))
cat(sprintf("Registros com temperatura válida: %d (%.2f%%)\n", 
            sum(!is.na(df_final_serie$temperatura_c)),
            100 * sum(!is.na(df_final_serie$temperatura_c)) / nrow(df_final_serie)))

# Estatísticas descritivas
cat("\n📈 Estatísticas Descritivas:\n")
print(summary(df_final_serie$temperatura_c))

# Verifica outliers (valores fora de 3 desvios padrão)
media <- mean(df_final_serie$temperatura_c, na.rm = TRUE)
desvio <- sd(df_final_serie$temperatura_c, na.rm = TRUE)
outliers <- df_final_serie %>%
  filter(abs(temperatura_c - media) > 3 * desvio)

cat(sprintf("\n⚠️ Possíveis outliers (>3σ): %d registros\n", nrow(outliers)))
if (nrow(outliers) > 0) {
  print(outliers %>% select(nome, ano, temperatura_c))
}

Conclusão

Parabéns! Você completou o tutorial de análise de temperatura ERA5 para favelas com série histórica. Os dados estão prontos para serem consumidos por sistemas web, dashboards interativos e análises posteriores.

Próximos Passos

  • Integre os arquivos JSON em um dashboard web (ex: Shiny, Plotly, D3.js)
  • Realize análises de tendência e mudanças climáticas
  • Compare os dados entre diferentes favelas e regiões
  • Crie alertas para anomalias de temperatura