About
A bubble map is a map combined with a scatter plot where the size of each bubble corresponds to specific numerical values. In the example below, the map illustrates earthquake locations globally, with the bubble size representing their depth.
This chart has been created by Joseph Barbier. Thanks to him for accepting sharing its work here!
As a teaser, here is the plot we’re gonna try building:
Libraries
First, we need to install the following libraries:
- matplotlib and
geoplot
: for creating the plot - pandas and
geopandas
: for data manipulation - highlight_text: for annotations
geoplot
andcartopy
for geospatial manipulation
# data manipulation
import numpy as np
import pandas as pd
import geopandas as gpd
# visualization
import matplotlib.pyplot as plt
from matplotlib import font_manager
from matplotlib.font_manager import FontProperties
from highlight_text import fig_text, ax_text
from matplotlib.patches import FancyArrowPatch
# geospatial manipulation
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import geoplot
import geoplot.crs as gcrs
Dataset
In order to create a bubble map, we need 2 kind of datasets:
- a dataset with country shapes, that we load with the following code:
proj = ccrs.Mercator()
url = "https://raw.githubusercontent.com/holtzy/The-Python-Graph-Gallery/master/static/data/all_world.geojson"
world = gpd.read_file(url)
world = world[~world['name'].isin(["Antarctica", "Greenland"])]
world = world.to_crs(proj.proj4_init)
world.head()
name | geometry | |
---|---|---|
0 | Fiji | MULTIPOLYGON (((20037508.343 -1800679.237, 200... |
1 | Tanzania | POLYGON ((3774143.866 -105050.440, 3792946.708... |
2 | W. Sahara | POLYGON ((-964649.018 3185897.152, -964597.245... |
3 | Canada | MULTIPOLYGON (((-13674486.249 6242596.000, -13... |
4 | United States of America | MULTIPOLYGON (((-13674486.249 6242596.000, -13... |
-
- a dataset with latitude and longitude values, and another numerical column:
#Load data
url = "https://raw.githubusercontent.com/holtzy/The-Python-Graph-Gallery/master/static/data/earthquakes.csv"
df = pd.read_csv(url)
# Filter dataset: big earth quakes only
df = df[df['Depth (km)']>=0.01] # depth of at least 10 meters
# Sort: big bubbles must be below small bubbles for visibility
df.sort_values(by='Depth (km)', ascending=False, inplace=True)
df.head()
Date | Time (utc) | Region | Magnitude | Depth (km) | Latitude | Longitude | Mode | Map | year | |
---|---|---|---|---|---|---|---|---|---|---|
7961 | 20/02/2019 | 06:50:47 | Banda Sea | 5.0 | 2026 | -6.89 | 129.15 | A | - | 2019.0 |
6813 | 07/07/2019 | 07:50:53 | Eastern New Guinea Reg, P.N.G. | 5.4 | 1010 | -5.96 | 147.90 | A | - | 2019.0 |
8293 | 17/01/2019 | 14:01:50 | Fiji Islands | 4.7 | 689 | -18.65 | 179.44 | A | - | 2019.0 |
11258 | 03/01/2018 | 06:42:58 | Fiji Islands Region | 5.5 | 677 | -19.93 | -178.89 | A | - | 2018.0 |
9530 | 06/09/2018 | 18:22:24 | Fiji Islands Region | 5.8 | 672 | -18.88 | 179.30 | A | - | 2018.0 |
Simple background map
We start this reproduction by creating the most simple background map possible. It only uses the world
dataset:
proj = ccrs.Mercator()
fig, ax = plt.subplots(figsize=(12, 8), dpi=300, subplot_kw={'projection':proj})
ax.set_axis_off()
# background map
world.boundary.plot(ax=ax)
plt.show()