CoolFace
Apppublic

dlpena84/ons-hidro-explorer

sourceHugging Facemitupdated 2mo agoView on Hugging Face
0likes
App README

💧 ONS Hidrológico Explorer

Toolbox em Streamlit para análise de dados operativos hidráulicos das usinas do Sistema Interligado Nacional (SIN) brasileiro, consumindo os dados abertos do ONS — Operador Nacional do Sistema Elétrico em formato Parquet.

A aplicação tem entry point único (app.py), com uma landing page de cards e navegação entre módulos via st.navigation. Cada módulo é um arquivo Python na raiz, executado pelo entry point.

Módulos

1. Gráficos Operativos · graficos_operativos.py

Visualização interativa de séries temporais para uma usina selecionada, com escolha entre base horária ou diária, eixo duplo (vazões em m³/s + nível/volume), linhas de referência configuráveis e exportação.

  • Bases:
  • Diária — parquets anuais, desde 01/01/2000
  • Horária — parquets mensais, desde 01/01/2010
  • Visualização com Plotly:
  • Linhas contínuas no eixo Y principal (vazões em m³/s)
  • Linha pontilhada no eixo Y secundário (nível em m ou volume útil em %)
  • Hover unificado mostrando todos os valores no ponto selecionado
  • Seletor de período recolhível (slider com handles + date inputs sincronizados) para ajuste fino sem recarregar dados
  • Controles min/máx por eixo Y
  • Linhas de referência horizontais customizáveis (outorga, alerta, etc.)
  • Variáveis:
  • Base horária — Y1: Vazão Afluente, Defluente, Turbinada, Vertida; Y2: Nível Montante (m), Volume Útil (%)
  • Base diária — Y1: as 4 acima + Vazão Natural; Y2: Nível Montante (m), Volume Útil (%)
  • Volume Útil (%) disponível no eixo Y2 apenas para usinas do tipo RCU e ITAIPU; demais usinas exibem somente Nível (m)

2. Histórico Dia/Mês · dia_historico.py

Análise comparativa de um mesmo dia/mês ao longo de um intervalo de anos: gráfico de colunas + rankings dos maiores e menores valores.

  • Entrada: usina, intervalo de anos (2000+), dia/mês, variável (Nível ou Volume Útil)
  • Gráfico de barras com rótulos de valor no topo (formato BR), uma barra por ano
  • Eixo Y: zero-anchored para Volume Útil (%); escala livre para Nível (m)
  • Linhas de referência horizontais customizáveis sobrepostas ao gráfico de barras
  • Lógica especial para 29/02: em anos não-bissextos, usa 28/02 e marca essas barras em azul-claro com aviso explicativo
  • Ranking com Top N configurável em duas tabelas lado a lado (maiores / menores). Ano vigente destacado em âmbar quando está no range
  • Carregamento inteligente: dados são baixados uma vez para todas as usinas do período. Mudança de usina ou variável atualiza render instantaneamente; só ano e dia/mês exigem novo carregamento

3. Projeção por Analogia · projecao_analogia.py

Projeção do restante do ciclo (civil ou hidrológico) usando um ou mais anos históricos análogos, com offset de continuidade no ponto de emenda.

  • Entrada: usina, horizonte temporal (ano civil jan–dez ou hidrológico out–set), variável (Nível ou Volume Útil)
  • Ciclo hidrológico: identificado pelo ano de encerramento (ex: "2024–2025" termina em set/2025)
  • Método de projeção: a partir do último dia com dado real, os valores restantes são substituídos pelos do ano análogo, com um offset constante calculado no ponto de emenda para eliminar saltos
  • Múltiplos análogos: seleção via multiselect; cada análogo recebe uma cor distinta no gráfico; botão ↺ Reset volta ao padrão
  • Ranking de ciclos: tabelas dos 10 piores e 10 melhores ciclos históricos por média de Vazão Natural, com destaque em amarelo para os análogos selecionados
  • Linhas de referência horizontais customizáveis sobrepostas ao gráfico
  • Exportação CSV da série resultante (dados reais + projeção), compatível com Excel BR

4. Permanência Mensal · curva_permanencia_mensal.py

