Metrics 101

A compact reference for the Boxscores tabs: 9-cat, Performance, Pressure, and Opportunity.

General rules (applies across tabs)

  • Opportunity metrics have two families:
    • Per-minute rates (e.g. OOR, AOR, 3POR) are only computed when a player logs ≥ 8 minutes. Otherwise they are stored as NULL and shown as .
    • Absolute & normalized opportunity metrics (e.g. OOR_abs / OOR_norm) do not use a minutes cutoff because they already account for minutes played via volume/shares.
  • Missing tracking fields stay missing: if tracking inputs (touches/passes/rebound chances) aren’t available or are detected as invalid for a team-game, the dependent metrics remain NULL (not forced to 0).
  • Per-minute normalization: for any stat X, X_per_min = X / minutes.
  • Per-36 (Performance tab): X_per36 = X × (36 / minutes).
  • Per-100 possessions (Performance tab): X_per100 = X × (100 / possessions).
  • Pace + role normalization: normalized opportunity metrics are computed using team-game shares, then adjusted by role (minutes share):
    X_norm = (X_abs / team_X_abs) / minutes_share

Inputs (where numbers come from)

  • Minutes: from traditional boxscore.
  • FGA / FTA / 3PA: from traditional boxscore.
  • Touches / Passes / Secondary Assists: from player tracking.
  • Free throw assists: from player tracking.
  • Rebound chances: from player tracking (chance-based, not rebounds made).
  • Possessions: from advanced boxscore (used for shares / context).
  • Usage%: from usage boxscore (used for TOI-T).
  • Deflections / Contested shots: from hustle boxscore.
  • Loose balls recovered: from hustle boxscore.
  • Matchup possessions: from defensive boxscore (used in DPOR when available).

Performance metrics (outcomes)

What this tab is for
Outcome-only metrics: raw box-score results plus derived rate views that remove minutes and pace.
Core shooting
2P% = (FGM − 3PM) / (FGA − 3PA)
eFG% = effective_field_goal_percentage (advanced)
TS% = true_shooting_percentage (advanced)
FT% on volume is interpreted alongside FTM/FTA (absolute, per-36, per-100).
Core counting stats (all stored as abs / per36 / per100)
PTS, REB, AST, STL, BLK, TOV, plus attempts/makes (FGM/FGA, FTM/FTA, 3PM/3PA, 2PM/2PA, OREB/DREB).
Efficiency & discipline
PTS/POSS = points / possessions
FTr = FTA / FGA
3Rate = 3PA / FGA
Advanced outcomes also shown: AST/TOV, assist ratio, turnover ratio, rebound% splits.
Rebound conversion (outcome skill proxy)
REB/CH = rebounds_total / rebound_chances_total

Pressure metrics (teammate pressure on opportunity)

What this tab is for
Pressure describes how teammates’ roles “crowd out” a player’s opportunity, and helps reason about redistribution when high-usage teammates are absent.
Role vector (used for peer overlap)
v = [touches_share, passes_share, possessions_share, usage_share]
usage_share is computed within team-game as usage_percentage / team_sum(usage_percentage).
Crowdedness (lumpy vs diffuse)
HHI_excl(i, X) = sum over teammates j != i of (share(j, X) ^ 2)
ENT_excl(i, X) = sum over teammates j != i of (-share(j, X) * ln(share(j, X)))
Higher HHI / lower entropy means teammates’ share is concentrated in a few players (redistribution tends to be “lumpy” when one leaves).
Peer-overlap pressure (who benefits)
w_ij = max(0, cosine(v_i, v_j))
peer_pressure_X(i) = sum over teammates j != i of (w_ij / sum_k w_ik) * share(j, X)
High peer pressure means “players most similar to me are already consuming resource X”, so this player is a likely beneficiary when that similar-role teammate is out.
Resources X tracked
Usage, possessions, touches, passes, scoring volume, 3PA volume, assist opportunity, rebound opportunity.
Teammate-take (simple pressure baseline)
A complementary view that answers: how much of a resource is taken by all teammates (not just the top 1-2).
minutes_teammate_take = 1 - minutes_share
possessions_teammate_take = 1 - possessions_share
touches_teammate_take = 1 - touches_share
passes_teammate_take = 1 - passes_share
For absolute resources (team totals), we compute 1 - (player_abs / team_abs), e.g.:
sor_abs_teammate_take = 1 - (sor_abs / team_sor_abs)
three_abs_teammate_take = 1 - (three_abs / team_three_abs)
aor_abs_teammate_take = 1 - (aor_abs / team_aor_abs)
ror_abs_teammate_take = 1 - (ror_abs / team_ror_abs)
Usage is handled as “usage volume”:
usage_poss_abs = (usage_percentage / 100) * possessions
usage_teammate_take = 1 - (usage_poss_abs / team_usage_poss_abs)
Interpretation: higher teammate-take means a smaller share for the player (more of the team’s resource is already “taken” by teammates). These are only computed when their required components/denominators are available; otherwise they remain NULL.

