Utilizando a biblioteca HydroBR — Parte 1

Trabalhando com dados da Agência Nacional de Águas

Wallisson Carvalho
8 min readMar 4, 2021
Rede Hidrometeorológica Nacional
Rede Hidrometerológica Nacional

Contextualizando

A obtenção manual e tratamento de dados de monitoramento hidrológico e meteorológico no Brasil pode ser um trabalho exaustivo, principalmente se a área de interesse é bem monitorada e possui muitas estações de monitoramento.

Pensando nisso, há algum tempo eu publiquei a biblioteca HydroBR, que teve como objetivo principal automatizar o download de dados de estações hidrometeorológicas situadas no Brasil. O que foi possível devido à conexão direta, por APIs, com os bancos de dados da Agência Nacional de Águas (ANA) e do Instituto Nacional de Meteorologia (INMET).

No momento em que estou escrevendo (04/03/2021), a biblioteca já conta com 1.594 downloads, mas muita gente ainda não sabe como aproveitar todas as funcionalidades que ela dispõe. Por isso, irei escrever uma série de artigos ensinando o passo a passo de como utilizá-la.

Nesse primeiro artigo, iremos focar apenas nos dados da ANA. Aqui seguiremos o seguinte roteiro:

  1. Seleção de estações a partir de um shapefile de bacia hidrográfica ou de uma área de interesse;
  2. Download dos dados das estações selecionadas;
  3. Visualização temporal da disponbilidade dos dados das estações baixadas;
  4. Exportação dos dados.

Vamos começar?!

1. Selecionando as estações

Para selecionarmos as estações precisaremos incialmente de um shapefile da área de interesse. No caso dessa aplicação, utilizarei a bacia hidrográfica do rio Doce. Mas você pode utilizar o shapefile de qualquer outra área, desde que esteja localizada no Brasil.

Inicialmente, além da HydroBR, responsável pelas funções de obtenção e visualização dos dados, usaremos as bibliotecas GeoPandas e Shapely, que serão responsáveis pelo georreferenciamento dos dados.

import hydrobr
import geopandas as gpd
from shapely.geometry import Point

Uma vez importadas as bibliotecas iremos:

  1. Abrir o shapefile da área de interesse utilizando o GeoPandas;
  2. Obter o inventário das estações da ANA;
  3. Georreferenciar o inventário;
  4. Filtrar as estações utilizando o shapefile da área.

Para abrirmos o shapefile iremos utilizar a função .read_file do GeoPandas, e para conferirmos se abrimos o shapefile correto podemos utilizar a função .plot . Aqui, vamos combinar que o seu shapefile estará com o sistema de coordenadas latlong WGS-84, ok?!

area = gpd.read_file(r'shapefiles/bacia_doce.shp')
area.plot()

Agora iremos obter o inventário das estações da ANA. Para isso a biblioteca HydroBR conta com duas funções específicas:

  • hydrobr.get_data.ANA.list_prec_stations - Para obter a lista de estações de precipitação
  • hydrobr.get_data.ANA.list_flow_stations - Para obter a lista de estações de vazão/nível

Daqui em diante, seguiremos utilizando apenas as estações de fluviométrias. No entanto, os métodos seriam os mesmos caso você tenha interesse nos dados das estações pluviométricas (salvo nos casos em que irei destacar).

Ao obter o inventário, poderemos utilizar a função .info para visualizarmos um resumo das suas informações.

lista_flu = hydrobr.get_data.ANA.list_flow_stations()
lista_flu.info()

O que nos retorna:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3771 entries, 0 to 3770
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Name 3771 non-null object
1 Code 3771 non-null object
2 Type 3771 non-null int64
3 DrainageArea 3707 non-null float64
4 SubBasin 3771 non-null int64
5 City 3770 non-null object
6 State 3771 non-null object
7 Responsible 3771 non-null object
8 Latitude 3771 non-null float64
9 Longitude 3771 non-null float64
10 StartDate 3771 non-null object
11 EndDate 3771 non-null object
12 NYD 3771 non-null int64
13 MD 3771 non-null float64
14 N_YWOMD 3771 non-null int64
15 YWMD 3771 non-null float64
dtypes: float64(5), int64(4), object(7)
memory usage: 471.5+ KB

