Interactive Choropleth Maps

Interactive Maps help to display, understand and relate with the datasets containing geospatial components.

These interactive and well-visualized maps help to dive deeper into the insights of available datasets and learn its susceptibility with respect to the surrounding geography.

Maps with good visualization give a perspective to look at the dataset which is inlined with the geography of the area. For example, the population at the center of the city is generally much higher than its peripheral area.

Unlike traditional maps, digital maps have the capability which links datasets attribute information to the layer which is being visualized. For example, an electric network feature can be linked to maintenance videos.

Creating a visual summary of the dataset to showcase in one glance is one of the best skill set to possess. In this article, we will look at simple steps to create Interactive choropleth Maps using python.

What are we going to visualize?

Answer to the above question is the Population of a city! For this, I have referred to the dataset from Datameet please check out the given link for amazing spatial data of Indian municipalities with respect to the census 2011.

From the given link, I have downloaded Bangalore’s dataset i.e. geojson file for this tutorial. You can go ahead and choose your own dataset.

Are you aware of Geopandas and Folium?

Geopandas: Python has a library named geopandas it extends the datatypes used by pandas to allow spatial operations on geometric types. GIS vector datasets such as shapefiles, geojson formats can be explored and spatial analysis can be performed using geopandas

Folium is a python library built on top of well known Leaflet.js, It possesses rich overlay capacities with built-in tilesets OpenStreetMap, Mapbox, and Stamen, and supports custom tilesets with Mapbox or Cloudmade API keys.

Step:1. Explore your data

For any data to be visualized it is very important for the programmer to explore the data. I have given some basic exploration limited to the visualization of the map. Before visualizing the datasets we must know about the attribute information which we want to link to our map. Following a few steps will help to know about your dataset and choose the attribute we want to showcase.

For this article, I am considering the population of the wards. the column name “WARD_NAME” gives the name of the ward and “POP_TOTAL” give a total population of that ward.

Please remember The “geometry” column is polygon showing the boundary of respective wards on the map. No map can be shown without having specified geometry

In [2]:
# import libraries
import geopandas as gpd
import folium
from branca.colormap import linear  # for colorbrewer

Let’s see how we can read the downloaded geojson file and print information about few rows

Geopandas has a read_file(‘path’) function which reads the geojson or geodataframe saved in a given path

.head() function allows user to print first few rows of the dataset

In [3]:
#reading dataset

