Frequentemente um mapa colorido é o mais adequado para comunicar alguma informação que pode ser agregada geograficamente. Neste texto eu descrevo o passo-a-passo para criar um mapa coroplético básico em Python usando os pacotes matplotlib e o geopandas. Além desses dois pacotes, vou utilizar o geobr desenvolvido pelo IPEA para baixar dados geoespaciais do Brasil para plotar os mapas.
Instalando os pacotes necessários:
pip install matplotlib geopandas geobr
Pacotes instalados sem erros, basta importá-los no script Python.
Dica: use o Google Colab caso tenha problemas ao tentar instalar o geopandas.
import pandas as pd
import geopandas as gpd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import geob
Primeiro é preciso obter os dados que desejamos visualizar através de mapas.
Para este exemplo eu vou utilizar os dados de área plantada de milho por unidade da federação publicados pelo IBGE.
No código a seguir os dados são obtidos através do Sistema IBGE de Recuperação Automática (SIDRA) pela URL que contém os parâmetros para a API da consulta. Essa URL pode ser obtida através do site do SIDRA (tabela 839).
Obtendo os dados
Podemos carregar a tabela apenas passando a URL ao método read_csv do Pandas.
A URL baixa um arquivo CSV com algumas linhas que podemos ignorar (metadados). Para isso utilizamos os argumentos skiprows
e skipfooter
.
url = "https://sidra.ibge.gov.br/geratabela?format=us.csv&name=tabela839.csv&terr=NC&rank=-&query=t/839/n3/all/v/109/p/last%201/c81/31693/l/,v,p%2Bt%2Bc81"
d = pd.read_csv(
url,
skiprows=2, # Ignora as duas primeiras linhas do arquivo
skipfooter=16, # Ignora as últimas 16 linhas do arquivo
)
d.head()
ANO | CÓD. | UNIDADE DA FEDERAÇÃO | PRODUTO DAS LAVOURAS TEMPORÁRIAS | ÁREA PLANTADA (HECTARES) | |
---|---|---|---|---|---|
0 | 2018 | 11 | Rondônia | Total | 185413 |
1 | 2018 | 12 | Acre | Total | 30140 |
2 | 2018 | 13 | Amazonas | Total | 3612 |
3 | 2018 | 14 | Roraima | Total | 9155 |
4 | 2018 | 15 | Pará | Total | 226708 |
Das colunas presentes na tabela precisamos apenas de duas: o código da unidade de federação (Cód.
) e a coluna com as áreas plantadas (Área plantada (Hectares)
). Para fazermos o merge dessa tabela com o dataframe com as geometrias obtidos com o geobr
vamos renomear a coluna Cód.
.
# Seleciona apenas as colunas de interesse
d = d[["Cód.", "Área plantada (Hectares)"]]
# Renomeia a coluna 'Cód.' para 'code_state' para juntar com a tabela de
# geometria das UFs
d = d.rename(columns={"Cód.": "code_state"})
d.head()
CODE_STATE | ÁREA PLANTADA (HECTARES) | |
---|---|---|
0 | 11 | 185413 |
1 | 12 | 30140 |
2 | 13 | 3612 |
3 | 14 | 9155 |
4 | 15 | 226708 |
Obtendo as geometrias
O pacote geobr
desenvolvido pelo IPEA permite baixar programaticamente dados geoespaciais do Brasil.
Para baixar os contornos dos estados brasileiros usamos o método read_state
.
# Baixa o GeoDataFrame com os estados do Brasil e DF
br_uf = geobr.read_state()
br_uf.head()
CODE_STATE | ABBREV_STATE | NAME_STATE | CODE_REGION | NAME_REGION | GEOMETRY | |
---|---|---|---|---|---|---|
0 | 11.0 | RO | Rondônia | 1.0 | Norte | MULTIPOLYGON (((-63.32721 -7.97672, -62.86662 ... |
1 | 12.0 | AC | Acre | 1.0 | Norte | MULTIPOLYGON (((-73.18253 -7.33550, -72.58477 ... |
2 | 13.0 | AM | Amazonas | 1.0 | Norte | MULTIPOLYGON (((-67.32609 2.02971, -67.31682 2... |
3 | 14.0 | RR | Roraima | 1.0 | Norte | MULTIPOLYGON (((-60.20051 5.26434, -60.19273 5... |
4 | 15.0 | PA | Pará | 1.0 | Norte | MULTIPOLYGON (((-54.95431 2.58369, -54.93542 2... |
Fazendo merge
Com o método merge podemos juntar os dois dataframes através da coluna code_state
. Depois selecionamos apenas as colunas necessárias.
br_uf_d = br_uf.merge(d)
br_uf_d = br_uf_d[["geometry", "Área plantada (Hectares)"]]
br_uf_d.head()
GEOMETRY | ÁREA PLANTADA (HECTARES) | |
---|---|---|
0 | MULTIPOLYGON (((-63.32721 -7.97672, -62.86662 ... | 185413 |
1 | MULTIPOLYGON (((-73.18253 -7.33550, -72.58477 ... | 30140 |
2 | MULTIPOLYGON (((-67.32609 2.02971, -67.31682 2... | 3612 |
3 | MULTIPOLYGON (((-60.20051 5.26434, -60.19273 5... | 9155 |
4 | MULTIPOLYGON (((-54.95431 2.58369, -54.93542 2... | 226708 |
Finalmente plotando o mapa
Criar um mapa estático com geopandas
é bastante simples. Basta dar um plot
passando o nome da coluna que se deseja usar para colorir o mapa.
Para esse mapa eu escolhi Greens
como as cores do mapa veja Colormaps para outras cores).
f, ax = plt.subplots()
f.set_size_inches(16, 16)
br_uf_d.plot(
ax=ax, # Axis de destino do gráfico
column="Área plantada (Hectares)", # Coluna com os valores usados para colorir o mapa
cmap="Greens", # Mapa de cores
edgecolor="black", # Cor dos contornos
linewidth=0.25, # Espessura dos contornos
)
Temos um mapa coroplético básico agora, mas faltam algumas coisas para estar completo. Não temos ideia dos valores que as cores representam, por isso uma escala de cores (colorbar) é imprescindível.
O código a seguir faz o mesmo mapa adicionando uma escala de cores na figura.
f, ax = plt.subplots()
f.set_size_inches(16, 16)
br_uf_d.plot(
ax=ax, # Axis de destino do gráfico
column="Área plantada (Hectares)", # Coluna com os valores usados para colorir o mapa
cmap="Greens", # Mapa de cores
edgecolor="black", # Cor dos contornos
linewidth=0.25, # Espessura dos contornos
)
# Adiciona escala Colorbar (https://stackoverflow.com/a/36080553)
# Cria um Axis usado para fazer o Colorbar
cax = f.add_axes(
[
0.82, # posicao x (entre 0.0 e 1.0)
0.18, # posicao y (entre 0.0 e 1.0)
0.03, # largura x
0.40, # altura y
]
)
sm = plt.cm.ScalarMappable(
cmap="Greens", # Usa o mesmo cmap do mapa
norm=plt.Normalize(
vmin=br_uf_d["Área plantada (Hectares)"].min(), # Valor mínimo
vmax=br_uf_d["Área plantada (Hectares)"].max(), # Valor máximo
),
)
# Põe o Axis com Colorbar na mesma figura do mapa
f.colorbar(sm, cax=cax)
Temos uma escala de cores, mas o formato dos valores não estão como desejados. Além disso, essas bordas com as coordenadas geográficas são desnecessárias e ficam feias para colocar numa publicação.
Aparando as arestas e polindo
Para que o mapa fique digno de uma publicação respeitável vamos fazer alguns ajustes.
Primeiro, vamos arrumar os números da escala da barra de cores. Segundo, um gráfico deve ter um título descritivo. Terceiro, devemos colocar a fonte dos dados. E por último, vamos remover as bordas.
f, ax = plt.subplots()
f.set_size_inches(16, 16)
br_uf_d.plot(
ax=ax, # Axis de destino do gráfico
column="Área plantada (Hectares)", # Coluna com os valores usados para colorir o mapa
cmap="Greens", # Mapa de cores
edgecolor="black", # Cor dos contornos
linewidth=0.25, # Espessura dos contornos
)
# Adiciona escala Colorbar (referência: https://stackoverflow.com/a/36080553)
# Cria um Axis usado para fazer o Colorbar
cax = f.add_axes(
[
0.82, # posicao x (entre 0.0 e 1.0)
0.18, # posicao y (entre 0.0 e 1.0)
0.03, # largura x
0.40, # altura y
]
)
sm = plt.cm.ScalarMappable(
cmap="Greens", # Usa o mesmo cmap do mapa
norm=plt.Normalize(
vmin=br_uf_d["Área plantada (Hectares)"].min(), # Valor mínimo
vmax=br_uf_d["Área plantada (Hectares)"].max(), # Valor máximo
),
)
# Põe o Axis com Colorbar na mesma figura do mapa
f.colorbar(
sm,
cax=cax,
# Formata a escala do Colorbar
format=ticker.FuncFormatter(lambda x, pos: f"{x/1000: >10,.0f} mil ha"),
)
# Adiciona um título ao mapa
ax.set_title(
"Área plantada de Milho por Estado em 2018",
fontdict={"fontsize": 20},
)
# Adiciona a fonte como nota de rodapé
f.text(
0.15, # Posição x
0.20, # Posição y
"Fonte: IBGE (2020)." # Texto
)
ax.axis("off") # Remove os eixos