Build your own game dashboard
The question: who shot from where, and how did it show up in the box score? A single-game dashboard puts the shot chart and the box score side by side and links them, so pointing at a player in one finds him in the other.
The workflow: one ESPN summary request, three sections from sportsdataverse-js (sdv.nba.espnNbaSummary({ event_id, parsed: true, section }) in Node; the same parser on the same JSON here): header for the teams, plays for every play with its court coordinates, and boxscore_player for the box score. The page keeps the field-goal attempts, moves them onto a sporty half court, joins each shot to its shooter's box-score row on the ESPN athlete id, and links the court and an sdvtables table through one sdvplot selection store.
The snapshot is Toronto at Orlando on 17 March 2024 (Orlando won 111-96; ESPN event 401585607), the same game sdv-js's shot-chart tutorials draw. Tick Fetch live from ESPN to load any NBA or WNBA game by its ESPN event id, or open one from the live scoreboard.
Hover a player's row to light that player's shots, or a shot to underline its shooter. Click rows to select players. Drag a box on the court to select everyone who shot from that zone (clear it with a click outside the box). Team narrows both views to one side.
What to take from it
- Check the join key before the join. The shot's shooter comes from the play's
participants, the box score's player fromathlete_id. Both are ESPN athlete ids, but ESPN sends ids as strings in some payloads and as numbers in others, and"4432573" === 4432573is false: a mismatch does not fail, it joins nothing. The page checks that both sides hold one and the same type before it joins (here, strings), and throws if not. - Validate against the source's own totals. Counting each player's charted attempts and comparing them with the box score's FGA is a free end-to-end check of the filter (no free throws, no missing locations) and the join.
- One store, any number of views. The court and the table never call each other: each is linked to the same selection store with
linkSelection, and the zone brush writes its own store, which the page turns into a selection of shooters.
Script it in Node: sdv-js's shot chart tutorial draws this game's shots to an SVG, and its shots-against-the-league tutorial compares them with the whole 2023-24 season. The Shot charts notebook covers hexagons, zones and league baselines.