GeoJSON and choropleth

A few examples of how to do that with folium.

Using GeoJson

Loading data

Let us load a GeoJSON file representing the US states.

In [1]:
import json

import requests

url = (
    "https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
us_states = f"{url}/us-states.json"

geo_json_data = json.loads(requests.get(us_states).text)

It is a classical GeoJSON FeatureCollection (see https://en.wikipedia.org/wiki/GeoJSON) of the form :

{
    "type": "FeatureCollection",
    "features": [
        {
            "properties": {"name": "Alabama"},
            "id": "AL",
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[-87.359296, 35.00118], ...]]
                }
            },
        {
            "properties": {"name": "Alaska"},
            "id": "AK",
            "type": "Feature",
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [[[[-131.602021, 55.117982], ... ]]]
                }
            },
        ...
        ]
    }

A first way of drawing it on a map, is simply to use folium.GeoJson :

In [2]:
import folium


m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(geo_json_data).add_to(m)

m
Out[2]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Note that you can avoid loading the file on yourself ; in simply providing a file path.

In [3]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(us_states).add_to(m)

m
Out[3]:
Make this Notebook Trusted to load map: File -> Trust Notebook

You can pass a geopandas object.

In [4]:
import geopandas

gdf = geopandas.read_file(us_states)

m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    gdf,
).add_to(m)

m
Out[4]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Click on zoom

You can enable an option that if you click on a part of the geometry the map will zoom in to that.

Try it on the map below:

In [5]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(geo_json_data, zoom_on_click=True).add_to(m)

m
Out[5]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Styling

Now this is cool and simple, but we may be willing to choose the style of the data.

You can provide a function of the form lambda feature: {} that sets the style of each feature.

For possible options, see:

In [6]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    geo_json_data,
    style_function=lambda feature: {
        "fillColor": "#ffff00",
        "color": "black",
        "weight": 2,
        "dashArray": "5, 5",
    },
).add_to(m)

m
Out[6]:
Make this Notebook Trusted to load map: File -> Trust Notebook

What's cool in providing a function, is that you can specify a style depending on the feature. For example, if you want to visualize in green all states whose name contains the letter 'E', just do:

In [7]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    geo_json_data,
    style_function=lambda feature: {
        "fillColor": "green"
        if "e" in feature["properties"]["name"].lower()
        else "#ffff00",
        "color": "black",
        "weight": 2,
        "dashArray": "5, 5",
    },
).add_to(m)

m
Out[7]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Wow, this looks almost like a choropleth. To do one, we just need to compute a color for each state.

Let's imagine we want to draw a choropleth of unemployment in the US.

First, we may load the data:

In [8]:
import pandas as pd

US_Unemployment_Oct2012 = f"{url}/US_Unemployment_Oct2012.csv"
unemployment = pd.read_csv(US_Unemployment_Oct2012)

unemployment.head(5)
Out[8]:
State Unemployment
0 AL 7.1
1 AK 6.8
2 AZ 8.1
3 AR 7.2
4 CA 10.1

Now we need to create a function that maps one value to a RGB color (of the form #RRGGBB). For this, we'll use colormap tools from folium.colormap.

In [9]:
from branca.colormap import linear

colormap = linear.YlGn_09.scale(
    unemployment.Unemployment.min(), unemployment.Unemployment.max()
)

print(colormap(5.0))

colormap
#d8f0a3ff
Out[9]:
3.210.3

We need also to convert the table into a dictionnary, in order to map a feature to it's unemployment value.

In [10]:
unemployment_dict = unemployment.set_index("State")["Unemployment"]

unemployment_dict["AL"]
Out[10]:
7.1

Now we can do the choropleth.

In [11]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    geo_json_data,
    name="unemployment",
    style_function=lambda feature: {
        "fillColor": colormap(unemployment_dict[feature["id"]]),
        "color": "black",
        "weight": 1,
        "dashArray": "5, 5",
        "fillOpacity": 0.9,
    },
).add_to(m)

folium.LayerControl().add_to(m)

m
Out[11]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Of course, if you can create and/or use a dictionary providing directly the good color. Thus, the finishing seems faster:

In [12]:
color_dict = {key: colormap(unemployment_dict[key]) for key in unemployment_dict.keys()}
In [13]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    geo_json_data,
    style_function=lambda feature: {
        "fillColor": color_dict[feature["id"]],
        "color": "black",
        "weight": 1,
        "dashArray": "5, 5",
        "fillOpacity": 0.9,
    },
).add_to(m)
Out[13]:
<folium.features.GeoJson at 0x7fa6b9856c70>

Note that adding a color legend may be a good idea.

In [14]:
colormap.caption = "Unemployment color scale"
colormap.add_to(m)

m
Out[14]:
Make this Notebook Trusted to load map: File -> Trust Notebook