Bubble map with Folium in Python

logo of a chart:BubbleMap

Folium is a Python library based on Leaflet.js JavaScript library. It allows us to create maps in the style of Google Maps with an additional layer of customization.

This post will explain how to use Folium to create bubble maps, a kind of chart where background maps are combined with individual points that represent events or physical objects that have a certain latitude and longitude.

For an introduction to Folium, check this post.
For an introduction to bubble map in Folium, check this post.

Libraries & Data

For creating this chart, we will need to load the following libraries:

  • folium for plotting the chart
  • pandas for loading the data
  • numpy for some calculations
import folium
from folium import plugins
import pandas as pd
import numpy as np

Dataset

Let's start by loading shape data:

url = "https://raw.githubusercontent.com/holtzy/The-Python-Graph-Gallery/master/static/data/earthquakes.csv"
df = pd.read_csv(url)
df = df[df['Depth (km)'] >= 0.01]  # depth of at least 10 meters
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

Custom bubble style

The main steps to create a bubble map with folium are:

  • initiate the map with folium.Map()
  • iterate over each rows to add each individual point with folium.CircleMarker()

In order to make each point better looking, in the CircleMarker(), we:

  • change radius to the value in row['Depth (km)']
  • change the color depending on the magnitude with: color = '#0a9396' if row['Magnitude'] < 4 else '#ee9b00' if row['Magnitude'] < 6 else '#ae2012'
  • change the opacity with fill_opacity
  • change border width with weight
# Initialize map
m = folium.Map(
    location=[0, 0],  # center around Africa
    zoom_start=2,  # dezoom
    tiles='cartodb positron'  # background style
)

# Add all the individual earthquakes to the map
for idx, row in df.iterrows():
    color = '#0a9396' if row['Magnitude'] < 4 else '#ee9b00' if row['Magnitude'] < 6 else '#ae2012'
    folium.CircleMarker(
        location=[row['Latitude'], row['Longitude']],
        radius=np.log(row['Depth (km)']) * 2,
        color=color,
        fill=True,
        fill_color=color,
        fill_opacity=0.5,
        weight=1
    ).add_to(m)

m.save('../../static/interactiveCharts/593-customize-bubble-map-with-folium-1.html')
%%html
<iframe
  src="../../interactiveCharts/593-customize-bubble-map-with-folium-1.html"
  width="790"
  height="600"
  title="Folium map"
  style="border: none"
>
</iframe>

Tooltip

An interactive map without a tooltip wouldn't be very effective!

Luckily, with the tooltip argument, customizing it is straightforward, and we can even incorporate some HTML into it.

For instance, we can display the Location, Magnitude, Depth, and Date, wrap them in <b> tags for boldness, and set them as level 5 headings (<h5>).

# Initialize map
m = folium.Map(
    location=[0, 0],
    zoom_start=2,
    tiles='cartodb positron'
)

# Add all the individual earthquakes to the map
for idx, row in df.iterrows():
    tooltip_text = f"""
   <h5><b>Location:</b> {row['Region']}</h5>
   <h5><b>Magnitude:</b> {row['Magnitude']}</h5>
   <h5><b>Depth:</b> {row['Depth (km)']} km</h5>
   <h5><b>Date:</b> {row['Date']}</h5>
   """
    color = '#0a9396' if row['Magnitude'] < 4 else '#ee9b00' if row['Magnitude'] < 6 else '#ae2012'
    folium.CircleMarker(
        location=[row['Latitude'], row['Longitude']],
        radius=np.log(row['Depth (km)']) * 2,
        color=color,
        fill=True,
        fill_color=color,
        fill_opacity=0.5,
        weight=1,
        tooltip=folium.Tooltip(tooltip_text, sticky=True)
    ).add_to(m)

m.save('../../static/interactiveCharts/593-customize-bubble-map-with-folium-2.html')
%%html
<iframe
  src="../../interactiveCharts/593-customize-bubble-map-with-folium-2.html"
  width="790"
  height="600"
  title="Folium map"
  style="border: none"
>
</iframe>

Automatically cluster points

folium comes with a set of plugins to add new features super easily!

For example here we use the MarkerCluster() plugin to automatically cluster the marker into groups when zooming-out.

And in order for this to work: we add the markers to the map with .add_to(marker_cluster) instead of .add_to(m)

from folium import plugins

# Initialize map
m = folium.Map(
    location=[0, 0],
    zoom_start=2,
    tiles='cartodb positron'
)

# Add earthquake data with clustering
marker_cluster = plugins.MarkerCluster().add_to(m)

# Add all the individual earthquakes to the map
for idx, row in df.iterrows():
    tooltip_text = f"""
   <h5><b>Location:</b> {row['Region']}</h5>
   <h5><b>Magnitude:</b> {row['Magnitude']}</h5>
   <h5><b>Depth:</b> {row['Depth (km)']} km</h5>
   <h5><b>Date:</b> {row['Date']}</h5>
   """
    color = '#0a9396' if row['Magnitude'] < 4 else '#ee9b00' if row['Magnitude'] < 6 else '#ae2012'
    folium.CircleMarker(
        location=[row['Latitude'], row['Longitude']],
        radius=np.log(row['Depth (km)']) * 2,
        color=color,
        fill=True,
        fill_color=color,
        fill_opacity=0.7,
        weight=0.4,
        tooltip=folium.Tooltip(tooltip_text, sticky=True)
    ).add_to(marker_cluster)

m.save('../../static/interactiveCharts/593-customize-bubble-map-with-folium-3.html')
%%html
<iframe
  src="../../interactiveCharts/593-customize-bubble-map-with-folium-3.html"
  width="790"
  height="600"
  title="Folium map"
  style="border: none"
>
</iframe>

Going further

You might be interested in:

Contact & Edit


👋 This document is a work by Yan Holtz. You can contribute on github, send me a feedback on twitter or subscribe to the newsletter to know when new examples are published! 🔥

This page is just a jupyter notebook, you can edit it here. Please help me making this website better 🙏!