Matplotlib baseball field drawing and Statcast spray chart for MLB analysis
Project description
baseball-field-viz
A Python library for drawing baseball fields and spray charts from Statcast data.
Companion to savant-extras — together they provide a seamless MLB analysis pipeline.
Installation
pip install baseball-field-viz
Why this library?
pybaseball's built-in spraychart() doesn't support overlaying heatmaps (e.g. seaborn kdeplot). This library gives you a matplotlib Axes object directly, so you can layer any plot on top.
from baseball_field_viz import draw_field
import seaborn as sns
fig, ax = plt.subplots(figsize=(10, 10))
draw_field(ax)
sns.kdeplot(data=df_t, x="x", y="y", ax=ax, cmap="Reds", fill=True, alpha=0.6)
Quick Start
import matplotlib.pyplot as plt
from baseball_field_viz import draw_field, spraychart, transform_coords
# Spray chart (one-liner)
fig, ax = plt.subplots(figsize=(10, 10))
spraychart(ax, df, color_by="events", title="Ohtani 2025 - Batted Balls")
plt.show()
Functions
transform_coords(df)
Convert Statcast hc_x/hc_y to feet coordinates (home plate at origin).
from baseball_field_viz import transform_coords
df_t = transform_coords(df)
# Adds 'x' and 'y' columns in feet
# x = 2.5 * (hc_x - 125.42)
# y = 2.5 * (198.27 - hc_y)
draw_field(ax, foul_distance=330, outfield_distance=340)
Draw a baseball field on a matplotlib Axes.
from baseball_field_viz import draw_field
fig, ax = plt.subplots(figsize=(10, 10))
draw_field(ax)
# Now overlay any plot: scatter, kdeplot, histplot, etc.
spraychart(ax, df, color_by="events", title=None)
Draw a spray chart in one call. Internally calls transform_coords and draw_field.
from baseball_field_viz import spraychart
fig, ax = plt.subplots(figsize=(10, 10))
spraychart(ax, df, color_by="events", title="Player - Season")
plt.show()
color_by options:
| Value | Effect |
|---|---|
"events" (default) |
home_run=red, triple=orange, double=blue, single=green, other=gray |
| Any column name | Categorical coloring with auto palette |
Full Example with Heatmap
from pybaseball import statcast
import duckdb
import matplotlib.pyplot as plt
import seaborn as sns
from baseball_field_viz import draw_field, transform_coords
# Fetch data
df_raw = statcast(start_dt="2025-03-01", end_dt="2025-10-31")
con = duckdb.connect()
df = con.execute("""
SELECT * FROM df_raw
WHERE batter = 660271
AND hc_x IS NOT NULL AND hc_y IS NOT NULL
AND game_type = 'R'
""").df()
df_t = transform_coords(df)
# Hits vs outs heatmap
fig, axs = plt.subplots(1, 2, figsize=(16, 8))
hits = df_t[df_t["events"].isin(["home_run", "double", "triple", "single"])]
outs = df_t[~df_t["events"].isin(["home_run", "double", "triple", "single"])]
draw_field(axs[0])
sns.kdeplot(data=hits, x="x", y="y", ax=axs[0], cmap="Reds", fill=True, alpha=0.6)
axs[0].set_xlim(-350, 350); axs[0].set_ylim(-50, 400)
axs[0].set_title("Hits Heatmap")
draw_field(axs[1])
sns.kdeplot(data=outs, x="x", y="y", ax=axs[1], cmap="Blues", fill=True, alpha=0.6)
axs[1].set_xlim(-350, 350); axs[1].set_ylim(-50, 400)
axs[1].set_title("Outs Heatmap")
plt.tight_layout()
plt.show()
Strike Zone (v0.2.0)
draw_strike_zone(ax, sz_top=3.5, sz_bot=1.5, color="black", lw=2)
Draw a strike zone rectangle on a matplotlib Axes (plate_x / plate_z coordinate system).
from baseball_field_viz import draw_strike_zone
fig, ax = plt.subplots(figsize=(6, 6))
draw_strike_zone(ax, sz_top=3.5, sz_bot=1.5)
pitch_zone_chart(ax, df, color_by="pitch_type", sz_top=None, sz_bot=None, title=None)
Plot pitch locations with strike zone overlay. Uses plate_x / plate_z columns (Statcast standard).
If sz_top/sz_bot are not provided, the mean of df["sz_top"]/df["sz_bot"] is used automatically.
from pybaseball import statcast
from baseball_field_viz import pitch_zone_chart
df = statcast(start_dt="2025-03-01", end_dt="2025-10-31")
df_pitcher = df[df["pitcher"] == 592789] # e.g. Yoshinobu Yamamoto
fig, ax = plt.subplots(figsize=(6, 6))
pitch_zone_chart(ax, df_pitcher, color_by="pitch_type", title="Yamamoto 2025 - Pitch Locations")
plt.show()
The strike zone is automatically sized from per-pitch Hawk-Eye measurements (sz_top/sz_bot) in the Statcast data, reflecting each batter's actual stance.
Requirements
- Python 3.9+
- matplotlib >= 3.5
- numpy >= 1.21
- pandas >= 1.3
Related
- savant-extras — Statcast bat tracking data fetcher
- pybaseball — Statcast data access
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file baseball_field_viz-0.2.4.tar.gz.
File metadata
- Download URL: baseball_field_viz-0.2.4.tar.gz
- Upload date:
- Size: 8.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9304803f14b4447215a9b1937243169e8c4c5846058da9f8f4e4043a9364d48e
|
|
| MD5 |
b7963383a2b39de0591338a443078bb8
|
|
| BLAKE2b-256 |
a9ee85bbea41ef8e2d0eb8daf4ddffe5e4a9ab22823110c0422b38800c841b62
|
Provenance
The following attestation bundles were made for baseball_field_viz-0.2.4.tar.gz:
Publisher:
publish.yml on yasumorishima/baseball-field-viz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
baseball_field_viz-0.2.4.tar.gz -
Subject digest:
9304803f14b4447215a9b1937243169e8c4c5846058da9f8f4e4043a9364d48e - Sigstore transparency entry: 976842706
- Sigstore integration time:
-
Permalink:
yasumorishima/baseball-field-viz@352bce9abb072a190a48682402215b16cc75a40f -
Branch / Tag:
refs/tags/v0.2.4 - Owner: https://github.com/yasumorishima
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@352bce9abb072a190a48682402215b16cc75a40f -
Trigger Event:
release
-
Statement type:
File details
Details for the file baseball_field_viz-0.2.4-py3-none-any.whl.
File metadata
- Download URL: baseball_field_viz-0.2.4-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52c80d3e7c6c2ca1e967011a12a9ba39f5b091aeb299d5911c7f0e8f1a6dbd38
|
|
| MD5 |
d2da5c1af6a3d16a1ce4c87cd3e0779b
|
|
| BLAKE2b-256 |
1e5c1c1de5c43ea7450b7f52a4773cfa63bdfde146510e849ef9c815c928ee55
|
Provenance
The following attestation bundles were made for baseball_field_viz-0.2.4-py3-none-any.whl:
Publisher:
publish.yml on yasumorishima/baseball-field-viz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
baseball_field_viz-0.2.4-py3-none-any.whl -
Subject digest:
52c80d3e7c6c2ca1e967011a12a9ba39f5b091aeb299d5911c7f0e8f1a6dbd38 - Sigstore transparency entry: 976842710
- Sigstore integration time:
-
Permalink:
yasumorishima/baseball-field-viz@352bce9abb072a190a48682402215b16cc75a40f -
Branch / Tag:
refs/tags/v0.2.4 - Owner: https://github.com/yasumorishima
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@352bce9abb072a190a48682402215b16cc75a40f -
Trigger Event:
release
-
Statement type: