Trackman Pitching Cards

I built this as a single HTML file where you just upload a Trackman CSV and it handles everything in the browser using PapaParse. Arsenal-wide metrics come from filtering pitch calls to count strikes, swings, and whiffs. Zone rate checks if location falls within the strike zone boundaries (1.5-3.5 feet high, -0.85 to 0.85 feet wide). Chase rate finds swings outside that zone. K%, BB%, and CSW% come from grouping by plate appearances.

For individual pitches, everything is grouped by pitch type. Lodash calculates the averages for velocity, spin, and break. Then the same whiff/zone/chase logic works but on an individual pitch type basis (i.e., automatically filters all data on a pitcher’s fastball vs. their sweeper).

The velocity chart maps average velocity to horizontal bar width, colored by pitch type. The break chart is an SVG centered at origin with a grid. The arsenal table sorts by usage, shows velocity/spin/movement numbers, and includes the plate discipline metrics. Pitch names get colored backgrounds matching the charts.

The Save and Share buttons use HTML2Canvas to save the page as an image. I hide both buttons before rendering so they don't appear in the export.

This works directly with a Trackman CSV.

Trackman Pitching Cards

The upload box is a file input wrapped in a styled container. When you click "Choose File" and select a CSV, it triggers an event listener on the file input. It then reads the CSV with headers turned on so each row becomes an object with column names as keys, and converts strings to numbers.

This is a pitching summary report that is the output when entering in a CSV to the upload box on the screen. At the top, I display the pitcher's name and the pitcher dropdown sits in the top right for switching between players.

The stats grid below shows nine handpicked statistics in individual boxes; total Pitches, PA, K%, BB%, K-BB%, CSW%, Whiff%, Zone%, and Chase%. These are calculated from calculateAdvancedStats() by filtering pitch calls, counting the total outcomes, and dividing by appropriate denominators.

The velocity chart and break chart sit side-by-side in a two-column grid. For velocity, I loop through each pitch type in pitchTypeStats, calculate the bar width as a percentage based on velocity, and render a bar showing the exact MPH, which then stacks according to usage.

For the break chart, I grab each individual pitch’s HorzBreak and InducedVertBreak values, then plot each as a circle in an SVG. Horizontal break on the x-axis, vertical break on the y-axis, as every break chart is depicted.

Below the charts, I render the pitch arsenal table by looping through pitch types sorted by descending usage.

Previous
Previous

xwOBA/xwOBACON Model and Dashboard

Next
Next

North Shore Navigators Offensive Dashboard