Choropleth maps are one of the most interesting and useful visualizations. They are important because they can provide information for geographic location, they look beautiful and grab attention in a presentation. Several different libraries can be used to do that. In this tutorial, I will use folium.
What is a choropleth map?
Here is the definition from Wikipedia:
Choropleth maps provide an easy way to visualize how a measurement varies across a geographic area or show the level of variability within a region. A heat map or isarithmic map is similar but does not use a priori geographic areas. They are the most common type of thematic map because published statistical data (from government or other sources) is generally aggregated into well-known geographic units, such as countries, states, provinces, and counties, and thus they are relatively easy to create using GIS, spreadsheets, or other software tools.
In simple and easy words, choropleth maps are the maps that show the information by geolocation using color on the map. See some of the pictures below to get more understanding.
Data Preparation
Data preparation is an important and common task for all data scientists. The dataset I used here is reasonably nice and clean. But for this visualization, I still need to work on it a bit. Let’s import the necessary libraries and the dataset.
import pandas as pd import numpy as npdf = pd.read_excel('https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/DV0101EN/labs/Data_Files/Canada.xlsx', sheet_name='Canada by Citizenship', skiprows=range(20), skipfooter=2)
I cannot show a screenshot of the dataset here because it’s too big. I encourage you to run the code by yourself. That’s the only way to learn.
This dataset contains how many immigrants came to Canada from the different countries of the world from 1980 to 2013. Let’s see the column names of the dataset to get a sense of what this dataset contains:
df.columns#Output: Index(['Type', 'Coverage', 'OdName', 'AREA', 'AreaName', 'REG', 'RegName', 'DEV', 'DevName', 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013], dtype='object')
We are going to plot the total number of immigrants from 1980 to 2013 in each country.
We need the name of the country and the years. Drop some unnecessary columns from the dataset.
df.drop(['AREA', 'REG', 'DEV', 'Type', 'Coverage', 'AreaName', 'RegName', 'DevName'], axis=1, inplace=True)
The column ‘OdName’ is the name of the country. Rename it to ‘Country’ for making it understandable.
df.rename(columns={'OdName':'Country'}, inplace=True)
Now, make a column ‘Total’ that will be the sum of the immigrants from all the years for each country.
df['Total'] = df.sum(axis=1)

Look, we have the ‘Total’ column at the end. It gives the total number of immigrants for each country.
Remember that setting this axis as 1 is important. It says that the sum operation should be across columns. Otherwise, it will do the sum across rows and we will end up getting the total number of immigrants per year instead of per country.
Basic Choropleth Map
I am going to show, how to develop a choropleth map step by step here. Import folium. If you do not have folium, install it by running this command in your anaconda prompt:
conda install -c conda-forge folium
Import folium now and generate a world map.
import folium
world = folium.Map(location=[0,0], zoom_start=2)

Now in this world map, we will set our data. But it also requires geo data that contains coordinates of each country. Download the geo data from this link. I already downloaded and put it in the same folder as the notebook I used for this tutorial. I just need to read that file now.
wc = r'world-countries.json'
For this choropleth map, you need to pass on
- the geo_data that we saved as ‘wc’ above,
- dataset,
- columns we need to use from the dataset,
- ‘key_on’ parameter that comes from the geo_data. The value of the ‘key_on’ parameter always starts with ‘feature’. Then we need to add the key from the geo_data that we saved as ‘wc’. That JSON file is too big. So, I am showing a part of it to explain the key_on parameter:
{"type":"Feature","properties":{"name":"Afghanistan"},"geometry":{"type":"Polygon","coordinates":[[[61.210817,35.650072],[62.230651,35.270664],[62.984662,35.404041],[63.193538,35.857166],[63.982896,36.007957],[64.546479,36.312073],[64.746105,37.111818],[65.588948,37.305217],[65.745631,37.661164],[66.217385,37.39379],[66.518607,37.362784],[67.075782,37.356144],[67.83,37.144994],[68.135562,37.023115],[68.859446,37.344336],[69.196273,37.151144],[69.518785,37.608997],[70.116578,37.588223],[70.270574,37.735165],[70.376304,38.138396],[70.806821,38.486282],[71.348131,38.258905],[71.239404,37.953265],[71.541918,37.905774],[71.448693,37.065645],[71.844638,36.738171],[72.193041,36.948288],[72.63689,37.047558],[73.260056,37.495257],[73.948696,37.421566],[74.980002,37.41999],[75.158028,37.133031],[74.575893,37.020841],[74.067552,36.836176],[72.920025,36.720007],[71.846292,36.509942],[71.262348,36.074388],[71.498768,35.650563],[71.613076,35.153203],[71.115019,34.733126],[71.156773,34.348911],[70.881803,33.988856],[69.930543,34.02012],[70.323594,33.358533],[69.687147,33.105499],[69.262522,32.501944],[69.317764,31.901412],[68.926677,31.620189],[68.556932,31.71331],[67.792689,31.58293],[67.683394,31.303154],[66.938891,31.304911],[66.381458,30.738899],[66.346473,29.887943],[65.046862,29.472181],[64.350419,29.560031],[64.148002,29.340819],[63.550261,29.468331],[62.549857,29.318572],[60.874248,29.829239],[61.781222,30.73585],[61.699314,31.379506],[60.941945,31.548075],[60.863655,32.18292],[60.536078,32.981269],[60.9637,33.528832],[60.52843,33.676446],[60.803193,34.404102],[61.210817,35.650072]]]},"id":"AFG"}
In the properties key, we have the name of the country. That’s what we need to pass on. So, the value of the key_on parameter will be ‘feature.properties.name’.
5. I will also use some styling parameters: fill_color, fill_opacity, line_opacity, and legend_name. I think these are self-explanatory.
Here is the code for our first choropleth map:
world.choropleth(geo_data=wc,
data=df,
columns=['Country', 'Total'],
key_on='feature.properties.name',
fill_color='YlOrRd',
fill_opacity=0.8,
line_opacity=0.2,
legend_name='Immigration to Canada'
)
world