Curva de permanência de vazões naturais médias mensais para qualquer usina do SIN, com base na série histórica 1931–2024 do ONS e extensão automática para o ano corrente via base diária.

  • Entrada: usina (inicia em branco), tipo de ano (civil jan–dez ou hidrológico out–set) e um ou mais anos/ciclos de destaque via multiselect com botão ↺ de reset ao ano/ciclo vigente
  • Ciclo hidrológico: mesma convenção do módulo Projeção por Analogia — ciclo Y termina em set/Y (ex: "2024–2025" = out/2024 → set/2025). Eixo X reordenado para Out→Set, e cada ciclo combina Out/Nov/Dez do ano calendário Y-1 com Jan–Set do ano Y
  • Estatísticas mensais calculadas sobre a série completa do arquivo XLS (série invariante 1931–2024):
  • Máxima histórica, Permanência de 10% (P10), Média histórica, Permanência de 90% (P90) e Mínima histórica
  • P10 = valor excedido em 10% do tempo (alta); P90 = valor excedido em 90% do tempo (baixa)
  • Gráfico: cinco linhas contínuas de 3 px com cores distintas; anos/ciclos de destaque em linhas com marcadores (símbolo único: círculo, quadrado, triângulo, diamante, etc.)
  • Cores dos destaques: ano/ciclo vigente sempre preto; se apenas um selecionado, também preto; demais recebem cores da paleta em sequência
  • Anos/ciclos de destaque: série do XLS (1931–2024) ou médias mensais da base DI para anos além do XLS (2025+); em modo hidrológico, o pré-fetch DI considera os dois anos calendário que compõem o ciclo. Carregamento em paralelo via ThreadPoolExecutor
  • Troca de ciclo (civil ↔ hidrológico): reseta a seleção e força remount do multiselect (mesmo padrão do módulo de Analogia)
  • Tabela: pivotada — meses nas colunas (na ordem do ciclo escolhido), métricas nas linhas; anos/ciclos de destaque aparecem abaixo das métricas em ordem cronológica
  • Arquivo de dados: data/vazoes_mensais.xls — série de Vazões Médias Mensais do ONS (versionado no repo)
  • Mapeamento de usinas (usinas_map.py): normalização automática de nomes (strip de acentos, pontuação) + 43 entradas manuais para divergências de nomenclatura entre a base DI/HO e o XLS histórico
  • Média parcial do ciclo/ano vigente: quando o ciclo vigente está nos destaques, exibe a média acumulada dos meses já encerrados (ex: janeiro de 2026 a maio de 2026 (parcial até o dia 17): 2.304,5 m³/s)
  • Ranking — Média da Vazão Natural Média Mensal: tabelas dos N piores e N melhores anos/ciclos da série XLS por média anual; slider configurável de posições (1 a N total); ciclos/anos selecionados no multiselect aparecem destacados em amarelo; exclui o ciclo vigente (incompleto)
  • Exportação CSV das estatísticas e séries de destaque, compatível com Excel BR

5. Comparador de Ciclos · comparador_ciclos.py

Sobreposição da evolução diária de uma variável para múltiplos anos ou ciclos hidrológicos em um único gráfico, permitindo comparação visual da trajetória de cada período.

  • Entrada: usina, tipo de ciclo (civil jan–dez ou hidrológico out–set), variável, anos/ciclos a comparar (multiselect com botão ↺ Reset)
  • Variáveis: Nível Montante (m), Volume Útil (%) para usinas RCU/Itaipu, Vazão Natural, Afluente, Defluente, Turbinada, Vertida e Transferida (m³/s) — base DI desde 2000
  • Gráfico: todas as séries com eixo X em formato DD/MM referenciado a um ano fixo (civil → 2000; hidrológico → 1999/2000) para sobreposição precisa; ciclo vigente sempre em preto
  • Controle de período (eixo X): slider + date inputs sincronizados para exibir subperíodos dentro do ciclo
  • Linhas de referência horizontais customizáveis (nome + valor); até 6 linhas, cores cíclicas, edição inline
  • Ajuste do eixo Y: slider + inputs com min/máx configuráveis; Nível com escala livre, demais variáveis com zero-anchored
  • Aparência: toggle com 4 controles de tamanho de fonte (ticks, labels, legenda, título)
  • Exportação PNG via modebar, com nome contextual contendo usina, ciclo e variável

6. Séries de Dados · exportador_ho.py

Filtra e exporta séries horárias (HO) e diárias (DI) do ONS para CSV.

  • Bases: Horária (desde jan/2010, parquets mensais) ou Diária (desde jan/2000, parquets anuais)
  • Entrada: uma ou mais usinas (multiselect com botões Todas/Nenhuma), período via seletores de data, separador e opção de BOM UTF-8
  • Download paralelo dos arquivos necessários via ThreadPoolExecutor
  • Filtros aplicados: período exato e usinas selecionadas; dados ordenados por usina e instante
  • Formato de saída: CSV com todas as colunas do parquet original; decimal vírgula automático quando separador é ; com BOM (formato PT-BR para Excel)
  • Pré-visualização das primeiras 500 linhas antes do download

Funcionalidades compartilhadas

  • Seleção dinâmica de usinas carregada do arquivo mais recente disponível, com fallback automático
  • Linhas de referência: presente nos módulos 1, 2, 3 e 5 — nome + valor configuráveis, até 6 cores cíclicas, edição inline, invalidação automática ao trocar usina ou variável
  • Exportação:
  • CSV compatível com Excel BR (separador ;, decimal ,, BOM UTF-8, datas pt-BR)
  • PNG via barra de ferramentas do Plotly (client-side, com anotação da fonte)
  • Performance:
  • Dados servidos do Cloudflare R2 (cache intermediário) — fallback automático para o S3 do ONS se necessário
  • Download paralelo de parquets via ThreadPoolExecutor
  • Cache via @st.cache_data — trocar parâmetros leves é instantâneo
  • Cache-busting automático para dados do período corrente (15 min para HO, 1 hora para DI)
  • Leitura seletiva de colunas com fallback de schema (parquets antigos sem todas as colunas)

Fluxo de dados

cron-job.org (HO + DI) ──► repository_dispatch ──┐
                                                  ├──► GitHub Actions ──► ONS (S3 público) ──► Cloudflare R2
GitHub Actions cron (histórico semanal) ──────────┘                                                  │
                                                                                              Streamlit App
                                                                                              (R2-first, fallback ONS)

Os dados são espelhados do ONS para um bucket Cloudflare R2 por jobs independentes:

GatilhoFrequênciaO que sincronizaWorkflow
cron-job.org → repository_dispatchA cada 15 min (5 min após cada ciclo ONS)HO do mês correnteingest_ho.yml
cron-job.org → repository_dispatch3× ao dia (9h30, 14h30, 17h30 BRT)DI do ano correnteingest_ons.yml
0 7 * * 0 (GitHub Actions)Domingo 04h BRTTodo o histórico (HO desde jan/2010, DI desde 2000)ingest_ons.yml

HO e DI usam repository_dispatch disparado por um serviço externo (cron-job.org) porque o GitHub Actions não garante crons em repositórios gratuitos — disparos podem atrasar mais de 1 hora. O histórico semanal permanece no GitHub Actions pois atraso de 1h numa tarefa semanal é irrelevante.

O app lê sempre do R2 primeiro; se o arquivo não estiver disponível, cai silenciosamente no S3 público do ONS. Isso protege o portal de dados abertos do ONS contra thundering herd em cache misses simultâneos.

Armazenamento no R2: ~320 MB (222 parquets), plano gratuito (10 GB).

Portal oficial ONS: https://dados.ons.org.br/

Stack

  • Streamlit ≥ 1.36 — interface web (requer st.navigation)
  • Pandas ≥ 2.2 — manipulação de dados
  • PyArrow ≥ 15 — leitura de Parquet
  • Plotly ≥ 5.22 — gráficos interativos
  • Boto3 ≥ 1.34 — acesso ao Cloudflare R2 (API compatível com S3)
  • xlrd ≥ 1.2 — leitura do arquivo XLS histórico de vazões mensais

Como rodar localmente

Requisitos: Python 3.11+.

bash
git clone https://github.com/dlpena/ons-hidro-explorer.git
cd ons-hidro-explorer

python -m venv venv
# Windows
.\venv\Scripts\activate
# Linux/macOS
source venv/bin/activate

pip install -r requirements.txt

O app funciona sem credenciais R2 — nesse caso lê direto do S3 do ONS (comportamento original). Para usar o cache R2, crie .streamlit/secrets.toml:

toml
[r2]
account_id        = "seu_account_id"
access_key_id     = "sua_access_key"
secret_access_key = "sua_secret_key"
bucket            = "ons-data-lake"
bash
streamlit run app.py

A aplicação abre em http://localhost:8501 na landing page, com sidebar para navegar entre os módulos.

Estrutura do projeto

ons-hidro-explorer/
├── app.py                       # entry point: page_config, CSS, st.navigation, landing
├── graficos_operativos.py       # módulo 1 — séries temporais operativas
├── dia_historico.py             # módulo 2 — comparativo histórico dia/mês
├── projecao_analogia.py         # módulo 3 — projeção por analogia hidrológica
├── curva_permanencia_mensal.py  # módulo 4 — permanência de vazões mensais
├── comparador_ciclos.py         # módulo 5 — comparador de anos/ciclos hidrológicos
├── exportador_ho.py             # módulo 6 — séries de dados (horária + diária)
├── usinas_map.py                # mapeamento de nomes ONS ↔ XLS histórico (auto + 43 manuais)
├── utils.py                     # fetch_parquet compartilhado (R2-first + fallback ONS)
├── ingest_ons.py                # script de ingestão ONS → R2 (usado pelo GitHub Actions)
├── requirements.txt
├── data/
│   └── vazoes_mensais.xls       # série histórica ONS 1931–2024
├── .streamlit/
│   ├── config.toml              # tema (light, azul-marinho #1A237E)
│   └── secrets.toml             # credenciais R2 — não versionado
├── .github/
│   └── workflows/
│       ├── ingest_ho.yml        # HO: repository_dispatch (cron-job.org, 15 em 15 min)
│       └── ingest_ons.yml       # DI (cron-job.org, 3×/dia) + histórico completo (cron semanal)
├── .gitignore
└── README.md

page_config, GA4 e CSS são definidos uma única vez em app.py. Os arquivos dos módulos não chamam st.set_page_config — são carregados via st.navigation. A função fetch_parquet em utils.py é o único ponto de acesso aos dados, garantindo cache compartilhado entre módulos e leitura R2-first com fallback automático para o ONS.

Deploy

Otimizado para deploy no Streamlit Community Cloud:

  1. 1.Faça fork ou clone do repositório no seu GitHub
  2. 2.Acesse https://share.streamlit.io e conecte com o GitHub
  3. 3.Aponte para app.py na branch main
  4. 4.Em App Settings → Secrets, adicione as credenciais R2 (opcional — sem elas o app lê direto do ONS)
  5. 5.Deploy automático a cada push

Autor

Diego Liz Pena — diegoicc@gmail.com

Licença

MIT