How to create bubble maps in Python with Geospatial data

A beginner’s guide and tutorial.

Photo by Marc Sendra Martorell on Unsplash

Ever thought how you can create bubble maps in Python with Geospatial data? I will show you how you can easily make a bubble maps both in a static format as well as an interactive one.

A bubble map uses size as an encoding variable. The size of the circle represents a numeric value on a Geographic area.

Photo by Marc Sendra Martorell on Unsplash

We often use Choropleth maps to display areas, and in that case, we use a colour encoding. Choropleth maps have an inherent bias problem with large areas. In contrast, bubble maps use circles to represent a numeric value of an area or region.

It often seems to be complicated and a bit advanced feature to create your bubble map in Python, but it is not. It is like creating bubble charts with latitude and longitude columns. Let us first import the libraries we need.

import pandas as pd
import numpy as np
import geopandas as gpd
import matplotlib.pyplot as plt
import plotly_express as px

And we can read the data with Geopandas. With Geopandas, you can read most of the geographic data formats like Shapefile, Geojson, Geo package, etc.. In this example, we are using population data from the city of Mälmo, Sweden.

gdf = gpd.read_file(“data/malmo-pop.shp”)

Here is a glimpse of the first rows of the dataset. We have numerous columns of the population subdivision (Age 5 to age 80 and above) for each administrative unit (Deso).

Photo by Marc Sendra Martorell on Unsplash

We usually use choropleth maps and use a colour encoding. As we are going to see, we can create a choropleth map very easily with Geopandas. Notice that we first normalize the data (Age80_w) by subdividing the total population.

gdf["Age_80_norm"] = (gdf["Age80_w"] / gdf["Total"]) * 100
fig, ax = plt.subplots(figsize=(16,16))
gdf.plot(ax=ax, column="Age_80_norm", cmap="Blues",edgecolor="grey", linewidth=0.4, legend=True)
Photo by Marc Sendra Martorell on Unsplash

Bubble Maps

Alternatively, we can use bubble maps and avoid some of the pitfalls of choropleth maps. For example, we do not need to normalize the data, and we can use the total subdivision of populations. However, we need to do some conversion to the data to be able to create a bubble map.

As you can see, the data we are using are Polygons, and we need points if we want to create bubble maps. That is, however, a simple process with Geopandas. We only need to change the geometry column, in this case, Polygons to Point geometry.

gdf_points = gdf.copy()
gdf_points[‘geometry’] = gdf_points[‘geometry’].centroid

We first copy the Geodataframe with Polygon geometry to a new Geodataframe. As we want to the bubble to be at the centre of the area, we can use centroid function in Geopandas to achieve this.

Now, we have the same Geodataframe with different Geometry column, a Point Geometry. Let us plot a bubble map as we have points dataset now.

fig, ax = plt.subplots(figsize=(16,16))
gdf.plot(ax=ax, color=”lightgray”, edgecolor=”grey”, linewidth=0.4)
gdf_points.plot(ax=ax,color=”#07424A”, markersize=”Age80_w”,alpha=0.7, categorical=False, legend=True )

The map below shows a bubble map for Age 80 and above population in a smaller administrative area in Mälmo, Sweden. Each circle represents a different size based on the subtotal population at the age of 80 and above. To construct a bubble map, you need to provide markersize to the column you want to be mapped, and in this case, the Age80_w.

Photo by Marc Sendra Martorell on Unsplash

As you can see, this is a static map, and often a problem with bubble maps is the overlapping of point circles. One way we can avoid this is to create interactive maps that allow the user to interact with and zoom into an area of interest. In the next section, we are going to see how you can create an interactive bubble map.

Interactive Bubble Maps

There are different Python libraries for plotting interactive bubble maps. To construct an interactive bubble map, we use Plotly Express. We just need to convert to another projection to display the map with Plotly Express. Plotly Express has scatter_mapbox() function which can take a Geodataframe and the column you want to use for the bubble map.

gdf_points_4326 = gdf_points.to_crs(“EPSG:4326”)
fig = px.scatter_mapbox(
                        hover_name = “Age80_w”,

With Plotly Express, we can avoid the overlapping problem of bubble maps by creating an interactive bubble map. See the below GIF.

Photo by Marc Sendra Martorell on Unsplash

Bubble maps can be an alternative map to display a numeric variable with different bubble size, instead of the most used choropleth maps. If you have a list of regions (i.e. administration areas) with values (i.e., age subdivisions), bubble maps can replace Choropleth maps. Bubble maps do not have the inherent big area bias in choropleth maps.


In this tutorial, we have seen how to create both static and interactive bubble maps, using Python. The static bubble maps have an overlapping problem. To avoid it, you can either create interactive maps that allow zoom in/out or increase the transparency of the static map circles.

The code for this tutorial is available in this Github Repository.

Leave a Reply

Your email address will not be published. Required fields are marked *