Skip to main content

Mound

A CLI and Python toolkit for retrieving, analyzing and visualizing MLB pitch-level data — without needing to know MLB player IDs or the underlying API structures.

> How many splitters did Roki Sasaki throw against the Diamondbacks last night?
> How often has he thrown it relative to his other pitches over his last four starts?
> What does its location look like over that period?

Mound answers questions like these with a few CLI commands or a few lines of Python.

Install

git clone https://github.com/stiles/mound.git
cd mound
pip install -e .

# Parquet export support:
pip install -e ".[parquet]"

Requires Python 3.10+.

Quickstart

CLI

# Find a player and their MLB ID
mound search "Roki Sasaki"

# Retrieve pitches from his last 4 starts
mound pitches "Roki Sasaki" --last 4

# Isolate one pitch type
mound pitches "Roki Sasaki" --last 4 --pitch splitter

# Pitch mix and results by pitch type
mound mix "Roki Sasaki" --last 4
mound results "Roki Sasaki" --last 4 --pitch splitter

# Plot pitch locations against the strike zone
mound zone "Roki Sasaki" --pitch splitter --last 4 --out splitter_zone.png

# Export the underlying data
mound pitches "Roki Sasaki" --last 4 --export roki_last4.csv

Run mound --help or mound <command> --help for the full option list.

Python

from mound import Pitcher

roki = Pitcher("Roki Sasaki")

pitches = roki.pitches(last=4)
splitters = pitches.filter(pitch_type="splitter")

splitters.pitch_mix()
splitters.strike_rate()
splitters.plot_zone(out="splitter_zone.png")

pitches.to_csv("roki_last4.csv")

Pitcher.pitches() and PitchCollection.filter() both accept:

Argument Meaning
last most recent N appearances
since / until date range ("YYYY-MM-DD" or date), inclusive
game one or more MLB game_pk values
pitch_type a pitch name, alias, or Statcast code (see below)

Filtering a PitchCollection always returns another PitchCollection, so any combination of .filter(), .pitch_mix(), .strike_rate(), .plot_zone() and export methods composes freely.

Plots

plot_zone() renders a headline, a dek (pitch count, strike rate, date range) and a source line around the strike-zone chart itself, rather than relying on axis titles or a boxed legend:

Roki Sasaki splitter locations

All three are auto-generated but overridable:

splitters.plot_zone(
    title="Sasaki leans on the splitter",
    subtitle="134 pitches since the All-Star break",
    source="Source: Baseball Savant",
    kind="heatmap",  # or "scatter" (default)
    out="splitter_zone.png",
)

Pass subtitle="" or source="" to omit either. Passing your own ax (e.g. for a multi-panel figure) skips the dek/source and falls back to a plain left-aligned title, so plot_zone() behaves as a well-mannered subplot.

Pitch types

Statcast tags every pitch with a short code. Mound normalizes these into human-readable names and accepts common aliases when filtering, so pitch_type="four-seam", "fastball" and "FF" are all equivalent.

Code Name Common aliases
FF four-seam fastball fastball, four-seam
FT two-seam fastball two-seam
SI sinker
FC cutter cut fastball
SL slider
ST sweeper sweeping slider
SV slurve
CU curveball curve
KC knuckle curve
CH changeup change-up
FS splitter split-finger
FO forkball
SC screwball
KN knuckleball knuckler
EP eephus

Note on Roki Sasaki's signature pitch: Statcast classifies it inconsistently start-to-start — sometimes as a splitter (FS), sometimes as a forkball (FO), depending on its movement profile in a given game. If a pitch_type="splitter" query looks incomplete, check pitch_type="forkball" too, or filter using both.

Data sources

Mound calls two unofficial, public MLB data services directly:

  • MLB Stats API — player search/lookup and game logs, used to resolve a pitcher's identity and discover which games to pull.
  • Baseball Savant — the /gf game-feed endpoint, used for pitch-by-pitch Statcast data (location, velocity, pitch type, count, outcome).

Both are unofficial and undocumented; endpoints or response shapes could change without notice. Mound sends a descriptive User-Agent and retries transient failures, but does not currently cache responses, so repeated queries re-fetch data from these services.

Development

pip install -e ".[dev]"
pytest
ruff check .

Tests run entirely against mocked HTTP fixtures in tests/fixtures/ (via the responses library) and don't require network access.

Known limitations

  • No caching yet — every call re-fetches from the MLB Stats API / Baseball Savant.
  • Pitch classification comes from Statcast's own model and can be inconsistent for pitches with unusual movement (see the Roki Sasaki note above).
  • Only pitchers are supported as the primary retrieval unit; there's no batter-vs-pitcher matchup view yet (see ROADMAP.md).
  • Historical data availability depends on Statcast/Savant coverage, which is generally reliable from 2015 onward.
  • All requests are synchronous and unthrottled beyond basic retry/backoff; heavy bulk retrieval (e.g. a full season) will be slow.

Roadmap

See ROADMAP.md for planned enhancements beyond this prototype.

Changelog

See CHANGELOG.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mound-0.1.0.tar.gz (547.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mound-0.1.0-py3-none-any.whl (25.0 kB view details)

Uploaded Python 3

File details

Details for the file mound-0.1.0.tar.gz.

File metadata

  • Download URL: mound-0.1.0.tar.gz
  • Upload date:
  • Size: 547.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.18

File hashes

Hashes for mound-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4b5778b076a6f38d41f9bf405d37a1ad5efd2ba92849eb43d73856644bf31a62
MD5 be776b181dbf5d829ff43e763ff0e9a2
BLAKE2b-256 54102be580f52e6964a04ad74689523446d246fa432d813dff715825488d3f11

See more details on using hashes here.

File details

Details for the file mound-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mound-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.18

File hashes

Hashes for mound-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fa06704d772519bc64fe194e58c7c1e1025f61f36165bb75fadb02db9e9a6293
MD5 15f83d404dc789b377a9f5bd8a72ad84
BLAKE2b-256 e28565bcf6f9add0e3d95e91e05a8d14562e02a88633caf7adeec5f169a8824d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page