Por padrão, as duas funções obtêm um inventário com campos que caracterizam algumas informações sobre as estações. Essas informações são apenas um guia que correspondem ao momento em que eu realizei a caracterização do inventário, sendo atualizadas a cada 6 meses. São elas:

  • Data da primeira medição (Coluna 10 — StartDate)
  • Data da última medição (Coluna 11 — EndDate)
  • Número de anos com dados (Coluna 12 — NYD)
  • Porcentagem de falhas entre a primeira e última medição (Coluna 13 — MD)
  • Número de anos sem nenhuma falha (Coluna 14 — N_YWOMD)
  • Porcentagem de anos com falhas(Coluna 15 — YWMD)

Agora iremos georreferenciar as informações do inventário armazenadas na variável lista_flu.

Para isso iremos criar uma geometria de pontos utilizando as informações de Latitude e Longitude com o auxílio da função Point() que importamos anteriormente. Aqui utilizaremos um recurso do python chamado list comprehension. Se você é iniciante no python não se preocupe, é só executar este mesmo código para a sua área.

Em seguida definiremos o sistema de coordenadas (Combinamos o WGS-84, lembra?!), e por fim, transformaremos o nosso inventário em um GeoDataFrame, que é uma estrutura tabular que contém geometrias (um GeoDataFrame assemelha-se à um shapefile)

# Criando uma lista de geometrias no formato de ponto
pontos = [Point(x) for x in zip(lista_flu.Longitude,
lista_flu.Latitude)]
# Definindo o sistema de coordenadas
crs={'proj':'latlong','ellps':'WGS84','datum':'WGS84','no_def':True}
# Criando o geodataframe
lista_flu_geo = gpd.GeoDataFrame(lista_flu, geometry=pontos,crs=crs)

Se utilizarmos a função .plot na variável lista_flu_geo, poderemos visualizar as estações fluviométricas de todo o país.

lista_flu_geo.plot()

Agora que temos a área de interesse e o inventário de estações georreferenciados, podemos filtrar apenas as estações que estão inseridas na área, utilizando a operação espacial .within, que identifica se uma geometria de ponto está localizada dentro de uma geometria poligonal.

# Selecionando os indices das estações que estão dentro da bacia
indices = lista_flu_geo.geometry.within(area.geometry[0])
# Filtrando as estações
lista_selecionada = lista_flu_geo[indices]
#Obtendo as informações
lista_selecionada.info()

Percebam que agora temos 152 linhas na nossa variável lista_selecionada (i.e., 152 estações) enquanto o inventário original continha 3.771 estações. As 152 linhas correspondem as estações que estão inseridas na nossa área de interesse (i.e., bacia hidrográfica do rio Doce).

