Mochileiro T.I
Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

Folium: uma biblioteca Python para mapas interativos

À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!