Share @ LinkedIn Facebook  hvplot, geopandas
hvplot - How to Convert Static Python Maps (Geopandas) to Interactive Maps?

How to Convert Static Maps (Geopandas) to Interactive Maps?

Table of Contents

Introduction

Python library geopandas provides a way to plot geographic spatial data on maps. Geopandas makes use of matplotlib for plotting purposes. All maps generated by geopandas is static. A Scatter plot made with geopandas does not give insights about points if a different size is used for points. We need interactive plots in this kind of situation to look into detail.

If you are a Python developer who has experience plotting maps with geopandas and wants to use the same API for creating interactive maps without learning many new things then this tutorial is for you. Also if you are starting out plotting maps with geopandas then we recommend that you follow this tutorial as it'll guide you about generative interactive graphs from the beginning.

We suggest that you go through our tutorial on plotting maps with geopandas before starting this as it'll help you understand things quicker.

In [1]:
import geopandas
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

import warnings

warnings.filterwarnings('ignore')

geopandas.datasets.available
Out[1]:
['naturalearth_cities', 'naturalearth_lowres', 'nybb']

geopandas has 3 datasets available. naturalearth_lowres and nybb dataset consist of Polygon shapes whereas naturalearth_cities consist of Points shape. We'll try to load the naturalearth_lowres dataset which has information about each country’s shapes. It also holds information about the estimated country population and continent.

In [2]:
world = geopandas.read_file(geopandas.datasets.get_path("naturalearth_lowres"))
print("Geometry Column Name : ", world.geometry.name)
print("Dataset Size : ", world.shape)
world.head()
Geometry Column Name :  geometry
Dataset Size :  (177, 6)
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...

1. Plotting With GeoPandas

We'll now explain plotting various map plots with GeoPandas. We'll also be using world happiness report dataset available from kaggle to include further data for analysis and plotting.

We'll start by just plotting the world dataframe which we loaded above to see results. We can simply call plot() on GeoDataFrame and it'll plot world countries on a map. By default, it'll just print all countries with their borders.

In [ ]:
world.plot(figsize=(12,8));

geopandas static plot

We'll now load our world happiness data. Please feel free to download a dataset from kaggle.

Dataset also holds information about GDP per capita, social support, life expectancy, generosity, and corruption. We'll be merging this dataframe with geopandas world GeoDataFrame which we loaded above to combine data and then use combined data for plotting.

NOTE

Please make a note that the happiness report dataset does not have a happiness report for all countries present on earth. It has data for around 156 countries. We also have manually made changes to the happiness dataset for around 10-15 countries where the country name was mismatching with name present in geopandas geodataframe. We have modified happiness report CSV to have the same country name as that of the geodataframe.

