The Spade

The Spade

Tutorial: How to Make QB Contour Maps in Python

Time for more code

Ray Carpenter's avatar
Ray Carpenter
Aug 28, 2025
∙ Paid
1
Share

We’re back with another tutorial for my paid subscribers. If you aren’t part of the club yet and this is something that may interest you, you can click the button below to subscribe:

If you aren’t a paid subscriber, don’t worry. You’ll still receive weekly write-ups from me about football data. We are about to ramp up since college football is officially back and the NFL is back next week. I’m really excited for you all to read the things I have scheduled. I think you’ll really like them.

We are changing back to Python for this but these are also doable in R. I just am in a Python class at the moment so I’m trying to use it more often. Maybe I’ll publish a write-up soon on when to use Python vs. when to use R when working with data transformation and visualization, if that’s something that sounds interesting to you.

Without any further delay, let’s hop right into the tutorial.


Step 1: Packages and Data

I’m running Python 3.13 on my computer.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
from matplotlib.colors import LinearSegmentedColormap
import matplotlib.gridspec as gridspec

YEAR = 2024
url = f'https://github.com/nflverse/nflverse-data/releases/download/pbp/play_by_play_{YEAR}.csv.gz'
data = pd.read_csv(url, compression='gzip', low_memory=False)

If you’re missing any of these packages already, go to your command line and install them. This code to grab the NFL play-by-play data is an easy way to get it all into one csv for you to work through. It’s a good way to pull entire seasons of data at once. We’ve saved it as a variable called ‘data’ in our code.

Step 2: Plotting Helper Functions

location_to_x puts our passes into 3 distinct buckets based on the play by play data. Left, middle, or right. get_pass_df filters our data to only include passing downs, also known as dropbacks. When we call these later, it’ll loop through all passing rows in the csv and create a plot point for each using air yards. I used air yards instead of passing yards because I wanted to plot the actual throws instead of the destinations using yards after catch.

Keep reading with a 7-day free trial

Subscribe to The Spade to keep reading this post and get 7 days of free access to the full post archives.

Already a paid subscriber? Sign in
© 2025 Raymond Carpenter
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture