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
Feature Image

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:

Basic map

Basic map

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.

Map with marker

Map with marker

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
Map with marker and plot

Map with marker and plot

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
Map with icon marker

Map with icon marker

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
Map with circle marker

Map with circle marker

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
Map with HTML marker

Map with HTML marker

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
US States

US States

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
US States with unemployment rate (fake data)

US States with unemployment rate (fake data)

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
Map with heatmap

Map with heatmap

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
Map with stamen terrain layer

Map with stamen terrain layer

m = folium.Map(location=[30.4407159,-66.6017203], zoom_start=3)
folium.TileLayer('stamentoner').add_to(m)
m
Map with stamen toner layer

Map with stamen toner layer

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
Map with multiple layers

Map with multiple layers

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!

Programming Python Data Science Artificial Intelligence