In [3]:
world_happiness = pd.read_csv("datasets/world_happiness_2019.csv")
print("Dataset Size : ",world_happiness.shape)
world_happiness.head()
Dataset Size :  (156, 9)
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
In [4]:
world_happiness_final = world.merge(world_happiness, how="left", left_on=['name'], right_on=['Country or region'])
#world_happiness_final = world_happiness_final.dropna()
print("Type of DataFrame : ", type(world_happiness_final))
world_happiness_final.head()
Type of DataFrame :  <class 'geopandas.geodataframe.GeoDataFrame'>
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 920938 Oceania Fiji FJI 8374.0 MULTIPOLYGON (((180.00000 -16.06713, 180.00000... NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 53950935 Africa Tanzania TZA 150600.0 POLYGON ((33.90371 -0.95000, 34.07262 -1.05982... 153.0 Tanzania 3.231 0.476 0.885 0.499 0.417 0.276 0.147
2 603253 Africa W. Sahara ESH 906.5 POLYGON ((-8.66559 27.65643, -8.66512 27.58948... NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 35623680 North America Canada CAN 1674000.0 MULTIPOLYGON (((-122.84000 49.00000, -122.9742... 9.0 Canada 7.278 1.365 1.505 1.039 0.584 0.285 0.308
4 326625791 North America United States of America USA 18560000.0 MULTIPOLYGON (((-122.84000 49.00000, -120.0000... 19.0 United States of America 6.892 1.433 1.457 0.874 0.454 0.280 0.128

NOTE

Please make a note that while combining normal dataframe to geodataframe we have used geodataframe first in "merge" operation. The main reason for doing so is that it'll output GeoDataFrame as output else it'll output normal pandas dataframe as output without geo functionalities. Please make a note that there will be few "NANs" present in the dataframe because we don't have happiness data for all countries of the world.

1.1 Happiness Choropleth Map

Below we are plotting our first choropleth map by simply calling the plot() method on geopandas GeoDataFrame by passing a column name as the first parameter to use for the map. We can pass other arguments like figsize, edgecolor, edgesize, etc for map. As it is a static matplotlib plot, we can call other matplotlib methods like title(), xlabel(), ylabel(), etc will work on it.

In [ ]:
world_happiness_final.plot("Score",
                           figsize=(18,10),
                           legend=True,
                           legend_kwds={"label":"Happiness by Country"},
                           cmap=plt.cm.Greens,
                          )
plt.title("World Happiness Report");

Geopandas Happiness Choropleth Map

1.2 Scatter Maps

We'll now explain scatter plots on maps with few examples. We'll use starbucks store location data available from kaggle for plotting these graphs. It has information about each Starbucks store locations as well as their address, city, country, phone number, latitude and longitude data.

In [5]:
starbucks_locations = pd.read_csv("datasets/starbucks_store_locations.csv")
starbucks_locations.head()
Out[5]:
Brand Store Number Store Name Ownership Type Street Address City State/Province Country Postcode Phone Number Timezone Longitude Latitude
0 Starbucks 47370-257954 Meritxell, 96 Licensed Av. Meritxell, 96 Andorra la Vella 7 AD AD500 376818720 GMT+1:00 Europe/Andorra 1.53 42.51
1 Starbucks 22331-212325 Ajman Drive Thru Licensed 1 Street 69, Al Jarf Ajman AJ AE NaN NaN GMT+04:00 Asia/Dubai 55.47 25.42
2 Starbucks 47089-256771 Dana Mall Licensed Sheikh Khalifa Bin Zayed St. Ajman AJ AE NaN NaN GMT+04:00 Asia/Dubai 55.47 25.39
3 Starbucks 22126-218024 Twofour 54 Licensed Al Salam Street Abu Dhabi AZ AE NaN NaN GMT+04:00 Asia/Dubai 54.38 24.48
4 Starbucks 17127-178586 Al Ain Tower Licensed Khaldiya Area, Abu Dhabi Island Abu Dhabi AZ AE NaN NaN GMT+04:00 Asia/Dubai 54.54 24.51

Below we are plotting a simple map plot first and then using a scatter plot available in matplotlib to plot all Starbucks locations on it. Please make a note that we have longitude and latitude data for each store available in the dataset which we are utilizing in scatter plot.

In [ ]:
with plt.style.context(("seaborn", "ggplot")):
    world.plot(figsize=(18,10),
               color="white",
               edgecolor = "grey");

    plt.scatter(starbucks_locations.Longitude, starbucks_locations.Latitude, s=15, color="red", alpha=0.3)
    plt.xlabel("Longitude")
    plt.ylabel("Latitude")
    plt.title("Strabucks Store Locations On Earth");

Geopandas Starbucks Locations Scatter Map

2. Converting Static Plots to Interactive

We'll now start converting above static maps to interactive maps using hvplot. We just need to import hvplot's pandas module to start. We then just need to call hvplot() method instead of plot() method on geodatagrame and it'll use holoviews to generate map plots.

In [ ]:
import hvplot.pandas

2.1 World Happiness Choropleth Map

We have below generated simple happiness map which can be generated by just calling hvplot() method passing is column Score to generate an interactive map. We can hover over it to see a score for each country.

In [ ]:
world_happiness_final.hvplot(c="Score",
                             cmap="Oranges")

Hvplot World Happiness Choropleth Map

We can pass other attributes to make changes to graphs like height, width, colormap, title and changing color when hovered over any country.

NOTE

Please make a note that entries where NaNs are present are represented with grey color..

In [ ]:
happiness = world_happiness_final.hvplot(c="Score",
                             cmap="BrBG",
                             hover_fill_color="red",
                             width=900,height=500,
                             title="World Happiness Report",
                            )
happiness

Hvplot World Happiness Choropleth Map

2.2 Healthy Life Expectancy Choropleth Map

Below we have introduced a few more attributes like hover_fill_color, line_width, etc.

In [ ]:
healthy_life = world_happiness_final.hvplot(c= "Healthy life expectancy",
                             width=900,height=500,
                             line_color="Healthy life expectancy",
                             cmap="YlOrRd",
                             hover_fill_color="white",
                             #line_dash="dotted",
                             line_width=2,
                             title="World Healthy life expectancy"
                             )

healthy_life

Hvplot World Healthy Life Expectancy Choropleth Map

2.3 GDP per Capita Choropleth Map

In [ ]:
gdp_per_capita = world_happiness_final.hvplot(c="GDP per capita",
                             width=900,height=500,
                             grid=True,
                             cmap="YlGn",
                             title="World GDP per capita Choropleth"
                             )
gdp_per_capita

Hvplot GDP per Capita Choropleth Map

2.4 Continent Choropleth Map

In [ ]:
world_happiness_final.hvplot(c="continent",
                             width=950,height=500,
                             cmap="Category10",
                             title="World Continent",
                             line_color=None
                             )

Hvplot Continent Choropleth Map

3. Merging Plots

We can generate more complicated graphs by merging more than one graph. Holoviews provides 2 operations to merge graphs.

  • + - It merges graphs by putting them next to each other
  • * - It overlays graphs on one another to create one single graph combining all individuals.

We suggest that you go through our tutorial on basic plotting with holoviews to get an idea about plotting with holoviews.

3.1 Starbucks Stores Location Scatter Map

Below we are creating a scatter map by overlaying scatter plot on a map using * operation.

In [ ]:
world_chart = world.hvplot(color="white",
                           width=900,height=450,
                           title="Starbucks Store Locations")

starbucks =  starbucks_locations.hvplot.points('Longitude', 'Latitude',
                                             color='red',
                                             alpha=0.2)

world_chart * starbucks

Hvplot Starbucks Stores Location Scatter Map

Below we are trying to get a count of Starbucks store for each city by grouping by city. We then take only US cities where a number of Starbucks stores is very high.

In [6]:
cities = ['New York', 'Chicago', 'Seattle', 'Las Vegas', 'Houston', 'San Diego', 'Los Angeles',
          'Portland', 'Phoenix', 'Dallas', 'San Jose', 'Washington', 'San Francisco',
          'San Antonio', 'Denver',  'Richmond', 'Boston', 'Charlotte', 'Austin', 'Boston',
          'Charlotte', 'Austin']

citywise_geo_data = starbucks_locations.groupby("City").mean()[["Longitude","Latitude"]]
citywise_store_cnts = starbucks_locations.groupby("City").count()[["Store Number"]].rename(columns={"Store Number":"Count"})
citywise_store_cnts = citywise_geo_data.join(citywise_store_cnts).sort_values(by=["Count"], ascending=False)
citywise_store_cnts = citywise_store_cnts[citywise_store_cnts.index.isin(cities)]
citywise_store_cnts.head()
Out[6]:
Longitude Latitude Count
City
New York -73.982759 40.753276 232
Chicago -87.679556 41.907333 180
Seattle -122.332051 47.616474 156
Las Vegas -115.200449 36.132756 156
Houston -95.455130 29.795844 154

3.2. US Cities Starbucks Count Scatter Map

Below we are creating another scatter map where we are overlaying city-wise store counts scatter plot on a map of US. We can clearly see a big bubble for New York indicating a very high number of stores there.

In [ ]:
us_chart = world[world["name"] == "United States of America"].hvplot(
                            color="snow",
                            width=400,height=300,
                            title="Starbucks US Stores by Cities")

us_cities =  citywise_store_cnts.hvplot.points(
                                            x='Longitude', y='Latitude',
                                            color='green',
                                            size="Count",
                                            alpha=0.8)

us_chart * us_cities

Hvplot US Cities Starbucks Count Scatter Map

3.3. Social Support, Freedom to Make Life Choices and Corruption Choropleth Map

Below we are merging 3 choropleth using + operations.

In [ ]:
world1 = world_happiness_final.hvplot(c="Social support",
                             cmap="Reds",
                             height=350,
                             title="World Social support Report",
                             line_width=0
                            )

world2 = world_happiness_final.hvplot(c="Freedom to make life choices",
                             cmap="Greens",
                             height=350,
                             title="World Freedom to make life choices Report",
                             line_width=0
                            )

world3 = world_happiness_final.hvplot(c="Perceptions of corruption",
                             cmap="Blues",
                             height=350,
                             title="World Perceptions of corruption Report",
                             line_width=0
                            )

(world1 + world2 +world3).cols(1)

Hvplot Social Support, Freedom to Make Life Choices and Corruption Choropleth Map

3.4 Starbucks Stores Location Scatter Map & World Happiness Choropleth Map

Below we have given another example where we are making use of * and + operations both to create a figure of Starbucks stores location scatter map and world happiness choropleth.

In [ ]:
((world_chart * starbucks) + happiness).cols(1)

Hvplot Starbucks Stores Location Scatter Map & World Happiness Choropleth Map

This ends our small tutorial on creating interactive maps using geopandas. Please feel free to let us know your views.

References



Sunny Solanki  Sunny Solanki