Updated On : Oct-12,2021 Tags geoviews, scatter-maps, bubble-maps
Geoviews - Scatter & Bubble Maps [Python]

Geoviews - Scatter & Bubble Maps

Geoviews is a Python library that lets us plot our geospatial data on Maps. It let us create maps like choropleth maps, scatter maps, bubble maps, etc. Geoviews is built on the top of the library named holoviews. It let us declare metadata about our map and then uses this metadata to create maps. It does not create maps on its own, instead, it uses one of the bokeh or matplotlib as a backend to create maps. We can set whichever backend we want to use using geoviews and then it'll create maps using that backend. The maps created using bokeh will be interactive maps whereas the ones create with matplotlib will be static maps. As a part of this tutorial, we'll explain with simple examples how we can create scatter and bubble maps using geoviews. We'll be using datasets available from geopandas and a few from the internet to create maps in our tutorial. We have already covered the tutorial on creating choropleth maps using geoviews. Please check the below link if you want to create choropleth maps.

If you are interested in learning about holoviews on which geoviews is based then please check our tutorial on it. It'll help you with this tutorial as well.

We'll now start our tutorial by importing geoviews and printing the version of it.

In [2]:
import geoviews

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

We'll first load a few datasets, to begin with. We'll be merging a few of these datasets as per our need to create maps.

The first dataset that we have loaded below is the world geometry dataset available from geopandas. It's an object of type GeoDataFrame which has information about the geometry of each country of the world. It has information about polygon/multi-polygon objects for each country of the world which will be used to plot countries on the map. We'll be using this dataset to create a world map and then plot points/bubbles on it.

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

In [3]:
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[3]:
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. Apart from the happiness score, it has information like GDP per capita, life expectancy, social support, freedom, generosity, and perception of corruption. This dataset does not have geometry information hence it'll be loaded as simple pandas dataframe. This dataframe will be merged with other geo data frames to add information of this dataframe to them. The dataset can be downloaded from the below link.

In [4]:
import pandas as pd

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

happiness.head()
Out[4]:
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

The third dataset that we have loaded has information about stores of Starbucks worldwide. It has Longitude and Latitude of each store. Apart from this, it has information like store name, address, city, state, country, postcode, phone number, etc. We have loaded this dataset as simple pandas dataframe. The dataset can be downloaded from the below link.

In [5]:
starbucks = pd.read_csv("datasets/starbucks_store_locations.csv")

starbucks.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

Scatter Maps

In this section, we'll explain how we can create scatter maps using geoviews. We have first set backend as bokeh using extension() method of geoviews. We can use the same method if we want to use matplotlib as a backend for our maps.

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

Geoviews - Scatter & Bubble Maps

Starbucks Store Locations Worldwide Scatter Map

Our first scatter map shows locations of Starbucks stores on the world map. In order to create a world map, we have used Polygons() method. We have given it the world geo dataframe that we had loaded earlier using geopandas. This will create an empty world map. We have explained in detail how Polygons() method work in our tutorial on choropleth maps using geoviews.

In order to plot points on the map showing locations of Starbucks stores, we need to use Points() method of geoviews. Below we have given a definition of the method for explanation purposes.


  • Points(data,kdims=[],vdims=[],**kwargs) - This method accepts normal pandas dataframe or geo dataframe along with other parameters and creates points on locations based on parameters settings.
    • The data parameter can take normal pandas dataframe which has latitude and longitude columns or geopandas GeoDataFrame which has Point objects (representing location on map) in geometry column.
    • The kdims parameter accepts a list of two strings where the first string is column name from the dataframe where Longitude information is present and the second string is where Latitude information is present. The points will be drawn at those locations. If we have given GeoDataFrame where geometry column has shapely Point objects in them then we can ignore this parameter as that column's data will be used to plot points on a map.
    • The vdims parameter accepts a list of strings as input which are column names in the dataframe. The first string column name will be used to decide the sizes of points on a map and all other columns will be used to show data in a tooltip when the mouse hovers over the point.

