Canonical pitch coordinates: attacker-perspective, x 0→100 own→opposition goal
Every event produced by an adapter is in canonical pitch coordinates before reaching a compute or render layer. x = 0 is the own goal, x = 100 is the opposition goal, y = 0 is attacker's right, y = 100 is attacker's left. No chart re-maps axes; all orientation is a render-time concern.
Context
Football providers use incompatible coordinate systems:
- Opta — bottom-to-top y, absolute coordinates where teams attack one direction per half.
- StatsBomb — top-to-bottom y, attacker-perspective.
- Wyscout / WhoScored — yet another variant.
Without a canonical normalisation, every chart would re-implement axis flipping — inconsistently. Each provider requires its own attack-direction rotation: Opta F24 absolute coordinates need both-axes rotation when a team attacks toward decreasing-x; Opta EG (event-grid) is attack-relative and passes through; StatsBomb needs y-inversion only.
Decision
Every adapter normalises to canonical attacker-perspective:
x∈ [0, 100], 0 = own goal, 100 = opposition goal.y∈ [0, 100], 0 = attacker’s right touchline, 100 = attacker’s left touchline.
Downstream compute and render layers never flip axes. Charts render with
a canonical pitch in mind; the attackingDirection prop on every chart
component ("up" | "down" | "left" | "right") controls visual
orientation at the render layer.
The attackingDirection prop replaces the older orientation +
mirror props across every pitch-based component. Butterfly layouts
(e.g. dual-team comparisons) use
attackingDirection="left" vs "right" instead of CSS scaleX(-1),
so text + glyphs don’t invert alongside the pitch.
Consequences
- Every adapter (
fromOpta,fromStatsBomb, etc.) carries the burden of normalisation. Invariants documented indocs/standards/coordinate-invariants.md. - Do not hand-convert provider data. Run raw events through the
adapter. Fixtures that hand-convert must cite the provider rule they
applied — e.g. Opta y is bottom-to-top, so raw
y=0is the south touchline, which is the attacker’s right when attacking east. - Renderers take
attackingDirection— butterfly layouts don’t need CSS tricks, so labels stay readable. - Pitch-anchored charts are out-of-scope for axis-padding / domain-pad because the pitch IS the bound; shifting the frame has no data-semantic meaning.