Monday, May 19, 2025
Unique Sportz
No Result
View All Result
  • Home
  • NBA
  • MLB
  • NFL
  • NHL
  • NCAAF
  • Nascar
  • Premier
  • Other Sports
    • Tennis
    • Boxing
    • Golf
    • Formula 1
    • Cycling
    • Running
    • Swimming
    • Skiing
    • MMA
    • WWE
    • eSports
    • CrossFit
Unique Sportz
  • Home
  • NBA
  • MLB
  • NFL
  • NHL
  • NCAAF
  • Nascar
  • Premier
  • Other Sports
    • Tennis
    • Boxing
    • Golf
    • Formula 1
    • Cycling
    • Running
    • Swimming
    • Skiing
    • MMA
    • WWE
    • eSports
    • CrossFit
No Result
View All Result
Unique Sportz
No Result
View All Result
Home NCAAF

Talking Tech: Generating Shot Charts using the Basketball API

March 5, 2025
in NCAAF
Reading Time: 12 mins read
0 0
A A
0
Talking Tech: Generating Shot Charts using the Basketball API


Welcome to the primary ever basketball put up on this right here weblog! As introduced a couple of weeks again, CollegeBasketballData.com is now dwell. I’ve usually been requested about offering service for faculty basketball and have all the time been hesitant. For one, the sheer quantity of information is a number of instances higher than for soccer as a consequence of almost triple the variety of groups and triple the variety of video games per group. I’ve additionally been an enormous fan each of Bart Torvik and Ken Pomeroy and wasn’t certain there was a lot of want for a CFBD-like service for CBB with the stats and analytics these guys present.

That each one mentioned, I’ve been requested persistently over time from numerous customers and the CFBD web site and API refreshes have made me energized to offer CBB a go. I am excited to supply this service and if I have been part of your CFB analytics journey, I hope I can do the identical for CBB.

Now let’s dive into some charts!

We’re going to be plotting group shot charts on prime of a typical NCAA males’s courtroom utilizing Python and the CollegeBasketballData.com API together with a couple of widespread Python packages. When all is claimed and accomplished, we could have one thing that appears like this.

Earlier than we do something, we’d like to ensure now we have all dependencies put in. We are going to want the CBBD Python package deal and some others. Run the next code in terminal.

pip set up cbbd pandas numpy matplotlib seaborn

Now we have to concentrate on plotting a basketball courtroom. We shall be utilizing matplotlib to attain this. Go forward and run the next block to import all of dependencies we simply put in.

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.type.use(‘seaborn-v0_8-dark-palette’)

As we did into plotting the courtroom, I first want to offer an enormous shout out to Rob Mulla, who wrote a sequence of helper features for plotting NCAA courts on Kaggle. His Kaggle article goes extra in-depth and even features a plot for a full measurement courtroom. We’ll simply be utilizing a half courtroom and duplicate/pasting a perform from that article.

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):
“””
Model 2020.2.19

Creates NCAA Basketball Half Court docket
Dimensions are in toes (Court docket is 97×50 ft)
Created by: Rob Mulla / https://github.com/RobMulla

* Notice that this perform makes use of “toes” because the unit of measure.
* NCAA Knowledge is supplied on a x vary: 0, 100 and y-range 0 to 100
* To plot X/Y positions first convert to toes like this:
“`
Occasions[‘X_’] = (Occasions[‘X’] * (94/100))
Occasions[‘Y_’] = (Occasions[‘Y’] * (50/100))
“`
ax: matplotlib axes if None will get present axes utilizing `plt.gca`

three_line: ‘mens’, ‘womens’ or ‘each’ defines 3 level line plotted
court_color : (hex) Colour of the courtroom
lw : line width
lines_color : Colour of the traces
lines_alpha : transparency of traces
paint_fill : Colour contained in the paint
paint_alpha : transparency of the “paint”
inner_arc : paint the dotted internal arc
“””
if ax is None:
ax = plt.gca()

# Create Pathes for Court docket Traces
center_circle = Circle((50/2, 94/2), 6,
linewidth=lw, colour=lines_color, lw=lw,
fill=False, alpha=lines_alpha)
hoop = Circle((50/2, 5.25), 1.5 / 2,
linewidth=lw, colour=lines_color, lw=lw,
fill=False, alpha=lines_alpha)