Int64Index: 152 entries, 1521 to 1686
Data columns (total 17 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Name 152 non-null object
1 Code 152 non-null object
2 Type 152 non-null int64
3 DrainageArea 151 non-null float64
4 SubBasin 152 non-null int64
5 City 152 non-null object
6 State 152 non-null object
7 Responsible 152 non-null object
8 Latitude 152 non-null float64
9 Longitude 152 non-null float64
10 StartDate 152 non-null object
11 EndDate 152 non-null object
12 NYD 152 non-null int64
13 MD 152 non-null float64
14 N_YWOMD 152 non-null int64
15 YWMD 152 non-null float64
16 geometry 152 non-null geometry
dtypes: float64(5), geometry(1), int64(4), object(7)
memory usage: 21.4+ KB

Podemos visualizar a distribuição espacial das estações plotando a nossa lista_selecionada utilizando como base do mapa a variável area.

base = area.plot(color='white', edgecolor='black')
lista_selecionada.plot(ax=base,marker='o',color='red')

2. Fazendo o download dos dados das estações selecionadas.

Neste ponto, já obtivemos o inventário das estações fluviométria de todo o país e filtramos apenas as estações que estão inseridas na nossa área de interesse, na variável lista_selecionada. Agora iremos fazer o download dos dados diários a partir dos códigos dessas estações.

Neste caso a biblioteca HydroBR conta com três funções específicas para o download dos dados diários das estações de monitoramento da ANA.

  • hydrobr.get_data.ANA.prec_data - Para obter os dados de precipitação a partir de uma lista de códigos de estações de precipitação;
  • hydrobr.get_data.ANA.flow_data - Para obter os dados de vazão a partir de uma lista de códigos de estações de vazão/nível;
  • hydrobr.get_data.ANA.stage_data - Para obter os dados de nível a partir de uma lista de códigos de estações de vazão/nível;

Como nossa lista refere-se apenas as estações de vazão/nível, iremos obter os dados de vazão. Para isso iremos transformar a coluna Code, que armazena os códigos das estações, em uma lista do python.

# Selecionando os códigos das estações
codigos = lista_selecionada.Code.to_list()
# Baixando as estações
dados_flu = hydrobr.get_data.ANA.flow_data(codigos)
# Informações
dados_flu.info()

Agora, nos já obtivemos os dados referentes à 152 estações fluviométrias. E levamos apenas 8min e 39s! (esse tempo varia de acordo com a velocidade da conexão). Quanto tempo levaríamos para obter os dados dessas mesmas 152 estações de forma manual? Eu chuto que seria muito mais que esses 8 minutos e 39 segundos!

3. Visualizando a disponibilidade temporal dos dados

Os dados das estações selecionadas foram armazenados na variável dados_flu, e vimos através da função .info que temos 152 colunas com códigos que variam entre 5570002 até 5698400, numa frequência diária entre o dia 01/12/1925 e 30/09/2020. No entanto, sabemos que nem todas as estações possuem registros em todos esses dias.

Uma ótima forma de visualizar temporalmente a disponibilidade desses dados é utilizando o gráfico de Gantt. A função hydrobr.Plot pode nos auxiliar nisso, nos fornecendo uma fig no formato plotly, o que nos leva a necessidade de usar a biblioteca plotly.

Importaremos a função plot, que salva o nosso gráfico num arquivo .html. Que é um formato iterativo.

from plotly.offline import plot
gantt_fig = hydrobr.Plot.gantt(dados_flu)
#Atualizando o layout da figura
gantt_fig.update_layout(
autosize=False,
width=1800, #Determina a largura da figura em pixels
height=1500, #Determina a altura da figura em pixels
xaxis_title = 'Ano', #Título do eixo
yaxis_title = 'Código da Estação', #Título do eixo y.
font=dict(family="Courier New, monospace", size=12))
#Plotando
plot(gantt_fig,filename='Gantt - Flu' + '.html')

Uma versão resumida do gráfico pode ser vista a seguir:

O gráfico completo no formato iterativo você pode visualizar aqui.

4. Exportando os Dados

A exportação dos dados conta com as opções de exportação da biblioteca Pandas. Aqui iremos exportar os dados para o formato .csv, com separador ‘;’.

# Selecionando os códigos das estações
dados_flu.to_csv('dados_fluviometricos_doce.csv', sep=';')

Conclusão

Neste artigo aprendemos a utilizar a biblioteca HydroBR com o foco nos dados da Agência Nacional de Água, com isso fomos capaz de realizar os seguintes procedimentos:

  • Selecionar estações a partir de um shapefile;
  • Realizar o download dos dados das estações a partir de uma lista de códigos;
  • Visualizar a disponibilidade temporal dos dados;
  • Exportar os dados para o formato csv.

O link para o projeto no github é esse aqui. Nos próximos artigos trarei mais funcionalidades da biblioteca.

--

--

Wallisson Carvalho

Environmental and Sanitation Engineer, Hydrologist and Data Scientist