Updated On : Oct-10,2021 Tags geoviews, choropleth-maps
Geoviews - Choropleth Maps using Bokeh and Matplotlib  [Python]

Geoviews - Choropleth Maps using Bokeh and Matplotlib

Geoviews is a Python library that provides an API that can be used to analyze geospatial data by plotting maps of various kinds like choropleth maps, scatter maps, bubble maps, etc. It's quite common for datasets to have geospatial information nowadays. Geoviews is built on the top of holoviews library. Geoviews like holoviews just let us declare what data columns to use for what purpose but internally it uses either bokeh or matplotlib to create maps. It let us create maps with as much less code as possible. The maps created by geoviews using bokeh back-end will be interactive maps whereas the ones created using matplotlib will be static. As a part of this tutorial, we'll explain how we can use geoviews to create choropleth maps. We'll be using datasets available from geopandas library and a few other sources for our explanations. If you want to create scatter and bubble maps using geoviews then please feel free to check the below tutorial.

If you are interested in holoviews then please feel free to check our tutorial on the same where we have explained in detail with simple examples how to use it. It can help you with this tutorial as well.

We'll now start with our tutorial without wasting much time. We have highlighted the important sections of the tutorial for an overview.

Tutorial Sections Overview

We have imported geoviews first and printed the version of it.

In [26]:
import geoviews

print("Geoviews Version : {}".format(geoviews.__version__))
Geoviews Version : 1.8.1

Load Datasets

In this section, we'll load a few datasets that we'll be using for creating choropleth maps. We might load a few other datasets later as well.

Below we have first import geopandas and printed its version. We have then loaded world datasets available from it. The world datasets loaded using geopandas is a GeoDataFrame object which is a special type of dataframe that has geoinformation present in it. The geoinformation is stored in a column named geometry which has instances of POLYGON or MULTIPOLYGON from shapely library representing countries of the world. We'll be using this dataset for primarily creating the world map. We'll also merge other datasets with this one to add more information to the chart.

If you want to learn about geopandas then please feel free to check our tutorial on it.

In [2]:
import geopandas as gpd

print("Geopandas Version : {}".format(gpd.__version__))

print("Available Datasets : {}".format(gpd.datasets.available))

world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))