Opportunity metrics (role + involvement)

Scoring Attempts
scoring_attempts = FGA + 0.44 * FTA
A proxy for “how many times a player tried to score”, independent of efficiency.
OOR — Offensive Opportunity Rate
oor = touches_per_min + 0.8 * scoring_attempts_per_min + 0.6 * passes_per_min
OOR_abs — Offensive Opportunity (Absolute)
oor_abs = touches + 0.8 * scoring_attempts + 0.6 * passes
Volume-based (accounts for minutes played via counts).
OOR_norm — Offensive Opportunity (Normalized)
oor_norm = (oor_abs / team_oor_abs) / minutes_share
Pace-invariant (share-based) and role-adjusted (minutes_share). Values around 1.0 are “as expected for minutes”.
SOR — Scoring Opportunity Rate
sor = scoring_attempts_per_min
The table also stores sor_per_36 = sor * 36.
SOR_abs — Scoring Opportunity (Absolute)
sor_abs = scoring_attempts
SOR_norm — Scoring Opportunity (Normalized)
sor_norm = (sor_abs / team_sor_abs) / minutes_share
3POR — Three-Point Opportunity Rate
three_por = 3PA_per_min
Additional stored fields (not always shown): three_per_touch = 3PA / touches (3PA per touch) and three_por_adj (currently NULL; requires uncontested-3PA inputs).
three_abs — Three-Point Opportunity (Absolute)
three_abs = 3PA
3_norm — Three-Point Opportunity (Normalized)
three_norm = (three_abs / team_three_abs) / minutes_share
3/TCH — Three-Point Trigger Rate
three_per_touch = 3PA / touches
How often a touch turns into a three-point attempt.
AOR — Assist Opportunity Rate
aor = passes_per_min + 0.5 * touches_per_min + secondary_assists_per_min
AOR_abs — Assist Opportunity (Absolute)
aor_abs = passes + 0.5 * touches + secondary_assists
AOR_norm — Assist Opportunity (Normalized)
aor_norm = (aor_abs / team_aor_abs) / minutes_share
DPOR — Defensive Play Opportunity Rate
This is designed to capture defensive involvement without using steals/blocks (outcomes).
base = deflections_per_min + contested_shots_per_min
DPOR = base + matchup_possessions_per_min (when matchup possessions are available)
DPOR = matchup_possessions_per_min (when both hustle components are missing)
Steal / Block opportunity
These are tracked separately as components:
stl_or = deflections_per_min
blk_or = contested_shots_per_min
STL_abs = deflections
BLK_abs = contested_shots
STL_norm = (deflections / team_deflections) / minutes_share
BLK_norm = (contested_shots / team_contested_shots) / minutes_share
FTAOR — Free Throw Assist Opportunity
Tracking-derived creation component:
ft_ast_or = free_throw_assists_per_min
ft_ast_abs = free_throw_assists
ft_ast_norm = (free_throw_assists / team_free_throw_assists) / minutes_share
LBROR — Loose Ball Recovery Opportunity
Hustle-derived chaos component:
lbr_or = loose_balls_recovered_total_per_min
lbr_abs = loose_balls_recovered_total
lbr_norm = (loose_balls_recovered_total / team_loose_balls_recovered_total) / minutes_share
ROR — Rebound Opportunity Rate
ror = rebound_chances_total_per_min
Chance-based (opportunity), not rebounds made (outcome).
The table also stores a weighted chance count ror_w = 1.2 * orb_chances + drb_chances and ror_w_per_min = ror_w / minutes.
ROR_abs — Rebound Opportunity (Absolute)
ror_abs = rebound_chances_total
ROR_norm — Rebound Opportunity (Normalized)
ror_norm = (ror_abs / team_ror_abs) / minutes_share
TOI-T — Turnover Opportunity Index (Tracking-style)
toi_t_norm = 0.45 * touches_share + 0.30 * passes_share + 0.15 * possessions_share + 0.10 * usage_percentage_z
Index-style metric (role/pace aware via shares). usage_percentage_z is a team-game z-score of Usage%.
Also stored:
toi_t_abs = 0.45 * touches + 0.30 * passes + 0.15 * possessions
toi_t_rate = toi_t_abs / minutes

Shares (extra context)

  • minutes_share = player_minutes / team_total_minutes
  • touches_share = player_touches / team_total_touches (tracking-only denominator)
  • passes_share = player_passes / team_total_passes (tracking-only denominator)
  • possessions_share = player_possessions / team_total_possessions
  • usage_share = player_usage% / team_sum(usage%)
Implementation note: Opportunity inputs are stored in public.player_opportunity_game, pressure metrics in public.player_opportunity_pressure_game, and derived performance metrics in public.player_performance_game.