Colocando pontos num mapa com Folium
Vamos supor que você está trabalhando com dados do mundo real. E nesses dados você tem as latitudes e longitudes de algumas entidades. E ainda mais, você quer colocar essas entidades num mapa e mostrar isso para as suas coleguinhas. Como fazer?
Bem, você tem algumas opções…
- Colocar manualmente pontos no mapa usando o Google Maps, o que é até okay quando você tem 2 ou 3 entidades mas quando isso passa de 10 já fica meio chato né?!
- Usar uma biblioteca/pacote de alguma linguagem de programação que faça isso. Particularmente minha opção favorita 💃🏻
Existem algumas bibliotecas disponíveis para isso, mas hoje vamos falar da Folium.
Folium
O propósito dessa biblioteca é unir o poder de manipulação de dados que Python possui com a força de visualização de mapas da biblioteca JavaScript Leaflet. A ideia aqui é tornar ainda mais fácil a missão de colocar pontos em um mapa.
Cadê o código?
Todo código que eu vou mostrar abaixo ta organizadinho neste diretório no GitHub, nele tem as instruções de preparação do ambiente tanto com docker quanto sem docker.
Instalação
Comece preparando o ambiente:
$ git clone https://github.com/jtemporal/intro-folium.git
$ cd intro-folium/
Com docker
Se você gosta da 🐳 :
$ docker-compose build
Sem docker
Se não é fã da 🐳:
$ pip install -r requirements.txt
$ pip install jupyter
Inciando
Depois disso, ainda no terminal:
Na versão 🐳:
$ docker-compose up jupy
ou sem docker:
$ jupyter notebook
Depois de rodar um dos comandos acima, você verá uma mensagem parecida com a seguinte no seu terminal:
A última linha indica o token de acesso, é só copiá-la e colocar no navegador para abrir o jupyter. Deve aparecer algo assim para você:
Se você rodar o notebook folium_intro.ipynb
inteiro você vai obter os mesmos resultados que vou mostrar aqui. Além disso, se você clicar na imagem do mapas que vão vir a seguir, você vai ser levado para a página desses mesmos mapas o que vai de te deixar intergarir com eles 😉
Colocando a mão na massa
Começamos importando as bibliotecas necessárias e criando um mapa:
import pandas as pd
import folium
brasil = folium.Map(
location=[-16.1237611, -59.9219642], # Coordenadas retiradas do Google Maps
zoom_start=4
)
O folium.Map()
precisa apenas do parâmetro location
para criar o seu mapa. Esse parâmetro recebe um par latitude
-longitude
que pode ser uma lista ou uma tupla. Aqui eu passei também um valor (4) para o parâmetro zoom_start
, o padrão desse parâmentro é 10, mas um zoom de 10 não deixa o país inteiro na região do mapa por isso, o novo valor de 4. Ao chamar o mapa, temos:
brasil
Mas agora eu quero colocar pontos no mapa. Aqui vou usar de exemplo um conjunto de dados com geolocalização de empresas que apareceram nos reembolsos analisados pela Operação Serenata de Amor. No repositório intro-folium
tem uma versão reduzida desse conjunto de dados. Então vamos começar lendo esses dados e colocando no mapa duas primeiras empresas:
empresas = pd.read_csv('empresas.xz')
empresa1 = empresas.iloc[0]
folium.Marker(
location=[empresa1['latitude'], empresa1['longitude']],
).add_to(brasil)
empresa2 = empresas.iloc[1]
folium.Marker(
location=[empresa2['latitude'], empresa2['longitude']],
).add_to(brasil)
O folium.Marker()
coloca um “pin” de localização no mapa. Para isso ocorrer precisamos passar novamente a location
e ainda indicar a qual mapa adicionar esse pin usando o metodo add_to()
. Chamando nomavente o mapa, temos:
brasil
Resista a curiosidade de colocar todos as empresas num mapa. Com as mais de ciquenta mil empresas deste dataset, isso provavelmente irá travar o seu computador (travou o meu jupyter). Confie em mim, um mapa com todas as empresas do dataset fica assim:
Sabendo que mostrar a belezinha acima trava o computador, vamos então selecionar um estado apenas para mostrar:
empresas_pe = empresas[empresas['state'] == 'PE']
Para melhorar a visualização eu também iniciei um novo mapa, esse tem as coordenadas do estado de Pernambuco (meu estado de origem ❤️), veja:
pernambuco = folium.Map(
location=[-8.3833569, -38.5757127],
zoom_start=7
)
pernambuco
E colocando as empresas no mapa:
for _, empresa in empresas_pe.iterrows():
folium.Marker(
location=[empresa['latitude'], empresa['longitude']],
).add_to(pernambuco)
pernambuco
Aqui ja podemos notar uma coisa que vale análise: Apesar de no dataset, apresentarem o estado cadastrado como Pernambuco, encontramos duas empresas que sua latitude e longitude não estão dentro do limite do estado 🤔
Puxa, muito legal isso, mas meio sem graça né? Então vamos dar uma olhada em como colorir um pouco as coisas?
Vamos começar reduzindo ainda mais nossa quantidade de empresas. Selecionei as 110 empresas de Olinda ❤️, e coloquei elas no mapa:
empresas_olinda_pe = empresas[empresas['city'] == 'OLINDA']
olinda = folium.Map(
location=[-7.9981267, -34.9082027],
zoom_start=13
)
for _, empresa in empresas_olinda_pe.iterrows():
folium.Marker(
location=[empresa['latitude'], empresa['longitude']],
).add_to(olinda)
olinda
Depois escolhi alguns bairros dos 22 bairros com empresas para colorir criando um dicionário que mapeia o nome de um bairro para uma cor:
colors = {
'AMPARO': 'pink',
'GUADALUPE': 'blue',
'CASA CAIADA': 'green',
'PEIXINHOS': 'orange',
'RIO DOCE': 'red',
'BAIRRO NOVO': 'purple',
}
olinda = folium.Map(
location=[-7.9981267, -34.9082027],
zoom_start=13
)
for _, empresa in empresas_olinda_pe.iterrows():
if empresa['neighborhood'] in colors.keys():
folium.Marker(
location=[empresa['latitude'], empresa['longitude']],
icon=folium.Icon(color=colors[empresa['neighborhood']])
).add_to(olinda)
Aqui usamos um novo parâmetro do folium.Marker()
, o icon
que recebe um objeto do tipo folium.Icon
e assim a coloração que queremos. Note que, antes de colocar os pontos no mapa, eu limpo o mapa de Olinda recriando esse objeto e assim, ao invés de colocar os pins coloridos por cima do mapa antigo com os pins azuis. Ainda mais um detalhe, esse tipo de marker (que parece um 📌) segue as cores do bootstrap, ou seja, é limitado, mas para esse exemplo serve:
olinda
Três coisinhas a mais
Mapas em páginas web
Você pode salvar seus mapas como páginas HTML usando o comando abaixo, basta identificar o mapa que quer salvar, usar o método .save()
e passar um nome do arquivo como como parâmetro. Todas as páginas de mapas desse post foram geradas assim:
olinda.save('mapas_htmls/olinda_some_colored.html')
Informações extras num mapa
Também pode passar informações sobre a entidade que você está colocando no mapa usando o parâmetro popup
. Assim ao clicar em um dos pins, um balão mostra alguma informação:
folium.Marker(
location=[empresa['latitude'], empresa['longitude']],
popup='sou uma empresa de Olinda',
icon=folium.Icon(color=colors[empresa['neighborhood']])
).add_to(olinda)
Um arco-iris
Como falei antes, o folium.Marker()
possui cores limitadas, então se você precisar de mais cores, ou se você precisar colocar cores diferentes daquelas disponíveis, use ou o folium.CircleMarker()
ou o folium.PolygonMarker()
. Ambos aceitam hash de cores.
E aí, vai fazer uns mapas também? 😉
Curiosidades e dicas
Mapas (e dados) abertos
A Leaflet, e assim por consequência também o Folium, usa o OpenStreetMap para montar seus mapas. Os mapas da OpenStreetMap são abertos e construídos por uma comunidade de pessoas interessadas em manter/ajudar o projeto, por exemplo, se você encontrar algum erro em alguma parte do mapa você pode enviar correções. Recomendo dar uma olhadinha na Wiki do OpenStreetMap para mais informações.
df.iloc[i]
Forma de visualizar qualquer linha do dataframe como se fosse um print bonito, basta passar como i
o índice da linha.
df.iterrows()
É muito útil para percorrer as linhas de um dataframe uma a uma. Esse método retorna sempre um índice e a linha correspondente.
Links
- Um resumão de dicas sobre pandas: Pandas cheatsheet da Lelê Portella
- WebApp pra ajudar a escolher um conjunto de cores: ColorBrewer2 (obrigada Geremia 😉)
- O que fazer quando tem muitos pontos? A dica do Filipe (obrigada 😉) foi usar um plugin do folium chamado
MarkerCluster