PassSonar wedge radius scales √-proportional to count, not linearly
Each wedge's outer radius is `√(count / maxCount)`, not `count / maxCount`. A bin with four times the passes has twice the radius — matching how human vision reads wedge area. Aligns with `mplsoccer` and Eliot McKinley's canonical reference.
PassSonar visual-encodingalgorithmfootball-semantics
Context
Three candidates for wedge-length encoding:
- Linear —
r ∝ count. Tall bins overwhelm short bins visually. - √ (area-proportional) —
r ∝ √count. Area reads as proportional to count. Matches perceptual studies and the mplsoccer convention. - Log —
r ∝ log(count). Compresses further; good for highly skewed distributions but misreads in the sparse common case.
The same argument applies here as for ShotMap markers (see
shotmap-marker-size-area-scaled): area-proportional scaling preserves the
implicit “how many” read.
Decision
completedRadius = √(bucket.completed / resolvedMax) and
attemptedRadius = √(bucket.attempted / resolvedMax). Under
colorBy="distance" or "frequency", the same √-transform applies to the
single-wedge radius. Log and linear are explicitly deferred — no
radiusScaling prop in v0.3.
Consequences
- Visual output matches McKinley’s canonical PassSonar and mplsoccer reference implementations; consumers switching from either library read the Campos rendering as expected.
- High-volume directions dominate less; dispersed passing patterns remain legible at the same chart size.
- Consumers wanting log or linear scaling override via the compute-layer
maxCountprop to compress or expand the range, or request the feature as a follow-up decision if that becomes insufficient. - Legend radius samples use the same √-transform so readings stay consistent between legend and plot.