Make beautiful 3D maps with pydeck: deck.gl in Python

Emanuel Zgraggen - November 2nd, 2022

PyDeck is the easiest way to turn GeoJSON into interactive visualizations in Python

Uber’s open source deck.gl is a WebGL-powered framework for visual exploratory data analysis of large datasets.

pydeck lets Python users create deck.gl maps without having to know Javascript and makes it super easy to created stunning 3D map visualizations in Python environments. It integrates well with the stack already used by data professionals such as Pandas.

In this example canvas we take data containing the center points of each zip code of Massachusetts and use pydeck to plot a Column illustrating the number of people living in that zip code. All is fully interactive and you can use your mouse to pan, zoom and pitch them map.

import pydeck as pdk
from urllib.request import urlopen
import json
import pandas as pd
from shapely.geometry import shape
import matplotlib.colors as colors
import matplotlib.cm as cmx
import matplotlib.pyplot as plt

# load massachusetts zip geo json
with urlopen('https://raw.githubusercontent.com/OpenDataDE/State-zip-code-GeoJSON/master/ma_massachusetts_zip_codes_geo.min.json') as response:
    state_geo = json.load(response)

# load data with zip to population mapping
df = pd.read_csv('https://raw.githubusercontent.com/einblick-ai/data/main/mass-zip-population.csv')
df['zip'] = df['zip'].astype(str).str.pad(width=5, side='left', fillchar='0')

# compute centroids of each zip code 
features = state_geo["features"]
centroids = {}
for feature in features:
    s = shape(feature["geometry"])
    centroids[feature['properties']['ZCTA5CE10']] = s.centroid

# map centroid to zip code in the df
df["zip_lat"] = 0
df["zip_lon"] = 0
for index, row in df.iterrows():
    if row["zip"] in centroids:
        df.loc[index, 'zip_lat'] = centroids[row["zip"]].y
        df.loc[index, 'zip_lon'] = centroids[row["zip"]].x

# setup default view box 
view = pdk.data_utils.compute_view(df[["zip_lon", "zip_lat"]])
view.pitch = 75

# create mapping from population to color
plasma = cm = plt.get_cmap('plasma') 
cNorm  = colors.Normalize(vmin=df["population"].min(), vmax=df["population"].max())
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=plasma)
df["color"] = df.apply (lambda row: scalarMap.to_rgba(row["population"]), axis=1)

# create column layer in pydeck
column_layer = pdk.Layer(
    "ColumnLayer",
    data=df,
    get_position=["zip_lon", "zip_lat"],
    get_elevation="population",
    elevation_scale=1,
    radius=300,
    pickable=True,
    get_fill_color="[color[0] * 255, color[1] * 255, color[2] * 255, color[3] * 255]",
    auto_highlight=True,
)

# add tooltip 
tooltip = {
    "html": "<b>{population}</b> people in {zip}",
    "style": {"background": "grey", "color": "white", "font-family": '"Helvetica Neue", Arial', "z-index": "10000"},
}

r = pdk.Deck(
    column_layer,
    initial_view_state=view,
    tooltip=tooltip
)

r.to_html("column_layer.html", notebook_display=True)

Start using Einblick

Pull all your data sources together, and build actionable insights on a single unified platform.

  • All connectors
  • Unlimited teammates
  • All operators