Welcome to an exciting new chapter on this blog as we delve into the world of college basketball! We recently launched CollegeBasketballData.com, an endeavor that’s been quite some time in the making. For years, I’ve been approached with requests to provide a service dedicated to college basketball. However, the vast amount of data involved, significantly larger than that of college football, made me hesitant. Plus, with stalwarts like Bart Torvik and Ken Pomeroy already offering stellar analytics, I wasn’t entirely sure if there was room for a service similar to CFBD in the college basketball arena.
Nonetheless, persistent interest from users has spurred me on to give it a shot. Thanks to the refreshed CFBD site and API, I’m energized and ready to extend my analytics journey into college basketball—and I hope you’ll join me!
Let’s get started with some visualizations!
In this session, we’ll be creating team shot charts laid over a standard NCAA men’s basketball court. We’ll use Python along with the CollegeBasketballData.com API and a couple of handy Python libraries. By the end, you’ll see something like this.
Before we dive in, let’s make sure we have all the necessary libraries installed. You’ll need the CBBD Python package, among others. Just execute this in your terminal:
pip install cbbd pandas numpy matplotlib seaborn
Next, we need to set the foundation by plotting a basketball court. We’ll be leveraging matplotlib for this purpose. Let’s get all our dependencies imported with this code block:
import cbbd
import pandas as pd
import numpy as np
import matplotlib.pylab as plt
import matplotlib as mpl
from matplotlib.patches import Circle, Rectangle, Arc
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import seaborn as sns
plt.style.use('seaborn-v0_8-dark-palette')
A big thanks to Rob Mulla, who developed a series of helper functions for plotting NCAA courts on Kaggle. His comprehensive guide even shows how to plot a full-size court, though today we’ll focus on a half court. Here’s a function we’ll use from his work:
def create_ncaa_half_court(ax=None, three_line="mens", court_color="#dfbb85",
lw=3, lines_color="black", lines_alpha=0.5,
paint_fill="blue", paint_alpha=0.4,
inner_arc=False):
# Function content here...
Additionally, with the new CBBD offerings, we now have the exciting ability to visualize shot data. First, configure your API key using the code snippet below, substituting your API key where needed:
configuration = cbbd.Configuration(
access_token = 'your_api_key_here'
)
Shot location data can be retrieved from the CollegeBasketballData.com API, particularly using the cbbd Python package we imported earlier. Here’s how to fetch shooting plays:
with cbbd.ApiClient(configuration) as api_client:
plays_api = cbbd.PlaysApi(api_client)
plays = plays_api.get_plays_by_team(season=2025, team='Dayton', shooting_plays_only=True)
This brings the data into a format we can easily analyze. By converting this into a pandas DataFrame and translating full court coordinates to half court, we simplify our plotting process.
We can visualize the data using matplotlib. For a basic scatter plot:
plt.scatter(df['y_half'], df['x_half'])
Not super engaging, right? Let’s upgrade that to a hexbin plot, which provides a much clearer picture:
plt.hexbin(df['y_half'], df['x_half'], gridsize=20, cmap='inferno')
Want something even more dynamic? By using seaborn, we can create a jointplot combining a heat map-style hexbin with the elegance of a bar chart. Watch this in action:
sns.jointplot(data=df, x='y_half', y='x_half', kind='hex', space=0, color=plt.cm.gist_heat_r(.2), cmap=plt.cm.gist_heat_r)
To take it a step further, overlaying this on our half court plot with the following code makes for a comprehensive and insightful shot chart:
cmap = plt.cm.gist_heat_r
joint_shot_chart = sns.jointplot(data=df, x='y_half', y='x_half',
kind='hex', space=0, color=cmap(.2), cmap=cmap)
joint_shot_chart.figure.set_size_inches(12,11)
ax = joint_shot_chart.ax_joint
create_ncaa_half_court(ax=ax, three_line="mens", court_color="white", lines_color="black", paint_alpha=0, inner_arc=True)
ax.set_xlabel('')
ax.set_ylabel('')
ax.tick_params(labelbottom='off', labelleft="off")
ax.set_title(f"Dayton Shot Attempts\n(2024-2025)", y=1.22, fontsize=18)
And there you have it, a fully fleshed out shot chart! To mix things up, you can also experiment with different types of joint plots like scatter or kde to suit various analytical needs.
Always eager to see what you think, and here’s wishing you happy coding on your journey into college basketball analytics!