Using plotly.express to make ZIP Code-level choropleth maps

Mm Fuenteslopez
4 min readApr 7, 2022

--

Choropleth map for the 2016 US election

Choropleth maps are a popular tool for visualizing geospatial data. Some of my favorite choropleth maps were used to display crime rates in NYC by zipcode, alcohol preferences in Europe (beer vs. vodka vs. wine), election results by US State, etc.

Using plotly.express’s example and why I decided to write this article

One of the many packages to plot choropleth maps using python is plotly.express.choropleth (follow this link to see the documentation) . The example in plotly’s documentation is giving general guidance on how to plot a FIPS code-level map (this would be at the US county level), however for the purposes of the specific project I needed to work on I needed to visualize data at the ZIP Code level instead.

This map is the one provided by plotly.express.choropleth’s documentation — using county-level data

First couple of road blocks and note to self

The screenshots below are some of the results I came across when trying to find a solution to my problem.

#1 Stack Overflow

Stack Overflow can sometimes be your worst enemy — never be deterred to find a solution by yourself!

#2 plotly community

To make matters even worse — even the plotly community suggested this problem had no solution!

After looking up multiple implementations on Stack Overflow, Github, etc. Everything suggested that plotly.express could only handle plots that were no more granular than county-level maps.

However, after digging deeper into the example provided in the documentation and noticing that plotly.express’s output is fully dependent on coordinates (irrespective of how complex these might be) I realized that the issue at hand was not one of feature/capabilities but instead one of mappings. Note to self — always trust your intuition!

What resources are needed to plot hyper-granular choropleth maps?

As a first step, you will need to find a GeoJSON file that contains all the coordinates (latitude and longitude) for every corner of the polygons of the areas you are trying to map.

See below what this looks like for zip code (12205) in New York State. The example below is using a GeoJSON file that was sourced from the following Github respository. Note: each one of the coordinates in the GeoJSON file below corresponds to a bend/corner in a single ZIP Code.

This implementation favors having all the latitude and longitude coordinates in JSON format.

Assuming you have the features you would want to plot by ZIP Code like in the example below, you may then proceed.

The final plot will have each ZIP Code in the state of New York colored by cluster label (“Cluster”)

I. Base packages to import for this project

First we need to import some essential data analysis libraries

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

II. Then we can import the data for our graph

Import the csv with all the ZIP Code level data into a pandas dataframe

df = pd.read_csv('New_York_State_ZIP_Codes-County_FIPS_Cross-Reference.csv')

III. Finally we can create our Choropleth maps

**Note the ZIP Code GeoJSON repo is linked to this article a bit earlier.

Something really important to note is the following parameter featureidkey=”properties.ZCTA5CE10" it is not necessary to define this parameter all the time, but if the project one is working on has very specific geographic coordinates, one has to specify the field in the GeoJSON file that indexes each set of coordinates.

In this case the field ”ZCTA5CE10” has the purposes of “joining” the coordinates in the GeoJSON to the ZIP Codes in the CSV file. You may now run the code below and should obtain a ZIP Code-level Choropleth map of the State of New York.

df = zipcode_data[['ZIP_Code','County_Name','Cluster']]import plotly.express as px
from urllib.request import urlopen
import json
with urlopen('https://raw.githubusercontent.com/OpenDataDE/State-zip-code-GeoJSON/master/ny_new_york_zip_codes_geo.min.json') as response:
zipcodes = json.load(response)
fig = px.choropleth(df,
geojson=zipcodes,
locations='ZIP_Code',
color='Cluster',
color_continuous_scale="Viridis",
range_color=(1,5),
featureidkey="properties.ZCTA5CE10",
scope="usa",
labels={'Cluster':'Cluster_Category'}
)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})

IV. That’s it!

You should now have a very granular interactive choropleth map. See screenshots below.

United States Level
New York State Level
New York City

References:

  1. https://plotly.com/python/choropleth-maps/ .
  2. https://github.com/OpenDataDE/State-zip-code-GeoJSON

--

--