accepted

ShotMap shape + fill grammar is preset-owned; Opta is outcome-first, StatsBomb is xG-first

`preset="opta"` locks markers to circles with fill-vs-hollow encoding outcome (goal vs non-goal). `preset="statsbomb"` uses shapes keyed to context/body-part (hexagon foot, circle header, square set-piece) with fill colour driven by the xG colour ramp. The two presets intentionally produce different charts from the same data model.

ShotMap default-behaviourvisual-encodingpreset-semantics

Context

Opta is outcome-first: the editorial question is “did it go in?”, and the dominant visual read is a filled-for-goal / hollow-for-shot binary. StatsBomb is xG-first: the editorial question is “how good was the chance?”, with context (set-piece, body-part) carrying almost as much signal as xG itself. Forcing one grammar across both providers loses interpretability on whichever convention it doesn’t match, and hand-coding a custom markers.shape + markers.fill pair for every consumer who changes provider is friction we don’t want.

Decision

Each preset owns its shape + fill grammar.

  • Opta — always circles. fill = outcome ? accent : transparent; strokeWidth lifts for goals. No xG colour ramp (Opta’s xG field is sparser and not the editorial focus). Legend is a shape-outline pair, not a gradient.
  • StatsBomb — shapes switch on context / bodyPart: hexagon (foot), circle (header), square (set-piece), triangle (corner), diamond (other). fill = interpolate(colorScale, clampProbability(xg)). Legend is a colour gradient bar plus a shape-glyph key.
  • Missing xG under StatsBomb preset — falls through to an outcome-colour fallback and hides the gradient legend, so sparse datasets still render.

Consequences

  • Mixing Opta and StatsBomb shots in one chart is not supported out of the box. Consumers pick a preset or override both markers.shape and markers.fill.
  • Legend composition is preset-dependent: shape-only under Opta, gradient + glyph key under StatsBomb. The compute model surfaces both pieces so renderers don’t reinvent the split.
  • Shape legend is omitted entirely when the dataset collapses to a single shape — no “key” for a one-entry category.
  • GoalMouthShotChart keeps its own diamond-for-goal / circle-for-shot grammar independent of preset; it’s an outcome-focused view by construction.
← All decisions