In [1]:
import os
import folium

print(folium.__version__)


0.10.1+9.g3c75288.dirty

GeoJSON and choropleth

A few examples of how to do that with folium.

Using GeoJson

Let us load a GeoJSON file representing the US states.


In [2]:
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 [3]:
m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(geo_json_data).add_to(m)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_0.html'))

m


Out[3]:

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


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

folium.GeoJson(us_states).add_to(m)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_1.html'))

m


Out[4]:

You can pass a geopandas object.


In [5]:
import geopandas

gdf = geopandas.read_file(us_states)

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

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

m.save(os.path.join('results', 'GeoJSON_and_choropleth_3.html'))

m


Out[5]:

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.save(os.path.join('results', 'GeoJSON_and_choropleth_3.html'))

m


Out[6]:

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.save(os.path.join('results', 'GeoJSON_and_choropleth_4.html'))

m


Out[7]:

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.save(os.path.join('results', 'GeoJSON_and_choropleth_5.html'))

m


Out[11]:

Of course, if you can create and/or use a dictionnary 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)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_6.html'))

m


Out[13]:

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


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

m.save(os.path.join('results', 'GeoJSON_and_choropleth_7.html'))

m


Out[14]:

Using Choropleth class

Now if you want to get faster, you can use the Choropleth class. Have a look at it's docstring, it has several styling options.

You can use it in providing a file name (geo_path) :


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

folium.Choropleth(
    geo_data=geopandas.read_file(us_states),
    fill_opacity=0.3,
    line_weight=2,
).add_to(m)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_7.html'))

m


Out[15]:

Or in providing a GeoJSON string (geo_str) :


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

folium.Choropleth(geo_data=us_states).add_to(m)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_8.html'))

m


Out[16]:

Then, in playing with keyword arguments, you can get a choropleth in a few lines:


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

folium.Choropleth(
    geo_data=us_states,
    data=unemployment,
    columns=['State', 'Unemployment'],
    key_on='feature.id',
).add_to(m)


m.save(os.path.join('results', 'GeoJSON_and_choropleth_9.html'))

m


Out[17]:

You can force the color scale to a given number of bins (or directly list the bins you would like), by providing the bins argument.


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

folium.Choropleth(
    geo_data=us_states,
    data=unemployment,
    columns=['State', 'Unemployment'],
    key_on='feature.id',
    fill_color='YlGn',
    bins=[3, 4, 9, 11]
).add_to(m)


m.save(os.path.join('results', 'GeoJSON_and_choropleth_10.html'))

m


Out[18]:

You can also enable the highlight function, to enable highlight functionality when you hover over each area.


In [19]:
state_data = pd.read_csv(US_Unemployment_Oct2012)

m = folium.Map(location=[48, -102], zoom_start=3)
folium.Choropleth(
    geo_data=us_states,
    data=state_data,
    columns=['State', 'Unemployment'],
    key_on='feature.id',
    fill_color='YlGn',
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name='Unemployment Rate (%)',
    highlight=True
).add_to(m)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_11.html'))

m


Out[19]:

You can customize the way missing and nan values are displayed on your map using the two parameters nan_fill_color and nan_fill_opacity.


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

messed_up_data = unemployment.drop(0)
messed_up_data.loc[4, 'Unemployment'] = float('nan')

folium.Choropleth(
    geo_data=us_states,
    data=messed_up_data,
    columns=['State', 'Unemployment'],
    nan_fill_color='purple',
    nan_fill_opacity=0.4,
    key_on='feature.id',
    fill_color='YlGn'
).add_to(m)


m.save(os.path.join('results', 'GeoJSON_and_choropleth_10.html'))

m


Out[20]:

Internally Choropleth uses the GeoJson or TopoJson class, depending on your settings, and the StepColormap class. Both objects are attributes of your Choropleth object called geojson and color_scale. You can make changes to them, but for regular things you won't have to. For example setting a name for in the layer controls or disabling showing the layer on opening the map is possible in Choropleth itself.


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

choropleth = folium.Choropleth(
    geo_data=us_states,
    data=state_data,
    columns=['State', 'Unemployment'],
    key_on='feature.id',
    fill_color='YlGn',
    name='Unenployment',
    show=False,
).add_to(m)

# The underlying GeoJson and StepColormap objects are reachable
print(type(choropleth.geojson))
print(type(choropleth.color_scale))

folium.LayerControl(collapsed=False).add_to(m)

m.save(os.path.join('results', 'GeoJSON_and_choropleth_11.html'))

m


<class 'folium.features.GeoJson'>
<class 'branca.colormap.StepColormap'>
Out[21]: