How to plot your data on maps using Python and Folium
Harness the power of Python with data and Leaflet.js on mapping to create rich map visualizations
Folium is a python package that combines all the spectrum of tools python offers to manipulate data with the leaflet javascript library to create rich and interactive maps.
As usual for my articles, I’m providing a Google colab jupyter notebook with all the code and results that you can access here .
Create a basic map
Before we start building anything, let’s install some library that we will be using throughout the tutorial. You can use any packaging tool, I’ll provide the examples for pipenv and for pip prepending !
, so that it works on jupyter notebooks like Google colab.
pipenv install folium pandas
Or
!pip install folium pandas
After having the libraries installed, creating a map is as simple as 1 line of code:
import folium
folium.Map(location=[48.130518, 11.5364172], zoom_start=12)
This will automatically generate an interactive map and output it to the jupyter notebook, where you will be able to interact with it. The function Map
takes some optional arguments, in our case we are sending the location (coordinates) and a default zoom level.
If all goes well, you should see a map like this:
Even though this is already very exciting, we are not doing anything special with it. The true power of folium
comes from combining the mapping capabilities of the library with the data manipulation power of Python, so let’s start doing some of that.
Adding markers
One basic functionality we could add to our map is the ability to mark places so that they can easily be found, or to highlight important information.
This can easily be done with the Marker
function from folium
, as we demonstrate next:
m = folium.Map(location=[48.218871184761596, 11.624819877497147], zoom_start=15)
tooltip = "Click Here For More Info"
marker = folium.Marker(
location=[48.218871184761596, 11.624819877497147],
popup="<stong>Allianz Arena</stong>",
tooltip=tooltip)
marker.add_to(m)
m
Similar to the first example, first we create a map object, but then we also create a marker object. The marker object is created by passing the coordinates to the point, what we want to show on the popup when someone clicks on the marker and the tooltip for the marker among other options.
Markers have tons of configuration options, and since the marker popup expects an HTML there are a lot of possibilities. But what if we want to show charts in the popups? Is there an easy way?
Chart popups for markers
Folium
provides built-in support for visualizations to any marker type. The visualizations are enabled by the libraries vincent and altair .
To render some visualizations we will need some data, so let’s get that first:
import json
import requests
url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
data = json.loads(requests.get(f"{url}/vis1.json").text)
Next, let’s plot the data in a marker:
m = folium.Map(location=[48.218871184761596, 11.624819877497147], zoom_start=15, tiles="Stamen Terrain")
marker = folium.Marker(
location=[48.218871184761596, 11.624819877497147],
popup=folium.Popup(max_width=450).add_child(
folium.Vega(data, width=450, height=250)
),
)
marker.add_to(m)
m
Awesome, but can we actually change the marker itself and not only the popup window? The short answer is yes, and with almost anything.
Customizing the marker
The Marker
function allows for a number of parameterizations, from changing the marker icon from a library of predefined icons, shapes to building your own marker using HTML, and in this article we will see examples for the 3, starting by using predefined icons:
m = folium.Map(location=[48.218871184761596, 11.624819877497147], zoom_start=15)
tooltip = "Click Here For More Info"
marker = folium.Marker(
location=[48.218871184761596, 11.624819877497147],
icon=folium.Icon(icon="cloud"),
popup="<stong>Allianz Arena</stong>",
tooltip=tooltip)
marker.add_to(m)
m
Going back to our simple Allianz Arena example, we have now changed the icon for a marker with a cloud, but where are these icons coming from? What options are available?
The icons are coming from the bootstrap library, but you could also use font awesome.
Next let’s use shapes, like circles to build our markers:
m = folium.Map(location=[48.218871184761596, 11.624819877497147], zoom_start=15)
tooltip = "Click Here For More Info"
marker = folium.CircleMarker(
location=[48.218871184761596, 11.624819877497147],
radius=50,
popup="<stong>Allianz Arena</stong>",
tooltip=tooltip)
marker.add_to(m)
m
Last, we can use HTML to build any type of marker we want to.
m = folium.Map(location=[48.218871184761596, 11.624819877497147], zoom_start=15)
tooltip = "Click Here For More Info"
marker = folium.Marker(
location=[48.218871184761596, 11.624819877497147],
popup="<stong>Allianz Arena</stong>",
icon=folium.DivIcon(html=f"""
<div style="color:#f00;background:#fff;width:60px;text-align:center;">MARKER</div>
"""),
tooltip=tooltip)
marker.add_to(m)
m
In this last example, we use HTML to create a DIV element and place some text as a marker, but we could use an SVG and render anything you want. Just remember to center your HTML so that the marker is in the right place, something I did not do in my example.
Choropleth Maps
Choropleth maps are popular thematic maps used to represent statistical data through various shading patterns or symbols on predetermined geographic areas (i.e. countries or states). They are good at utilizing data to easily represent variability of the desired measurement, across a region.
For creating choropleth maps we need to work with 2 types of data, statistical data for the shades or colors we want to represent, and geo spatial data.
In our example we are going to use the US states to define the regions, and the US unemployment statistics (not real data).
Let’s start with plotting the geographical regions, aka the US states:
data_url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
us_states_url = f"{data_url}/us-states.json"
m = folium.Map([43, -100], zoom_start=4)
folium.GeoJson(us_states_url).add_to(m)
m
Our new map contains now an overlay highlighting the US states, but we can do more, we can now use the statistical information we have about US unemployment and highlight the states with more and less unemployment.
First, let’s see what the data looks like:
import pandas as pd
us_unemployment_url = f"{data_url}/US_Unemployment_Oct2012.csv"
unemployment = pd.read_csv(us_unemployment_url)
unemployment.head()
State | Unemployment | |
---|---|---|
0 | AL | 7.1 |
1 | AK | 6.8 |
2 | AZ | 8.1 |
3 | AR | 7.2 |
4 | CA | 10.1 |
The data is pretty simple, one column contains the state, and the next contains the unemployment rate.
With that given we can start coloring our map:
m = folium.Map(location=[48, -102], zoom_start=3)
folium.Choropleth(
geo_data=us_states,
name='choropleth',
data=unemployment,
columns=['State', 'Unemployment'],
key_on='feature.id',
fill_color='YlGn',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='Unemployment Rate %'
).add_to(m)
m
Nicely done!
Heatmaps
Heatmaps are another popular choice for maps, they can be used for multiple purposes including weather conditions, pollution, population density, etc.
They are extremely powerful tools and with the help of pandas
and folium
super easy to build. Let’s take an example using bike stations in the city of Chicago. I found an interesting dataset online with bike stations with coordinates that we will use to build our heat map.
Let’s load the data:
stations_url = 'https://gbfs.divvybikes.com/gbfs/en/station_information.json'
stations = json.loads(requests.get(stations_url).text)['data']['stations']
stations = pd.json_normalize(stations)
stations = stations[['lat', 'lon']]
stations.head()
lat | lon | |
---|---|---|
0 | 41.876511 | -87.620548 |
1 | 41.867226 | -87.615355 |
2 | 41.856268 | -87.613348 |
3 | 41.874053 | -87.627716 |
4 | 41.886976 | -87.612813 |
The bike station data has multiple columns with tons of data, however for our purposes we only need the coordinates, so we remove the rest. Now each row represents a set of coordinates (latitude and longitude) where a bike station is placed.
Next we will build a heatmap to highlight the areas in the city where bike stations are more concentrated.
from folium import plugins
m = folium.Map([41.8781, -87.6298], zoom_start=11)
# convert to (n, 2) nd-array format for heatmap
stationArr = stations.values
# plot heatmap
m.add_child(plugins.HeatMap(stationArr, radius=15))
m
Great work! The secret for the heat map was simply using a plugin from folium
passing a matrix with the latitude and longitude of each station and a radius.
Map tiles
Finally, before closing out, I’d like to highlight another feature of folium
, map tiles. So far we worked with one type of rendering for maps, but there are many options we could use, each of which would make the maps look different.
Let’s see some examples:
m = folium.Map(location=[30.4407159,-66.6017203], zoom_start=3)
folium.TileLayer('stamenterrain').add_to(m)
m
m = folium.Map(location=[30.4407159,-66.6017203], zoom_start=3)
folium.TileLayer('stamentoner').add_to(m)
m
Or even better, you can give the users the option to use by using yet another feature called layerControl
m = folium.Map(location=[30.4407159,-66.6017203], zoom_start=4)
# Add tiles
folium.TileLayer('stamentoner').add_to(m)
folium.TileLayer('stamenwatercolor').add_to(m)
folium.TileLayer('cartodbpositron').add_to(m)
folium.TileLayer('openstreetmap').add_to(m)
# Add the option to switch tiles
folium.LayerControl().add_to(m)
m
You can see now on this map, on the top right, a layer selection, which users can use to switch between tiles.
Conclusion
Writing this article has been super fun! Folium
offers a lot of configuration options, tons of opportunities to build great maps, and I’ll definitely continue playing with it to make something fun.
While researching this topic I had some issues as the documentation is not really great, however, on their github page , they provide great examples you can run and see how to implement some of the things we learned today. I highly recommend going through them.
Thanks for reading!
Source: livecodestream