Às vezes nos deparamos com situações onde existe a necessidade de um mapa para mostrar a localização de algum dado. Python nos oferece através da biblioteca Folium uma excelente opção para esse propósito.
Esta é uma biblioteca bem popular capaz de criar mapas interativos, cujo foco é gerar visualizações geográficas simples e rápidas usando a poderosa biblioteca Javascript Leaflet.js
O Folium fornece suporte a diversos tipos de mapas com diferentes camadas e estilos, como por exemplo mapas de tiles padrão, satélite e híbridos.
Além disso ele facilita a adição de vários elementos ao mapa, como marcadores, linhas e polígonos, heatmaps (densidade de pontos), mapas de Cloropleth (variação de cor) e clusters (agrupamento de marcadores).
A biblioteca suporta a integração com os formatos de dados geoespaciais GeoJSON e TopoJSON, permitindo portanto fácil manipulação e visualização de tais dados.
Por fim o Folium permite exportar mapas para HTML, facilitando dessa maneira o compartilhamento ou incorporação a deles em páginas web.
Folium e Leaflet.js
Em linhas gerais podemos dizer que o Folium faz uma espécie de tradução do código Python para Javascript, de modo que seja capaz gerar mapas utilizando a biblioteca Leaflet.js.
Ou seja, o Folium é uma biblioteca Python que serve como uma interface para o Leaflet.js, dispensando assim conhecimento ou uso direto de Javascript.
Ele encapsula as funcionalidades do Leaflet.js em funções e classes Python, facilitando dessa maneira a geração de mapas dentro do Jupyter Notebook, aplicações Web, etc.
Por exemplo, usando apenas Leaflet.js, criariamos um mapa assim:
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
Já no Folium, seu equivalente seria:
import folium
mapa = folium.Map(location=[51.505, -0.09], zoom_start=13)
Embora o Folium não suporte todos os plugins e customizações avançadas do Leaflet.js, ele cobre a maioria das necessidades comuns, tornando o trabalho com mapas muito mais acessível para quem trabalha com Python.
Portanto, caso não encontre algum recurso no Folium, tenha em mente que existe a possibilidade resolver seu problema diretamente com o Leaflet.js.
Criando um mapa interativo com o Folium
Antes de tudo precisamos instalar o Folium: (caso queira, crie um ambiente virtual antes)
python -m venv venv (opcional)
pip install folium
A utilização do folium é bastante simples e intuitiva. Assim sendo, criar um mapa é muito fácil:
import folium
# Cria o mapa e o posiciona nas coordenadas informadas
mapa = folium.Map([-23.59507, -46.63423], zoom_start=11)
# Para salvar o mapa em HTML
mapa.save("mapa.html")
O código acima cria um mapa a partir da coordenada de latitude -23.59507 e longitude -46.63423 com zoom em 11. (quanto maior o número, maior o zoom)
Você pode interagir com ele arrastando-o, aumentando e diminuindo o zoom, etc, igual ao Google Maps, experimente!
Adicionando marcadores ao Mapa
Por vezes precisamos apontar alguma localidade em um mapa, portanto utilizamos o conceito de marcadores, que nada mais são do que pontos com algum ícone desenhado sobre ele.
Nesse sentido, utilizaremos uma pequena base de dados contendo a localização de alguns aeroportos brasileiros:
aeroportos = [
{"nome": "Aeroporto de Guarulhos", "lat": -23.4356, "lon": -46.4731},
{"nome": "Aeroporto de Brasília", "lat": -15.8696, "lon": -47.9208},
{"nome": "Aeroporto do Galeão", "lat": -22.8090, "lon": -43.2506},
{"nome": "Aeroporto de Salvador", "lat": -12.9086, "lon": -38.3225},
{"nome": "Aeroporto de Porto Alegre", "lat": -29.9939, "lon": -51.1711}
]
Em seguida, vamos usar esses dados para gerar um mapa interativo com marcadores para cada aeroporto:
import folium
# Criando um mapa centrado no Brasil
mapa = folium.Map(location=[-15.7801, -47.9292], zoom_start=5)
# Lista de aeroportos mencionada acima
aeroportos = [...]
# Adicionando marcadores ao mapa
for aeroporto in aeroportos:
folium.Marker(
location=[aeroporto["lat"], aeroporto["lon"]],
popup=aeroporto["nome"],
icon=folium.Icon(color="blue", icon="plane", prefix="fa")
).add_to(mapa)
# Salvando o mapa em um arquivo HTML
mapa.save("mapa_aeroportos.html")
Resultado:
Adicionando camadas ao Mapa
Além disso, há ainda a possibilidade de adicionar camadas ao mapa, ou “Tiles” adicionando o código abaixo ao exemplo anterior:
# Tile CartoDB Positron
folium.TileLayer(
tiles="https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
attr='© <a href="https://carto.com/">CARTO</a>',
name="CartoDB Positron"
).add_to(mapa)
# Tile Esri Satellite
folium.TileLayer( tiles="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
attr="Tiles © Esri",
name="Esri Satellite"
).add_to(mapa)
# Adicionando o controle de camadas ao mapa
folium.LayerControl().add_to(mapa)
Conforme podemos notar, o código acima adiciona as camadas CartoDB Positron e Esri Satellite, ambas encontradas na lista de camadas disponível no leaflet.io
Uma vez que o Leaflet.io fornece apenas o código javascript, obter os parâmetros “tiles”, “attr” e “name” pode não ser muito intuitivo para algumas pessoas.
No entanto, não é tão difícil assim… observe o seguinte trecho javascript disponível no site deles:
var CartoDB_Positron = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
});
O atributo “tiles” vem do início de L.tileLayer, o atributo “attr” vem após a palavra “contributors” e por fim “name” é o nome da variável javascript.
Dessa forma, segundo podemos notar, criamos um mapa com três camadas:
Note que agora há um ícone no canto superior direito, habilitando a troca das camadas do mapa (tiles).
Desenhando linhas
Certamente em algumas situações existe a necessidade de representar rotas, fronteiras ou qualquer outro dado espacial que seja conectado em um mapa.
Assim sendo o Folium oferece um recurso chamado Polyline (ou Polilinha) que é uma sequência de segmentos de linha conectados por coordenadas geográficas, ou seja, latitudes e longitudes.
Uma lista Python pode representar um conjunto de coordenadas e além disso, quando criada, pode-se personalizar a polyline com diferentes cores, opacidade e estilos.
Com o intuito de exemplificar esse conceito, vamos desenhar uma rota hipotética entre as cidade de São Paulo, Campinas, Limeira e Rio de Janeiro:
import folium
# Criando um mapa centrado no Brasil
mapa = folium.Map(location=[-15.7801, -47.9292], zoom_start=5)
# Lista de pontos intermediários na rota
rota_completa = [
[-23.5505, -46.6333], # São Paulo
[-22.9035, -47.0574], # Campinas
[-22.7595, -47.4176], # Limeira
[-22.9083, -43.1964] # Rio de Janeiro
]
# Adicionando a rota ao mapa
folium.PolyLine(
rota_completa, color="red", weight=4, dash_array="5, 5" # Linha tracejada
).add_to(mapa)
Como resultado, o Folium desenha o mapa com nossa rota:
Agrupando marcadores
Em algumas ocasiões nos deparamos com mapas cujos marcadores encontram-se muito próximos uns aos outros e portanto, acabam poluindo sua visualização.
Em várias dessas situações é possível dividir os marcadores em grupos de tal forma que possamos selecioná-los individualmente e dessa maneira, melhorar a visualização do mapa.
Apesar de poucos marcadores, nosso exemplo dos aeroportos é capaz de demonstrar a funcionalidade de agrupamento no Folium:
import folium
# Criando um mapa centrado no Brasil
mapa = folium.Map(location=[-15.7801, -47.9292], zoom_start=5)
# Primeiro grupo (vermelho)
grupo1 = folium.FeatureGroup("primeiro grupo").add_to(mapa)
folium.Marker((aeroportos[0]["lat"],aeroportos[0]["lon"]), icon=folium.Icon("red")).add_to(grupo1)
folium.Marker((aeroportos[1]["lat"],aeroportos[1]["lon"]), icon=folium.Icon("red")).add_to(grupo1)
folium.Marker((aeroportos[2]["lat"],aeroportos[2]["lon"]), icon=folium.Icon("red")).add_to(grupo1)
# Segundo grupo (verde)
grupo2 = folium.FeatureGroup("segundo grupo").add_to(mapa)
folium.Marker((aeroportos[3]["lat"],aeroportos[3]["lon"]), icon=folium.Icon("green")).add_to(grupo2)
folium.Marker((aeroportos[4]["lat"],aeroportos[4]["lon"]), icon=folium.Icon("green")).add_to(grupo2)
folium.LayerControl().add_to(mapa)
Como resultado temos o mapa com três aeroportos no grupo vermelho e os outros dois no grupo verde. Além disso podemos selecionar qual grupo queremos visualizar através do ícone no canto superior direito:
Arquivos GeoJSON
Com o intuito de representar dados aeroespaciais, o formato GeoJSON foi criado em 2008 por especialistas em Geoinformação e Web GIS.
O GeoJSON pode representar conjuntos de pontos (marcadores), linhas (rotas e caminhos) e polígonos (áreas e regiões) de forma padronizada e portanto fácil de compreender.
Por se tratar de um formato amplamente utilizado em sistemas de informação geográfica, O Folium bem como o Leaflet.js tem compatibilidade com o mesmo.
Assim sendo, veja o exemplo abaixo que demarca todas as fronteiras territoriais do mundo:
import requests
# Criando um mapa centrado no Brasil
mapa = folium.Map(location=[-15.7801, -47.9292], zoom_start=5)
geojson_data = requests.get(
"https://raw.githubusercontent.com/python-visualization/folium-example-data/main/world_countries.json"
).json()
folium.GeoJson(geojson_data, name="Fronteiras").add_to(mapa)
folium.LayerControl().add_to(mapa)
Como resultado obtemos o mapa contendo as fronteiras:
Conclusão
Conforme demonstrado através de exemplos ao longo deste artigo, concluímos que apesar de adicionar uma camada extra em Python para criar mapas, O Folium ainda é uma excelente opção.
Isso se deve ao fato de que para a maioria dos casos onde o desenvolvedor não sabe Javascript, o conhecimento apenas em Python já resolve o problema.
Além disso, a biblioteca dá a possibilidade de integrar o poder do Leaflet.js com projetos Python de forma muito simples, poupando muito tempo de desenvolvimento.
Em casos mais complexos, onde o Folium não tem recursos, ainda é possível adicionar código Javascript puro de modo que o programa seja capaz de extrair todas as funcionalidades nativas do Leaflet.js.
Em resumo, trata-se de uma excelente biblioteca para criação de mapas interativos e deve ser considerada quando surgir a necessidade dessa demanda em seu projeto.
Espero ter ajudado!
Até a próxima!