After creating a world map using Polygons() method, we have created the plot of points using Points() method by giving it the Starbucks dataset that we loaded earlier. We have asked it to use Longitude and Latitude columns for kdims parameter and Store Name and City columns for vdims parameter. As Store Name is a column with string values, all points will be of the same size.

We have then merged the world map created using Polygons() with points plot created using Points() using simple multiplication. This is the standard way of combining more than one plot in library holoviews on top of which geoviews is built. We recommend that you go through our tutorial on holoviews to understand this if you don't have a background on this.

Apart from creating a map, we have set modified various map attributes like height, width, title, points color, points size, opacity, etc. We have done that in two ways. Holoviews lets us modify various attributes of maps in two ways.

  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 or Points 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 Points by giving a list of parameters and their values one after another. There is no distinction like %%opts cell magic command here.

In our example, we have specified Polygons options using cell magic command and Points options using opts() method. In our upcoming examples, we'll give Points options also using cell magic commands. It's a choice of the developer which method he/she wants to use.

In [ ]:
%%opts Polygons [height=600 width=900 tools=["hover", ] title="Starbucks Stores Worldwide"] (color="lightgrey")

world_map = geoviews.Polygons(world)

points_on_map = geoviews.Points(starbucks,
                                kdims=["Longitude", "Latitude"],
                                vdims=["Store Name", "City"]).opts(color="tomato",
                                                           size=5,
                                                           alpha=0.1,
                                                           line_color="black",
                                                           hover_color="lime",
                                                           tools=["hover", ]
                                                        )

world_map * points_on_map

Geoviews - Scatter & Bubble Maps

Starbucks Stores Worldwide Scatter Map (CartoMidnight Tile)

In this example, we have again created Starbucks stores scatter map but this time we have created a background map using tile service provided by bokeh. 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.

Below we have created points using Points() method like our previous example. We have then merged this point object with CartoMidnight tile using star operation. There are various tiles available through geoviews.tile_sources module. We can retrieve a list of all possible available tiles using geoviews.tile_sources.tile_sources command.

Please make a NOTE that we have set a few options of Points using cell magic command this time.

In [ ]:
%%opts Points [height=600 width=900 title="Starbucks Stores Worldwide"]

points_on_map = geoviews.Points(
                                starbucks,
                                kdims=["Longitude", "Latitude"],
                                vdims=["Store Name", "City"],
                        ).opts(color="tomato",
                               size=5,
                               alpha=0.1,
                               line_color="black",
                               hover_color="lime",
                               tools=["hover", ]
                        )


points_on_map * geoviews.tile_sources.CartoMidnight()

Geoviews - Scatter & Bubble Maps

Starbucks Store Locations Across India

In this example, we have created a scatter map showing Starbucks store locations across India. We have created points on a map using Points() method by giving it a filtered Starbucks dataframe where only entries for India are present. All of the remaining code is almost the same as our previous examples. This time we have used Wikipedia tile for showing the background map as it has little more information.

In [ ]:
%%opts Points [height=700 width=900 title="Starbucks Stores India"]

points_on_map = geoviews.Points(
                                starbucks[starbucks["Country"] == "IN"],
                                kdims=["Longitude", "Latitude"],
                                vdims=["Store Name", "City"],
                        ).opts(color="tomato",
                               size=15,
                               alpha=0.1,
                               line_color="black",
                               hover_color="lime",
                               tools=["hover", ]
                        )


points_on_map * geoviews.tile_sources.Wikipedia()

Geoviews - Scatter & Bubble Maps

Bubble Maps

Now, we'll explain how we can create a bubble map which is just a scatter map with points of different sizes to represent another dimension of data.

2018 US Population Bubble Map

The first bubble map that we have created shows the population of US states on the US map. In order to create this map, we have loaded and merged a few datasets.

Below we have loaded the first GeoJson dataset which has geometry about the shape of each US state. We have loaded the GeoJSON file using geopandas. The final resulting dataset is geopandas GeoDataFrame where geometry column holds polygon/multi-polygon objects representing individual states of US.

In [26]:
us_states = gpd.read_file("datasets/us-states.json")

us_states.head()
Out[26]:
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...