This map is interactive! You can navigate around using the mouse. Also, it changes the color with intensity. The darker the color, the more immigrants came from that country to Canada. But black means there is no data available or there were no immigrants.
Add Tiles
This map may look a bit plane. We can use tiles to make it look more interesting:
world_map = folium.Map(location=[0, 0], zoom_start=2, tiles='stamenwatercolor')
world_map.choropleth(geo_data=wc,
data=df,
columns=['Country', 'Total'],
threshold_scale=threshold_scale,
key_on='feature.properties.name',
fill_color='YlOrRd',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='Immigration to Canada'
)

Isn’t it better looking! We can make it more interesting by using a few tiles which will give us options to change the tiles based on the requirement. We will use folium’s TileLayer method to add the different layers of tiles on the map. In the end, we will also include the LayerControl method to get the option of altering the layers.
world = folium.Map(location=[0, 0], zoom_start=2, tiles='cartodbpositron')
tiles = ['stamenwatercolor', 'cartodbpositron', 'openstreetmap', 'stamenterrain']
for tile in tiles:
folium.TileLayer(tile).add_to(world)
world.choropleth(
geo_data=wc,
data=df,
columns=[‘Country’, ‘Total’],
threshold_scale=threshold_scale,
key_on=’feature.properties.name’,
fill_color=’YlOrRd’,
fill_opacity=0.7,
line_opacity=0.2,
legend_name=’Immigration to Canada’,
smooth_factor=0
)
folium.LayerControl().add_to(world)
world

Look, underneath the right corner of legend, there is a stack of tiles. If you click on that you will get the list of tiles. You will be able to change the tiles style there. I find this option very cool!
Add Informative Label
Finally, I want to show you another useful and interesting option. That is to use an informative label. We cannot expect everyone to know the name of the country by looking at the map. It will be useful to have the label of the country on the map. We will make it interesting. Folium has a function called ‘GeoJsonTooltip’ that does that. First, we need to make the world map as usual. Add all the parameters to it and save in a variable. Then add this additional feature using ‘GeoJsonTooltip’ with an add_child method. Here is the complete code.
world = folium.Map(location=[0,0], zoom_start=2, tiles='cartodbpositron') choropleth = folium.Choropleth(geo_data=wc, data=df, columns=['Country', 'Total'], threshold_scale=threshold_scale, key_on='feature.properties.name', fill_color='YlOrRd', fill_opacity=0.7, line_opacity=0.2, legend_name='Immigration to Canada', ).add_to(world)choropleth.geojson.add_child( folium.features.GeoJsonTooltip(['name'], labels=False)) world

Notice, I put the cursor on France, it shows the name France. The same way you can put the cursor in any place of the map get the name of the place.
Conclusion
I wanted to show how to develop an interactive choropleth map, style it, and add informative labels to it. I hope it was helpful.
#python #datascience #datavisualization #DataAnalytics #dataAlatises #ChoroplethMap