gdf= gpd.read_file('data/BBMP.GeoJSON')
gdf.head()
Out[3]:
OBJECTID
ASS_CONST_
ASS_CONST1
WARD_NO
WARD_NAME
POP_M
POP_F
POP_SC
POP_ST
POP_TOTAL
AREA_SQ_KM
LAT
LON
RESERVATIO
geometry
0
1
150
Yelahanka
2.0
Chowdeswari Ward
10402.0
9224.0
2630.0
286.0
19626.0
7.06
13.121709
77.580422
General
MULTIPOLYGON (((77.59229 13.09720, 77.59094 13...
1
2
150
Yelahanka
3.0
Atturu
13129.0
10891.0
2921.0
665.0
24020.0
10.15
13.102805
77.560038
General (Women)
MULTIPOLYGON (((77.56862 13.12705, 77.57064 13...
2
3
150
Yelahanka
4.0
Yelahanka Satellite Town
13457.0
12325.0
3687.0
601.0
25782.0
4.90
13.090987
77.583925
Backward Category - A
MULTIPOLYGON (((77.59094 13.09842, 77.59229 13...
3
4
151
K.R. Puram
51.0
Vijnanapura
18118.0
16969.0
6454.0
228.0
35087.0
2.05
13.006063
77.669565
Scheduled Caste
MULTIPOLYGON (((77.67683 13.01147, 77.67695 13...
4
5
151
K.R. Puram
53.0
Basavanapura
11494.0
10518.0
4115.0
325.0
22012.0
6.28
13.016847
77.715456
General
MULTIPOLYGON (((77.72899 13.02061, 77.72994 13...

We can get the dimension of our data:

By using .shape method it displays the information of the number of rows and number of columns present i.e. total shape of the given data set

In [4]:
#exploring shape 
gdf.shape
Out[4]:
(198, 15)

To know which columns are present and get access to column names instantly we use .columns method

In [5]:
gdf.columns
Out[5]:
Index(['OBJECTID', 'ASS_CONST_', 'ASS_CONST1', 'WARD_NO', 'WARD_NAME', 'POP_M',
       'POP_F', 'POP_SC', 'POP_ST', 'POP_TOTAL', 'AREA_SQ_KM', 'LAT', 'LON',
       'RESERVATIO', 'geometry'],
      dtype='object')

For the representation purpose, geopandas has .plot() method which gives us a plot of geometry column and latitude, longitude

information in the form of x, y-axis to understand the region covered by all the wards of Bangalore city.

In [6]:
gdf.plot()
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f6525491d30>

Can’t wait to see our first folium map?

Our first raw map can be seen by assigning a variable named my_map and give a latitude-longitude of map

( This will be the default location of map tiles). We can add multiple arguments such as zoom level, base map tile, etc using folium

In [7]:
my_map= folium.Map([12.9724, 77.5806], zoom_start=11)

folium.GeoJson(gdf).add_to(my_map)

my_map.save("my_first_map.html")

#my_map                       #display output 
/home/sumedh/anaconda_3/envs/geo_py37/lib/python3.6/site-packages/pyproj/crs.py:77: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method.
  return _prepare_from_string(" ".join(pjargs))

Either we can save it as an HTML map or we can just return the my_map variable to see the output.

In [8]:
from IPython.display import IFrame

IFrame(src='my_first_map.html', width=1280, height=600)
Out[8]:

Step 2: Create a style function using branca python colormap and the dataset

We have used branca library. This library is a spinoff from folium, that would host the non-map-specific features.

The below code shows the linearscale for colors. To create a linear scale between the lowest value of the population to the highest value of population we have used min() and max(). The term linear.YlGn_09.scale shows scale varying from yellow to green color

In [9]:
# exploring branca colormap for display choropleth with colours
from branca.colormap import linear
colormap = linear.YlGn_09.scale(gdf.POP_TOTAL.min(), gdf.POP_TOTAL.max())
print(colormap(6.0))

colormap
#ffffe5

Out[9]:
19287.036582.0
In [10]:
pop_dict=gdf.set_index('WARD_NAME')['POP_TOTAL']
#pop_dict['Atturu']
pop_dict
Out[10]:
WARD_NAME
Chowdeswari Ward            19626.0
Atturu                      24020.0
Yelahanka Satellite Town    25782.0
Vijnanapura                 35087.0
Basavanapura                22012.0
                             ...   
Madivala                    35155.0
Ramamurthy Nagar            21999.0
Horamavu                    28167.0
Marathahalli                22489.0
Hemmigepura                 24311.0
Name: POP_TOTAL, Length: 198, dtype: float64
In [11]:
def style_function(feature):
    pop_d = pop_dict.get(int(feature['id']), None)
    return {
        'fillColor': '#black' if pop_d is None else colormap(pop_d),
        'color': 'black',
        'weight': 1,
        'dashArray': '5, 5',
        'fillOpacity': 0.9,
    }

Step 3: Last step and your choropleth map is ready!

We are using folium function to call geojson file, add our created style function and create a geojson tooltip.

geojson tooltip is used when you want to get the information while hovering over the map

In [15]:
my_map= folium.Map([12.9724, 77.5806], zoom_start=11)

x=folium.GeoJson(
    gdf,
    name='population',
    style_function=style_function,
    highlight_function= None,
    tooltip=(gdf[i] for i in gdf['POP_TOTAL'])
).add_to(my_map)
x.add_child(
folium.features.GeoJsonTooltip(['POP_TOTAL']))
folium.LayerControl().add_to(my_map)

my_map.save('my_choropleth_geojson1.html')

We can give the layer control option (Please check the top right corner of map given below)

We can save the output map as an interactive HTML

In [16]:
from IPython.display import IFrame

IFrame(src='my_choropleth_geojson1.html', width=1280, height=600)
Out[16]:

Happy Mapping!

(2) Comments

Leave A Comment

All fields marked with an asterisk (*) are required