Below we have written a small function named calculate_center() which takes GeoDataFrame as input and returns center of each Polygon/MultiPolygon object present in geometry column of dataframe. We have used this function to retrieve the center of each state of the US. We have also retrieved Longitude and Latitude of the center of each state.

In [27]:
def calculate_center(df):
    """
    Calculate the centre of a geometry

    This method first converts to a planar crs, gets the centroid
    then converts back to the original crs. This gives a more
    accurate
    """
    original_crs = df.crs
    planar_crs = 'EPSG:3857'
    return df['geometry'].to_crs(planar_crs).centroid.to_crs(original_crs)

us_states["center"] = calculate_center(us_states)
us_states["Longitude"] = [val.x for val in us_states.center]
us_states["Latitude"] = [val.y for val in us_states.center]

us_states.head()
Out[27]:
id name geometry center Longitude Latitude
0 AL Alabama POLYGON ((-87.35930 35.00118, -85.60667 34.984... POINT (-86.82705 32.81439) -86.827048 32.814386
1 AK Alaska MULTIPOLYGON (((-131.60202 55.11798, -131.5691... POINT (-152.52500 65.00297) -152.525004 65.002968
2 AZ Arizona POLYGON ((-109.04250 37.00026, -109.04798 31.3... POINT (-111.66516 34.33632) -111.665157 34.336315
3 AR Arkansas POLYGON ((-94.47384 36.50186, -90.15254 36.496... POINT (-92.43914 34.91573) -92.439137 34.915733
4 CA California POLYGON ((-123.23326 42.00619, -122.37885 42.0... POINT (-119.68388 37.38770) -119.683878 37.387697

Below we have loaded US 2018 population from a CSV file using pandas.

In [28]:
us_pop = pd.read_csv("datasets/State Populations.csv")

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

Now, we have merged the US state’s geo dataframe with the US population dataframe. We have removed geometry and center columns from the resulting dataframe as well. The resulting dataframe will have the population as well as the Longitude and Latitude of the center of each state. We'll be using this final dataframe for creating a bubble map.

In [29]:
us_states_pop = us_states.merge(us_pop, left_on="name", right_on="State").drop(columns=["geometry", "center"])

us_states_pop.head()
Out[29]:
id name Longitude Latitude State 2018 Population
0 AL Alabama -86.827048 32.814386 Alabama 4888949
1 AK Alaska -152.525004 65.002968 Alaska 738068
2 AZ Arizona -111.665157 34.336315 Arizona 7123898
3 AR Arkansas -92.439137 34.915733 Arkansas 3020327
4 CA California -119.683878 37.387697 California 39776830

At last, we have created a bubble map showing the population of US states in 2018 using Points() method by giving it the merged dataframe that we created earlier. We have set a few options of char using cell magic command and a few using opts() method.

We have merged the points chart with Wikipedia tile to create the final US population bubble map.

In [ ]:
%%opts Points [width=900 height=650 title="2018 US Population Statewise" tools=["hover", ]]
%%opts Points (color="dodgerblue" hover_color="lime" line_color="black")

import numpy as np

us_pop_points = geoviews.Points(
                                us_states_pop,
                                kdims=["Longitude", "Latitude"],
                                vdims=["2018 Population", "State"]
                            ).opts(
                                size=np.sqrt(geoviews.dim('2018 Population'))*0.006,
                            )

us_pop_points * geoviews.tile_sources.Wikipedia()

Geoviews - Scatter & Bubble Maps

GDP Of World Countries Bubble Map

In this example, we have created a bubble map showing the GDP of various countries on the world map. In order to create this map, we have loaded and merged a few datasets which we'll explain next.

Below we have merged the world geo dataset with the world happiness dataset, both of which we had loaded at the beginning of the tutorial.

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

world_happiness.head()
Out[30]:
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

Now, we have retrieved the center of each country of the world using calculate_center() method which we had created earlier. We have also retrieved the longitude and latitude of the center of each country.

In [31]:
world_happiness["center"] = calculate_center(world_happiness)
world_happiness["Longitude"] = [val.x for val in world_happiness.center]
world_happiness["Latitude"] = [val.y for val in world_happiness.center]

world_happiness.head()
Out[31]:
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 center Longitude Latitude
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 POINT (34.75848 -6.27836) 34.758476 -6.278363
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 POINT (-96.99822 67.99064) -96.998220 67.990636
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 POINT (-119.45018 51.26001) -119.450184 51.260007
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 POINT (67.31752 48.46973) 67.317523 48.469726
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 POINT (63.12119 41.82781) 63.121190 41.827806

Below we have first created bubbles of map using Points() method giving it world happiness merged dataframe which we created in the previous step. While giving the geo dataframe, we have removed geometry and center columns to avoid confusion and errors. We have asked the method to use Longitude and Latitude columns for drawing bubbles and use gdp_md_est column to decide bubble size.

We have set various options of chart using %%opts cell magic command and opts() method.

At last, we have merged the point chart that we created with EsriNatGeo tile to create the final bubble map. The map background comes from the tile.

In [ ]:
%%opts Points [width=900 height=650 title="GDP of Countries"]

world_gdp = geoviews.Points(
                                world_happiness.drop(columns=["geometry", "center"]),
                                kdims=["Longitude", "Latitude"],
                                vdims=["Country or region", "gdp_md_est"]
                            ).opts(
                                color="tomato",
                                size=np.sqrt(geoviews.dim('gdp_md_est'))*0.01,
                                tools=["hover",],
                                hover_color="lime",
                                line_color="black"
                            )

world_gdp * geoviews.tile_sources.EsriNatGeo()

Geoviews - Scatter & Bubble Maps

Starbucks US Stores Count Bubble Map

The last bubble map that we'll create will show the number of Starbucks stores per US state. The size of the bubble will be based on the number of stores in that state. In order to create this map, we have modified and merged a few datasets which we have loaded earlier.

First, we have filtered our original Starbucks dataset to keep only entries where the country is the US. We have then retrieved the count of stores per US state by using the grouping functionality of pandas. The final dataframe will have code for each state and store count.

In [32]:
starbucks_us = starbucks[starbucks["Country"] == "US"]

starbucks_us_state_cnt = starbucks_us.groupby("State/Province").count()[["Store Number"]].reset_index().rename(columns={"Store Number":"Store Count"})

starbucks_us_state_cnt.head()
Out[32]:
State/Province Store Count
0 AK 49
1 AL 85
2 AR 55
3 AZ 488
4 CA 2821

Now we have merged the US state’s geo dataset (US Population Bubble Map Section) which we had created earlier with the state's store count dataset from the previous cell. The resulting merged dataset will have the longitude and latitude of the center of each US state and Starbucks store count as well. We'll be using this dataset for the creation of our last bubble map.

In [33]:
starbucks_us_statewise = us_states_pop.merge(starbucks_us_state_cnt, left_on="id", right_on="State/Province")

starbucks_us_statewise.head()
Out[33]:
id name Longitude Latitude State 2018 Population State/Province Store Count
0 AL Alabama -86.827048 32.814386 Alabama 4888949 AL 85
1 AK Alaska -152.525004 65.002968 Alaska 738068 AK 49
2 AZ Arizona -111.665157 34.336315 Arizona 7123898 AZ 488
3 AR Arkansas -92.439137 34.915733 Arkansas 3020327 AR 55
4 CA California -119.683878 37.387697 California 39776830 CA 2821

Below we have first created a bubbles chart using Points() method by giving it a merged dataframe from our previous cell. We have then merged this bubbles chart with Wikipedia tile to bring the map background into the chart. As usual, we have set various chart options using the cell magic command and opts() method.

In [ ]:
%%opts Points [width=900 height=650 title="Starbucks US Stores Count Statewise" tools=["hover", ]]
%%opts Points (color="green" hover_color="lime" line_color="black" alpha=0.5)

us_pop_points = geoviews.Points(
                                starbucks_us_statewise,
                                kdims=["Longitude", "Latitude"],
                                vdims=["State", "Store Count"]
                            ).opts(
                                size=geoviews.dim("Store Count") * 0.06,
                            )

us_pop_points * geoviews.tile_sources.Wikipedia()

Geoviews - Scatter & Bubble Maps



Sunny Solanki  Sunny Solanki