Map design: Ridgeline Maps, Edwards, Colorado.
Data. All 888,502 offensive-zone shots across 8 NHL seasons (2018-19 → 2025-26) — MoneyPuck.com shots_2018-2024.csv + shots_2025.csv, all situations including PP / PK / empty net. Player bio data from allPlayersLookup.csv.
The rink is binned into pointy-top hexagons with a 4-foot edge (~41.6 sq ft each).
For each hex, the "best shooter" is the player with the highest empirical-Bayes-adjusted Sh%:
(g + k · lg_sh) / (s + k), prior k = 30, prior mean = the hex's own league rate.
A player must have scored at least 1 goal from the hex to qualify — a 0-for-N shooter can never own a location.
The shot-attempt threshold starts at 8 and steps down (8 → 7 → 6 → … → 1) until a goal-scorer is found,
so low-traffic hexes get filled in too. Hexes with zero goals in the currently selected season stay gray.
Interactive locking. Hovering shows the hex's own best shooter, their bio, and their team logo. Clicking a hex locks that player and switches the map into their personal heatmap —
every hex now colors by that player's bivariate signature from there (gray if they haven't shot the hex), the tooltip reports the locked player's own goals/shots from the hex you're over, and the career-timeline panel on the right shows their per-season totals with a "did not play" row for seasons where they weren't in the league yet.
The click-origin hex keeps its gold ring so you can find your way back. Click the origin again, press Esc , or click any empty hex to unlock and return to the "best at every spot" view.
Bivariate color scheme. Every hex is encoded along two axes simultaneously: x = finishing rate (<15%, 15–25%, ≥25%) and y = shot count backing that rate (<5, 5–9, ≥10). The two cross into a 3 × 3 Stevens-style Teal-Red palette — bottom-left pale gray for "low rate, weak sample," bottom-right red for "hot hand on a thin sample," top-left teal for "high-volume but cold," and top-right deep muddy purple for the cells where a shooter is both efficient and well-sampled.
Why Sh% × Shots, not Sh% × Goals. An earlier version of this view paired Sh% against the shooter's goal count from each hex. That was statistically weak: Sh% = G / S, so goals appeared in both axes, and the bivariate was partly double-counting the same signal. Shots is the denominator of Sh% and is independent of the numerator — high shots can co-occur with any Sh%, so the matrix now isn't redundant. The top-right cells now read as "credibly elite shooter at this location," which is the closest you can get to "scoring danger" with the small-sample sizes hockey shot data offers. Small-sample cells (left column of the matrix) stay pale regardless of the point estimate, which is the right visual treatment for "we can't be confident in this rate."
Rink. Offensive zone only. Regulation NHL geometry — 28-ft corner radius, 11 ft from goal line to end boards,
64 ft from goal line to far blue line, 15-ft faceoff circles centered 22 ft off centerline / 20 ft from the goal line,
restricted-area trapezoid behind the net. Local coordinates: x lateral (0 = rink center), y depth toward the blue line (0 = goal line).