world.head()
Geopandas Version : 0.9.0
Available Datasets : ['naturalearth_cities', 'naturalearth_lowres', 'nybb']
Out[2]:
pop_est continent name iso_a3 gdp_md_est geometry
0 920938 Oceania Fiji FJI 8374.0 MULTIPOLYGON (((180.00000 -16.06713, 180.00000...
1 53950935 Africa Tanzania TZA 150600.0 POLYGON ((33.90371 -0.95000, 34.07262 -1.05982...
2 603253 Africa W. Sahara ESH 906.5 POLYGON ((-8.66559 27.65643, -8.66512 27.58948...
3 35623680 North America Canada CAN 1674000.0 MULTIPOLYGON (((-122.84000 49.00000, -122.9742...
4 326625791 North America United States of America USA 18560000.0 MULTIPOLYGON (((-122.84000 49.00000, -120.0000...

Below we have loaded another dataset that has information about the happiness score of each country of the world. It has few other information as well like GDP, healthy life expectancy, freedom, generosity, perception of corruption, and social support. The dataset is loaded as simple pandas dataframe.

The dataset can be downloaded from the below link.

In [3]:
import pandas as pd

happiness = pd.read_csv("datasets/world_happiness_2019.csv")

happiness.head()
Out[3]:
Overall rank Country or region Score GDP per capita Social support Healthy life expectancy Freedom to make life choices Generosity Perceptions of corruption
0 1 Finland 7.769 1.340 1.587 0.986 0.596 0.153 0.393
1 2 Denmark 7.600 1.383 1.573 0.996 0.592 0.252 0.410
2 3 Norway 7.554 1.488 1.582 1.028 0.603 0.271 0.341
3 4 Iceland 7.494 1.380 1.624 1.026 0.591 0.354 0.118
4 5 Netherlands 7.488 1.396 1.522 0.999 0.557 0.322 0.298

Now, we have merged our happiness dataset with the world geo dataset to create a final dataset which geo-information of each country and other important attributes present through the happiness dataset which we can utilize to create choropleth maps.

In [4]:
world_happiness = world.merge(happiness, left_on="name", right_on="Country or region")

world_happiness.head()
Out[4]:
pop_est continent name iso_a3 gdp_md_est geometry Overall rank Country or region Score GDP per capita Social support Healthy life expectancy Freedom to make life choices Generosity Perceptions of corruption
0 53950935 Africa Tanzania TZA 150600.0 POLYGON ((33.90371 -0.95000, 34.07262 -1.05982... 153 Tanzania 3.231 0.476 0.885 0.499 0.417 0.276 0.147
1 35623680 North America Canada CAN 1674000.0 MULTIPOLYGON (((-122.84000 49.00000, -122.9742... 9 Canada 7.278 1.365 1.505 1.039 0.584 0.285 0.308
2 326625791 North America United States of America USA 18560000.0 MULTIPOLYGON (((-122.84000 49.00000, -120.0000... 19 United States of America 6.892 1.433 1.457 0.874 0.454 0.280 0.128
3 18556698 Asia Kazakhstan KAZ 460700.0 POLYGON ((87.35997 49.21498, 86.59878 48.54918... 60 Kazakhstan 5.809 1.173 1.508 0.729 0.410 0.146 0.096
4 29748859 Asia Uzbekistan UZB 202300.0 POLYGON ((55.96819 41.30864, 55.92892 44.99586... 41 Uzbekistan 6.174 0.745 1.529 0.756 0.631 0.322 0.240

Plotting Map with One Line of Code

In order to plot maps using geoviews, we first need to set backend that it should use for plotting. We'll be using bokeh as a backend for the majority of our charts as it let us create interactive charts. We'll also explain later on how we can switch to matplotlib backend.

Below we have first set backend as bokeh using extension() method of geoviews.

In [ ]:
geoviews.extension("bokeh")

Geoviews - Choropleth Maps using Bokeh and Matplotlib

Geoviews provides a method named Polygons() which we'll use for plotting choropleth. It accepts data that has geometry information present in them and creates a map from it.


  • Polygons(data=None,kdims=None,vdims=None) - This method takes as input dataframe which has gemetry information and creates a plot from it. The geometry information is generally polygons/multi-polygons representing regions on map.
    • The kdims parameter accepts two strings specifying column names from the dataframe that will be used to create polygons on the map. As we'll be using geopandas GeoDataFrame, we don't need to provide this parameter.
    • The vdims parameter requires a list of one string specifying column name from data whose values will be used to color regions on a map. We can provide a list with more than one string to this parameter as well. In that case, the first string column's data will be used to color regions on a map all other string columns data will be included in a tooltip when the mouse hovers over the region. We can even ignore this parameter and the whole map will be colored with just one color.

Below we have created our first map by using Polygons() method giving it a world geo dataframe which we had loaded using geopandas earlier. We have the first store the result of the calling method in a variable and print it.

Whenever we print the result of Polygons() method, it'll show kdims parameter in square brackets - [] and vdims parameter in parenthesis - (). In our case, we have not provided vdims hence there is nothing printed. It printed [Longitude,Latitude] for kdims which it took from geometry column of geo dataframe.

We have then displayed the map by calling output() method of geoviews giving it the world map object we had created earlier using Polygons() method. We can simply call execute world map object in a cell of jupyter notebook as well and it'll also display the map.

We can notice that as we have not provided vdims parameter value, the whole map is colored with just one color. We can also notice that chart dimensions by default are quite small. We'll explain in our upcoming examples how we can modify the dimensions of the map, add the title to it, add hover styles, and many more.

In [6]:
world_map = geoviews.Polygons(data=world)

print(world_map)
:Polygons   [Longitude,Latitude]
In [ ]:
geoviews.output(world_map)

Geoviews - Choropleth Maps using Bokeh and Matplotlib

1. Normal Choropleth Maps

In this section, we'll create a few choropleth maps using our datasets which we had loaded earlier. We'll also explain how we can modify the look and feel of maps.

1.1 World Colored by Continent Map

Our first choropleth map simply colors each continent of the world using different colors. We have created a world continent choropleth map by giving the world geo dataframe to Polygons() method asking it to use columns continent for coloring individual regions of data. We can notice that the chart has colored each country belonging to the same continent with the same color. The second column named name provided as vdims will be used to show the name of the country when a mouse hovers over any country.

Once we have created a map using Polygons() method, we also need to modify the look of the map and there are two ways to do it.

  1. %%opts Cell Magic Command - This is cell magic command in jupyter notebooks which is available for charts created through holoviews. It accepts the first argument which is the name of the object (Polygons in our case). Then it let us specify chart parameters to modify in two ways.
    • The parameters mentioned in [] let us modify overall chart dimensions like height, width, title, axes, labels, ticks, tools, axes limits, etc.
    • The parameters mentioned in () let us modify the look of components inside of map, like colormap of regions, opacity, hover color, etc.
    • If you want to learn about magic commands in a jupyter notebook then please feel free to check our small tutorial explaining them with simple examples. List of Useful Magic Commands in Jupyter Notebook
  2. opts() Method - This method can be called on an instance of Polygons by giving a list of parameters and their values one after another. There is no distinction like %%opts cell magic command here.

We'll be explaining both ways in our examples. If you are interested in learning about them then please feel free to check our tutorial on Holoviews from which the concepts are inherited as geoviews is built on top of it.

Below we have modified the list of parameters of the chart using %%opts cell magic command. We have specified height, width, title, tools, colormap, alpha, and hover color parameters using it.

In [ ]:
%%opts Polygons [height=550 width=900 title="World Continents" tools=["hover"]] (cmap="tab10" hover_color="lime" alpha=0.6)

geoviews.Polygons(data=world, vdims=["continent", "name"])

Geoviews - Choropleth Maps using Bokeh and Matplotlib

1.2 World Happiness Choropleth Map

In this section, we have created our first choropleth map showing the happiness score of countries worldwide. We have called Polygons() method with the world happiness geo dataframe which we had created earlier by merging the world geo dataframe with the happiness dataframe. We have then given column names Score and name to vdims parameter. This will inform it to use the contents of Score column to color regions (countries) of the map. The contents of Score and name columns will be displayed when the mouse hovers over any region.

We have also modified various chart attributes like height, width, colormap, etc.

Please make a NOTE that we can call %%opts cell magic command more than once but all calls should be at the beginning of the cell and it'll be in effect in that cell of Jupyter notebook only.

In [ ]:
%%opts Polygons [height=550 width=900 title="Happiness Score Per Country" colorbar=True] (cmap="OrRd")
%%opts Polygons [tools=["hover",]] (hover_color="grey")

geoviews.Polygons(data=world_happiness, vdims=["Score", "name"])

Geoviews - Choropleth Maps using Bokeh and Matplotlib

1.3 Perception of Corruption Choropleth Map

In this example, we have created our second choropleth map which shows the perception of corruption worldwide. We have used the same world happiness geo dataframe for creating this choropleth map. We have asked Perceptions of corruption column to be used to color regions of the map.

But this time, we have stored results Polygons object in a variable. We have then called opts method with a list of parameters of the map to modify. This is the same as using %%opts cell magic command and will give the same results. The decision to use cell magic command or method is on individual whichever is convenient to them.

In [ ]:
choropleth = geoviews.Polygons(data=world_happiness, vdims=["Perceptions of corruption", "name"])

choropleth.opts(height=600, width=900, title="Perception of Corruption Per Country Worldwide",
                tools=["hover"], cmap="Greens", colorbar=True, colorbar_position="bottom")

Geoviews - Choropleth Maps using Bokeh and Matplotlib

1.4 US States Population Choropleth Map

In this section, we'll create our third choropleth map showing the population density of US states in 2018. We'll be loading and merging two datasets for creating this map.

  • US States GeoDataFrame - This dataset has geometry information for each state of united states. We have geoinformation for states available in GeoJSON format. We have loaded that file using geopandas in GeoDataFrame format. We have also printed the first few rows to show the contents of it.
  • US States Population Dataset - The second dataset is simple pandas dataframe loaded from a CSV file which has information about the population of each state in 2018.
In [11]:
us_states = gpd.read_file("datasets/us-states.json")

us_states.head()
Out[11]:
id name geometry
0 AL Alabama POLYGON ((-87.35930 35.00118, -85.60667 34.984...
1 AK Alaska MULTIPOLYGON (((-131.60202 55.11798, -131.5691...
2 AZ Arizona POLYGON ((-109.04250 37.00026, -109.04798 31.3...
3 AR Arkansas POLYGON ((-94.47384 36.50186, -90.15254 36.496...
4 CA California POLYGON ((-123.23326 42.00619, -122.37885 42.0...
In [12]:
us_pop = pd.read_csv("datasets/State Populations.csv")

us_pop.head()
Out[12]:
State 2018 Population
0 California 39776830
1 Texas 28704330
2 Florida 21312211
3 New York 19862512
4 Pennsylvania 12823989

After loading two datasets, we have merged them to create one dataset and printed the first few rows of the merged dataset below.

In [13]:
us_states_pop = us_states.merge(us_pop, left_on="name", right_on="State")

us_states_pop.head()
Out[13]:
id name geometry State 2018 Population
0 AL Alabama POLYGON ((-87.35930 35.00118, -85.60667 34.984... Alabama 4888949
1 AK Alaska MULTIPOLYGON (((-131.60202 55.11798, -131.5691... Alaska 738068
2 AZ Arizona POLYGON ((-109.04250 37.00026, -109.04798 31.3... Arizona 7123898
3 AR Arkansas POLYGON ((-94.47384 36.50186, -90.15254 36.496... Arkansas 3020327
4 CA California POLYGON ((-123.23326 42.00619, -122.37885 42.0... California 39776830

At last, we have created a choropleth map using Polygons() method giving it this merged GeoDataFrame as input asking it to use 2018 Population column for coloring individual states.

We have also modified various attributes of the chart using %%opts cell magic command.

In [ ]:
%%opts Polygons [height=700 width=900 title="US 2018 Population" tools=["hover", ]]
%%opts Polygons [xlim=(-170, -60) ylim=(10,75) colorbar=True colorbar_position="top"]
%%opts Polygons (cmap="PuRd" hover_color="lime")

geoviews.Polygons(data=us_states_pop, vdims=["2018 Population", "State"])

Geoviews - Choropleth Maps using Bokeh and Matplotlib

2. Changing Plotting Backends

As we said earlier, geoviews creates a chart using one of the two backends.

  • Bokeh
  • Matplotlib

Till now, we had created all charts using bokeh as backend. We can easily switch backend using extension() method by giving it backend name. In this section, we'll be creating maps using matplotlib backend.

Below we have set backed as matplotlib using extension() method.

In [ ]:
geoviews.extension("matplotlib")

Geoviews - Choropleth Maps using Bokeh and Matplotlib

2.1 Perception of Corruption Choropleth Map (Matplotlib Backend)

Below we have recreated our perception of the corruption map using the matplotlib backend.

Please make a NOTE that chart parameters like chart figure sizes and a few other parameters will have different names based on the backend that we use. As we can see figure size for matplotlib is specified using fig_inches parameter whereas it's specified using height & width for bokeh backend.

TIP - We can simply press TAB inside of square backets - [] or parenthesis - () to know list of parameter names as well.

In [ ]:
%%opts Polygons [fig_inches=(15,8) colorbar=True]

choropleth = geoviews.Polygons(data=world_happiness, vdims=["Perceptions of corruption", "name"])

choropleth.opts(title="World Perception of Corruption", cmap="Greens")

Geoviews - Choropleth Maps using Bokeh and Matplotlib

2.2 US States Population Choropleth Map (Matplotlib Backend)

In this section, we have recreated the US population choropleth map using the matplotlib backend. The majority of the code is the same as that when we had created it using the bokeh backend with a difference in a few chart parameter names.

In [ ]:
%%opts Polygons [fig_inches=(15,8) title="US 2018 Population" tools=["hover", ]]
%%opts Polygons [xlim=(-170, -60) ylim=(10,75) colorbar=True colorbar_position="top"]
%%opts Polygons (cmap="PuRd" hover_color="lime")

geoviews.Polygons(data=us_states_pop, vdims=["2018 Population", "State"])

Geoviews - Choropleth Maps using Bokeh and Matplotlib

3. Different Cartographic Projections

In this section, we'll explain how we can create different projections of maps. We'll be using cartopy library for creating projections of different types. Cartopy library has a module named crs which provides a list of different projections. We just need to create an instance of any projection type from cartopy.crs module and set it as the value of projection option of Polygons. We have explained it with examples below.

If you are interested in learning about cartopy then please feel free to check our tutorial on it. It's another map creation library in python built on the top of matplotlib.

We'll first set our backend as bokeh.

In [ ]:
geoviews.extension("bokeh")

Geoviews - Choropleth Maps using Bokeh and Matplotlib

3.1 GDP Per Capita Choropleth Map (Orthographic Projection)

In this section, we have created a choropleth map of GDP per capita with orthographic projection. We have first imported crs module from cartopy library.

Then we have created a choropleth map using Polygons() method of geoviews by giving it world happiness geo dataframe and asking it to use column GDP per capita to color countries of the world.

The majority of our options are set like we have been doing till now using %%opts magic command with the addition of one option. We have added an option named projection with a value of crs.Orthographic() object. This will instruct geoviews to change the projection to orthographic.

With just this simple addition, we can change the projection of our map in geoviews.

In [19]:
from cartopy import crs
In [ ]:
%%opts Polygons [height=550 width=550 title="GDP per capita Per Country" tools=["hover", ]] (cmap="OrRd" hover_color="lime")
%%opts Polygons [projection=crs.Orthographic()]

geoviews.Polygons(data=world_happiness, vdims=["GDP per capita", "name"])

Geoviews - Choropleth Maps using Bokeh and Matplotlib

3.2 Freedom to Make Life Choices Choropleth Map (Mollweide Projection)

In this section, we have created another choropleth map which shows freedom to make life choices of various countries worldwide with mollweide projection.

We have created a choropleth map using Polygons() method asking it to use Freedom to make life choices column for coloring polygons of countries. All other options are set like we have been doing for the last few examples. The projection option is set to value crs.Mollweide() which will force mollweide projection.

In [ ]:
%%opts Polygons [height=450 width=900 title="Freedom to make life choices Per Country" tools=["hover", ]]
%%opts Polygons [projection=crs.Mollweide()] (cmap="RdBu" hover_color="lime")

geoviews.Polygons(data=world_happiness, vdims=["Freedom to make life choices", "name"])

Geoviews - Choropleth Maps using Bokeh and Matplotlib

4. Adding Geo Tiles

In this section, we'll explain how we can add geo Tiles to our data. There are various geo tile providers which present different types of information on the map and we can add that information to our map by just adding that tile to our map. The tile can have information like world countries’ names, a terrain view, midnight view, topographic view, ocean view of the world. We'll be adding a few such tiles to our choropleth maps for explanation purposes.

We can access a list of all available tiles from geoviews using the below command.

In [22]:
geoviews.tile_sources.tile_sources
Out[22]:
{'CartoDark': :WMTS   [Longitude,Latitude],
 'CartoEco': :WMTS   [Longitude,Latitude],
 'CartoLight': :WMTS   [Longitude,Latitude],
 'CartoMidnight': :WMTS   [Longitude,Latitude],
 'StamenTerrain': :WMTS   [Longitude,Latitude],
 'StamenTerrainRetina': :WMTS   [Longitude,Latitude],
 'StamenWatercolor': :WMTS   [Longitude,Latitude],
 'StamenToner': :WMTS   [Longitude,Latitude],
 'StamenTonerBackground': :WMTS   [Longitude,Latitude],
 'StamenLabels': :WMTS   [Longitude,Latitude],
 'EsriImagery': :WMTS   [Longitude,Latitude],
 'EsriNatGeo': :WMTS   [Longitude,Latitude],
 'EsriUSATopo': :WMTS   [Longitude,Latitude],
 'EsriTerrain': :WMTS   [Longitude,Latitude],
 'EsriReference': :WMTS   [Longitude,Latitude],
 'EsriOceanBase': :WMTS   [Longitude,Latitude],
 'EsriOceanReference': :WMTS   [Longitude,Latitude],
 'OSM': :WMTS   [Longitude,Latitude],
 'Wikipedia': :WMTS   [Longitude,Latitude]}

4.1 Tile Example

In this section, we have simply created on tile and plotted it. We have created CartoDark tile and plotted it below to show how it looks. We can then merge it with our map and it'll have this dark look. We can also plot points directly on this tile to create scatter and bubble maps which we have covered in a different tutorial.

Please feel free to check it from the below link.

In [ ]:
tile = geoviews.tile_sources.CartoDark()

tile

Geoviews - Choropleth Maps using Bokeh and Matplotlib

4.2 Social Support Choropleth Map (CartoDark Tile)

In this section, we have created a choropleth map showing social support provided by various countries worldwide and have added carto dark tile to it.

Choropleth map has been created using Polygons() method by giving it world happiness geo dataframe and asking it to use column named Social support to color polygons of countries.

We have then created an instance of CartoDark() and just multiplied it with Polygons object representing our choropleth map. This star operation is commonly used in holoviews to merge more than one chart into a single chart. We can notice that how the dark theme is added to our map.

In [ ]:
%%opts Polygons [height=550 width=900 title="Social support Per Country" tools=["hover", ] colorbar=True]
%%opts Polygons (cmap="PiYG" hover_color="lime" line_color="white")

choropleth = geoviews.Polygons(data=world_happiness, vdims=["Social support", "name"])

tile = geoviews.tile_sources.CartoDark()

choropleth * tile

Geoviews - Choropleth Maps using Bokeh and Matplotlib

4.3 Generosity Choropleth Map (ESRI Tile)

In this section, we have created a choropleth map representing the generosity of people for each country worldwide. We have added ESRI tile to the map.

We have created a choropleth map using Polygons method giving it the world happiness geo dataframe and asking to use Generosity column from the geo dataframe for coloring polygons of the map. We have then simply multiplied the choropleth map with an instance of ESRI() to add ESRI tile to the map.

In [ ]:
%%opts Polygons [height=550 width=900 title="Generosity Per Country" tools=["hover", ] colorbar=True]
%%opts Polygons [projection=crs.Mercator()]
%%opts Polygons (cmap="RdYlGn" hover_color="lime" line_color="white")

choropleth = geoviews.Polygons(data=world_happiness, vdims=["Generosity", "name"])

choropleth * geoviews.tile_sources.ESRI()

Geoviews - Choropleth Maps using Bokeh and Matplotlib

This ends our small tutorial explaining how to create choropleth maps using geoviews. Please feel free to let us know your views in the comments section.



Sunny Solanki  Sunny Solanki