# Paint – 18 Ft 10 inches which converts to 18.833333 toes – gross!
paint = Rectangle(((50/2)-6, 0), 12, 18.833333,
fill=paint_fill, alpha=paint_alpha,
lw=lw, edgecolor=None)

paint_boarder = Rectangle(((50/2)-6, 0), 12, 18.833333,
fill=False, alpha=lines_alpha,
lw=lw, edgecolor=lines_color)

arc = Arc((50/2, 18.833333), 12, 12, theta1=-
0, theta2=180, colour=lines_color, lw=lw,
alpha=lines_alpha)

block1 = Rectangle(((50/2)-6-0.666, 7), 0.666, 1,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
block2 = Rectangle(((50/2)+6, 7), 0.666, 1,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(block1)
ax.add_patch(block2)

l1 = Rectangle(((50/2)-6-0.666, 11), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l2 = Rectangle(((50/2)-6-0.666, 14), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l3 = Rectangle(((50/2)-6-0.666, 17), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(l1)
ax.add_patch(l2)
ax.add_patch(l3)
l4 = Rectangle(((50/2)+6, 11), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l5 = Rectangle(((50/2)+6, 14), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l6 = Rectangle(((50/2)+6, 17), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(l4)
ax.add_patch(l5)
ax.add_patch(l6)

# 3 Level Line
if (three_line == ‘mens’) | (three_line == ‘each’):
# 22′ 1.75″ distance to middle of hoop
three_pt = Arc((50/2, 6.25), 44.291, 44.291, theta1=12,
theta2=168, colour=lines_color, lw=lw,
alpha=lines_alpha)

# 4.25 toes max to sideline for mens
ax.plot((3.34, 3.34), (0, 11.20),
colour=lines_color, lw=lw, alpha=lines_alpha)
ax.plot((50-3.34, 50-3.34), (0, 11.20),
colour=lines_color, lw=lw, alpha=lines_alpha)
ax.add_patch(three_pt)

if (three_line == ‘womens’) | (three_line == ‘each’):
# womens 3
three_pt_w = Arc((50/2, 6.25), 20.75 * 2, 20.75 * 2, theta1=5,
theta2=175, colour=lines_color, lw=lw, alpha=lines_alpha)
# 4.25 inches max to sideline for mens
ax.plot( (4.25, 4.25), (0, 8), colour=lines_color,
lw=lw, alpha=lines_alpha)
ax.plot((50-4.25, 50-4.25), (0, 8.1),
colour=lines_color, lw=lw, alpha=lines_alpha)

ax.add_patch(three_pt_w)

# Add Patches
ax.add_patch(paint)
ax.add_patch(paint_boarder)
ax.add_patch(center_circle)
ax.add_patch(hoop)
ax.add_patch(arc)

if inner_arc:
inner_arc = Arc((50/2, 18.833333), 12, 12, theta1=180,
theta2=0, colour=lines_color, lw=lw,
alpha=lines_alpha, ls=”–“)
ax.add_patch(inner_arc)

# Restricted Space Marker
restricted_area = Arc((50/2, 6.25), 8, 8, theta1=0,
theta2=180, colour=lines_color, lw=lw,
alpha=lines_alpha)
ax.add_patch(restricted_area)

# Backboard
ax.plot(((50/2) – 3, (50/2) + 3), (4, 4),
colour=lines_color, lw=lw*1.5, alpha=lines_alpha)
ax.plot( (50/2, 50/2), (4.3, 4), colour=lines_color,
lw=lw, alpha=lines_alpha)

# Half Court docket Line
ax.axhline(94/2, colour=lines_color, lw=lw, alpha=lines_alpha)

# Plot Restrict
ax.set_xlim(0, 50)
ax.set_ylim(0, 94/2 + 2)
ax.set_facecolor(court_color)
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel(”)
return ax

You may be aware that the code has a number of formatting choices and you may even change between a males’s and ladies’s courts. CBBD doesn’t at the moment provide NCAA ladies’s information, however that’s nonetheless a really good characteristic to have.

Go forward and run the perform with none choices specified.

create_ncaa_half_court()

Fairly fundamental and it simply works! We are able to add some formatting choices.

create_ncaa_half_court(three_line=”mens”, court_color=”black”, lines_color=”white”, paint_alpha=0, inner_arc=True)

Be happy to fiddle extra with completely different courtroom and magnificence combos.

We are going to seize shot location information from the CollegeBasketballData.com (CBBD) API. Particularly, we’ll be working with the cbbd Python package deal (imported above). First, configure your API key, changing your personal API key with the placeholder beneath. In case you want an API key, you may register for a free key through the CBBD foremost web site.

configuration = cbbd.Configuration(
access_token = ‘your_api_key_here’
)

Shot location information is included in play by play information. We are able to use the CBBD Performs API to seize all capturing performs for a selected group or participant. On this instance, we’ll seize team-level information. We are going to specify season and group parameters. We may even move in a shooting_plays_only flag to solely return capturing performs (i.e. filtering out issues like timeouts, rebounds, fouls, and many others). The code block beneath will seize capturing performs related to Dayton within the 2025 season. Be happy to modify up the group or season.

with cbbd.ApiClient(configuration) as api_client:
plays_api = cbbd.PlaysApi(api_client)
performs = plays_api.get_plays_by_team(season=2025, group=’Dayton’, shooting_plays_only=True)
performs[0]

Instance output of a capturing play:

PlayInfo(id=118229, source_id=’401715398101806301′, game_id=426, game_source_id=’401715398′, game_start_date=datetime.datetime(2024, 11, 9, 19, 30, tzinfo=datetime.timezone.utc), season=2025, season_type=, game_type=”STD”, play_type=”LayUpShot”, is_home_team=False, team_id=212, group=’Northwestern’, convention=”Huge Ten”, opponent_id=64, opponent=”Dayton”, opponent_conference=”A-10″, interval=1, clock=’19:36′, seconds_remaining=1176, home_score=0, away_score=0, home_win_probability=0.635, scoring_play=False, shooting_play=True, score_value=2, wallclock=None, play_text=”Ty Berry missed Layup.”, individuals=[PlayInfoParticipantsInner(name=”Ty Berry”, id=5452)], shot_info=ShotInfo(shooter=ShotInfoShooter(identify=”Ty Berry”, id=5452), made=False, vary=”rim”, assisted=False, assisted_by=ShotInfoShooter(identify=None, id=None), location=ShotInfoLocation(y=270, x=864.8)))

We are able to simply load this up right into a pandas DataFrame. The present scale for the x and y coordinates is 10 pts for each 1 foot. Dividing by 10, we will convert that into toes as we import right into a DataFrame, which is able to make it simpler to work with the half courtroom plot we ran by means of above. We may even filter out any capturing performs which may be lacking location information for no matter cause.

df = pd.DataFrame.from_records([
dict(
x=p.shot_info.location.x / 10,
y=p.shot_info.location.y / 10,
)
for p in plays
if p.shot_info is not None
and p.shot_info.location is not None
and p.shot_info.location.x is not None
and p.shot_info.location.y is not None
])

df.head()

x
y

0
76.14
29.5

1
22.56
41.0

2
26.32
8.5

3
81.78
31.5

4
69.56
9.5

We’ve one final step to take to get our information right into a usable state. We’re at the moment working with half courtroom plots, however these shot areas correspond to a full courtroom. We are going to convert the shot areas to half courtroom coordinates by translating areas from the lacking half over to the seen half of the courtroom.

df[‘x_half’] = df[‘x’]
df.loc[df[‘x’] > 47, ‘x_half’] = (94 – df[‘x’].loc[df[‘x’] > 47])
df[‘y_half’] = df[‘y’]
df.loc[df[‘x’] > 47, ‘y_half’] = (50 – df[‘y’].loc[df[‘x’] > 47])

# solid these to drift to keep away from typing points later
df[‘x_half’] = df[‘x_half’].astype(float)
df[‘y_half’] = df[‘y_half’].astype(float)

We are able to simply plot this information utilizing matplotlib. For instance, we will put it right into a scatter plot.

plt.scatter(df[‘y_half’], df[‘x_half’])

Not very fairly, however you may clearly see a basketball courtroom, together with the final define of the 3-point line.

We are able to enhance upon these by making a hexbin chart, which is able to bucket pictures into hexagonal areas of the courtroom to create a type of heatmap. The beneath code will create a hexbin plot utilizing the inferno colour map.

plt.hexbin(df[‘y_half’], df[‘x_half’], gridsize=20, cmap=’inferno’)

You may view extra colormaps right here and mess around with completely different colour schemes. Simply change inferno within the above snippet with the colormap of our alternative. You may as well kind in plt.cm. and use autocomplete to conveniently see what is offered.

I am a fan of gist_heat_r, so let’s test that one out. We’ll simply rerun the code from above, changing the colormap with that one.

plt.hexbin(df[‘y_half’], df[‘x_half’], gridsize=20, cmap=plt.cm.gist_heat_r)

You may as well fiddle with the gridsize parameter for decrease or greater decision. Right here I’ll improve the worth from 20 to 40.

plt.hexbin(df[‘y_half’], df[‘x_half’], gridsize=40, cmap=plt.cm.gist_heat_r)

We have plotted an empty half courtroom. We have plot precise shot location information factors. It is time to convey that every one collectively. Run the beneath snippet after which we’ll break it down line by line.

fig, ax = plt.subplots(figsize=(13.8, 14))
ax.hexbin(x=’y_half’, y=’x_half’, cmap=plt.cm.gist_heat_r, gridsize=40, information=df)
create_ncaa_half_court(ax, court_color=”white”,
lines_color=”black”, paint_alpha=0,
inner_arc=True)
plt.present()

Fairly good, huh? Let’s stroll by means of it.

On line 1, we’re setting the dimensions of the plot and returning the plot fig and ax objects.On line 2, we’re utilizing the ax object to create a hexbin plot, nearly similar to above.On line 3, we’re calling the create_ncaa_half_court perform with our desired styling choices. The colormap used right here works finest with a white background.Lastly, we present the courtroom with the plotted hex bins.

Let’s make this even cooler. We will use a library known as seaborn, which is constructed upon matplotlib. It accommodates most of the base plots discovered inside matplotlib, however with its personal tweaks and enhancements. It additionally gives a number of extra, extra superior varieties of plots. You may view the gallery right here. We’re going to be working with a jointplot, which is able to mix the hexbin chart we created with points of a bar chart.

It is fairly merely. Simply run the snippet beneath to see what it seems like.

sns.jointplot(information=df, x=’y_half’, y=’x_half’,
variety=’hex’, area=0, colour=plt.cm.gist_heat_r(.2), cmap=plt.cm.gist_heat_r)

Now put all of it collectively and let’s plot the jointplot on prime of our half courtroom plot.

cmap = plt.cm.gist_heat_r
joint_shot_chart = sns.jointplot(information=df, x=’y_half’, y=’x_half’,
variety=’hex’, area=0, colour=cmap(.2), cmap=cmap)

joint_shot_chart.determine.set_size_inches(12,11)

# A joint plot has 3 Axes, the primary one known as ax_joint
# is the one we need to draw our courtroom onto
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)

One final thing, let’s take away the entry labels and add a title.

cmap = plt.cm.gist_heat_r
joint_shot_chart = sns.jointplot(information=df, x=’y_half’, y=’x_half’,
variety=’hex’, area=0, colour=cmap(.2), cmap=cmap)

joint_shot_chart.determine.set_size_inches(12,11)

# A joint plot has 3 Axes, the primary one known as ax_joint
# is the one we need to draw our courtroom onto
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)

# Do away with axis labels and tick marks
ax.set_xlabel(”)
ax.set_ylabel(”)
ax.tick_params(labelbottom=’off’, labelleft=”off”)
ax.set_title(f”Dayton Shot Attemptsn(2024-2025)”, y=1.22, fontsize=18)

There are different kinds of joint plots you can also make by altering the sort parameter on line 3 above. For instance, altering the sort from hex to scatter outcomes on this.

Here’s what occurs after we change it to kde.

It does not look so nice, does it? We are able to fiddle a bit with the styling to make that look a bit higher. I will change the colormap to inferno, add fill and thresh parameters, and alter the half courtroom styling a bit bit.

cmap = plt.cm.inferno
joint_shot_chart = sns.jointplot(information=df, x=’y_half’, y=’x_half’,
variety=’kde’, area=0, fill=True, thresh=0, colour=cmap(.2), cmap=cmap)

joint_shot_chart.determine.set_size_inches(12,11)

# A joint plot has 3 Axes, the primary one known as ax_joint
# is the one we need to draw our courtroom onto
ax = joint_shot_chart.ax_joint
create_ncaa_half_court(ax=ax,
three_line=”mens”,
court_color=”black”,
lines_color=”white”,
paint_alpha=0,
inner_arc=True)

# Do away with axis labels and tick marks
ax.set_xlabel(”)
ax.set_ylabel(”)
ax.tick_params(labelbottom=’off’, labelleft=”off”)
ax.set_title(f”Dayton Shot Attemptsn(2024-2025)”, y=1.22, fontsize=18)

That is higher. See the jointplot docs for extra kinds, examples, and customizations.

It’s best to now be capable of create shot location charts towards an precise courtroom utilizing matplotlib and seaborn with the CBBD Python library. There are lots of methods to take this additional:

Plot a number of groups utilizing subplotsPlot made pictures and missed pictures side-by-side for a similar group utilizing subplotsApply the identical code to plotting shot charts for particular playersFind new styling and customizations

Lastly, I already cited Rob Mulla and his wonderful Kaggle article and helper features for plotting NCAA basketball courts. I would be remiss if I additionally did not shout Savvas Tjortjoglou as a drew a variety of inspiration from his article on plotting NBA shot charts.

As all the time, let me know what you assume and pleased coding!



Source link

Tags: APIBasketballChartsGeneratingshotTalkingTech
Previous Post

What helmet design will drivers wear in the 2025 F1 season?

Next Post

Xbox and PC Game Pass in March 2025: All new games and departures at a glance – with the European Fallout

Related Posts

Kirk Herbstreit Was 'Not Happy' With ESPN Firing Analyst
NCAAF

Kirk Herbstreit Was 'Not Happy' With ESPN Firing Analyst

May 19, 2025
Paul Finebaum Names Star Freshman QB Who is a 'Can't Miss' Prospect
NCAAF

Paul Finebaum Names Star Freshman QB Who is a 'Can't Miss' Prospect

May 18, 2025
College football 2025 win totals Bruce Feldman likes most: Is Clemson an 11-1 team?
NCAAF

College football 2025 win totals Bruce Feldman likes most: Is Clemson an 11-1 team?

May 18, 2025
Arch Manning's Heisman campaign could be determined in Week 1
NCAAF

Arch Manning's Heisman campaign could be determined in Week 1

May 17, 2025
Pair of South Carolina stars land in top 10 of Top 100 CFB players list
NCAAF

Pair of South Carolina stars land in top 10 of Top 100 CFB players list

May 18, 2025
ESPN Names New No. 1 Team In Updated Top 25 College Football Rankings
NCAAF

ESPN Names New No. 1 Team In Updated Top 25 College Football Rankings

May 18, 2025
Next Post
Xbox and PC Game Pass in March 2025: All new games and departures at a glance – with the European Fallout

Xbox and PC Game Pass in March 2025: All new games and departures at a glance – with the European Fallout

Report: FIFA Club World Cup prize money to surpass B for 32 clubs

Report: FIFA Club World Cup prize money to surpass $1B for 32 clubs

Komatsu confident Haas will resolve bodywork issues by Melbourne

Komatsu confident Haas will resolve bodywork issues by Melbourne

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • Disclaimer
  • DMCA
  • Privacy Policy
  • Cookie Privacy Policy
  • Terms and Conditions
  • Contact us
  • About Us
UNIQUE SPORTZ

Copyright © 2024 Unique Sportz.
Unique Sportz is not responsible for the content of external sites.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Home
  • NBA
  • MLB
  • NFL
  • NHL
  • NCAAF
  • Nascar
  • Premier
  • Other Sports
    • Tennis
    • Boxing
    • Golf
    • Formula 1
    • Cycling
    • Running
    • Swimming
    • Skiing
    • MMA
    • WWE
    • eSports
    • CrossFit

Copyright © 2024 Unique Sportz.
Unique Sportz is not responsible for the content of external sites.