accepted

Heatmap defaults to fixed 12×8 bins; no adaptive grid

Zero-config Heatmap bins events into a fixed 12×8 grid. Adaptive schemes that vary bin count with data density were rejected because they break cross-match comparability — two heatmaps must be readable side by side without grid surprises.

Heatmap default-behaviourapivisual-encoding

Context

mplsoccer and similar libraries scale bin counts with data density (more events → finer bins). That’s analytically sensible but editorially dangerous: two heatmaps from different matches render with different grids, and visual comparison becomes “which has more bins?” rather than “where was the action?”. A publishable default must be predictable across matches.

Decision

gridX=12, gridY=8 hard-coded as the zero-config default. Consumers wanting tactical layouts use zonePreset or pass explicit xEdges / yEdges arrays. Sparse matches render with many empty cells — that’s correct, not a bug. Finer-grain analytical work uses an explicit override, not an implicit adaptive scheme.

Why 12×8

12 columns ≈ 8.75m each on a 105m pitch; 8 rows ≈ 8.5m each on a 68m pitch. Roughly square cells, aligned with football-zone intuition (thirds × sixths). Coarse enough to read at broadcast card sizes, fine enough to distinguish wing vs central activity.

Consequences

  • Comparable across matches — cell index (4, 3) is always the same physical region.
  • Sparse datasets look sparse. autoCrop / empty-state styling handles the degenerate case; zero counts don’t silently densify.
  • Tactical zones (18-zone, Juego de Posición) are available via zonePreset="opta-18-zones" etc., not via a gridResolution="fine" prop.
  • Territory and similar downstream charts lock to their own fixed grids and don’t inherit Heatmap’s.
← All decisions