Show the Python (data and shared helpers for this chapter’s charts and diagrams)
import logging
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch, Rectangle, Ellipse
from gridiron import Play, Player, style, technique
from gridiron.data import nfl, pbp
logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR)
style.apply()
RED = style.SERIES[7] # dead money, and the bill for a choice
PURPLE = style.SERIES[6] # rings: the player a diagram is about
GREEN = "#0f7a55" # darker aqua, for text and boxes on the light page
GOLD = style.SERIES[3]
# League-wide salary cap by league year, $ millions (NFL announcements; see the notes).
CAP = {2011: 120.0, 2012: 120.6, 2013: 123.0, 2014: 133.0, 2015: 143.28, 2016: 155.27, 2017: 167.0,
2018: 177.2, 2019: 188.2, 2020: 198.2, 2021: 182.5, 2022: 208.2, 2023: 224.8, 2024: 255.4,
2025: 279.2, 2026: 301.2}
# ---------------------------------------------------------------- contracts (Over the Cap, via nflverse)
CONTRACTS = nfl().load_contracts().to_pandas()
# Every contract row carries the player's whole year-by-year cap history; keep one row per player-year-team.
_rows, _seen = [], set()
for rec in CONTRACTS.itertuples():
if rec.season_history is None:
continue
for s in rec.season_history:
y = s.get("year")
if not (isinstance(y, str) and y.isdigit()) or not s.get("team"):
continue
k = (rec.otc_id, y, s["team"])
if k in _seen:
continue
_seen.add(k)
_rows.append((rec.otc_id, rec.player, rec.position, int(y), s["team"], s["cap_number"] or 0.0,
s.get("base_salary") or 0.0, s.get("prorated_bonus") or 0.0))
HIST = pd.DataFrame(_rows, columns=["otc", "player", "pos", "year", "team", "cap", "base", "prorated"])
NICK = {"49ers": "SF", "Bears": "CHI", "Bengals": "CIN", "Bills": "BUF", "Broncos": "DEN", "Browns": "CLE",
"Buccaneers": "TB", "Cardinals": "ARI", "Chargers": "LAC", "Chiefs": "KC", "Colts": "IND",
"Commanders": "WAS", "Washington": "WAS", "Redskins": "WAS", "Cowboys": "DAL", "Dolphins": "MIA",
"Eagles": "PHI", "Falcons": "ATL", "Giants": "NYG", "Jaguars": "JAX", "Jets": "NYJ", "Lions": "DET",
"Packers": "GB", "Panthers": "CAR", "Patriots": "NE", "Raiders": "LV", "Rams": "LA", "Ravens": "BAL",
"Saints": "NO", "Seahawks": "SEA", "Steelers": "PIT", "Texans": "HOU", "Titans": "TEN", "Vikings": "MIN"}
GROUP = {"QB": "QB", "RB": "RB", "FB": "RB", "WR": "WR", "TE": "TE", "LT": "OL", "LG": "OL", "C": "OL",
"RG": "OL", "RT": "OL", "IDL": "IDL", "ED": "EDGE", "LB": "LB", "CB": "CB", "S": "S",
"K": "ST", "P": "ST", "LS": "ST"}
GROUP_NAME = {"QB": "Quarterback", "EDGE": "Edge rusher", "OL": "Offensive line", "WR": "Wide receiver",
"CB": "Cornerback", "IDL": "Interior DL", "S": "Safety", "LB": "Linebacker", "TE": "Tight end",
"RB": "Running back"}
# Team-season spending by position group, 2014-2025, as a share of what the team spent on players
# who were on the roster (dead money is not in this data, so shares are of 'live' cap spending).
H = HIST[HIST.year.between(2014, 2025)].copy()
H["abbr"] = H.team.map(NICK)
H["grp"] = H.pos.map(GROUP)
H = H.dropna(subset=["abbr", "grp"])
SPEND = H.groupby(["year", "abbr", "grp"]).cap.sum().unstack("grp").fillna(0.0)
SHARE = SPEND.div(SPEND.sum(axis=1), axis=0)
# Regular-season records and dropback efficiency for the same team-seasons.
_s = nfl().load_schedules().to_pandas()
_s = _s[(_s.game_type == "REG") & _s.season.between(2014, 2025) & _s.home_score.notna()].copy()
_fix = {"OAK": "LV", "SD": "LAC", "STL": "LA"}
_s["home_team"] = _s.home_team.replace(_fix)
_s["away_team"] = _s.away_team.replace(_fix)
_tie = 0.5 * (_s.home_score == _s.away_score)
_rec = pd.concat([
pd.DataFrame({"year": _s.season, "abbr": _s.home_team, "w": (_s.home_score > _s.away_score) + _tie}),
pd.DataFrame({"year": _s.season, "abbr": _s.away_team, "w": (_s.away_score > _s.home_score) + _tie})])
WINPCT = _rec.groupby(["year", "abbr"]).w.mean().rename("winpct")
_p = pbp(range(2014, 2026), columns=["season", "season_type", "posteam", "qb_dropback", "epa", "down"])
_p = _p[(_p.season_type == "REG") & (_p.qb_dropback == 1) & _p.epa.notna() & _p.down.notna()]
_p["posteam"] = _p.posteam.replace(_fix)
DB_EPA = _p.groupby(["season", "posteam"]).epa.mean().rename("db_epa")
DB_EPA.index.names = ["year", "abbr"]
TEAMS = SHARE.join(WINPCT, how="inner").join(DB_EPA)
R_QB_PRICE = np.corrcoef(TEAMS.QB, TEAMS.winpct)[0, 1]
R_QB_PLAY = np.corrcoef(TEAMS.db_epa, TEAMS.winpct)[0, 1]
R_BY_GROUP = {g: np.corrcoef(TEAMS[g], TEAMS.winpct)[0, 1] for g in GROUP_NAME}
N_TEAMSEASONS = len(TEAMS)
# The market's verdict: the ten richest active contracts at each position, as a share of the cap
# in the year each was signed (Over the Cap's APY / cap). One row per player, his newest deal.
# Over the Cap codes tackles as LT and RT; both count as one group, as the franchise tag counts them.
MKT_GROUP = {"QB": "Quarterback", "ED": "Edge rusher", "WR": "Wide receiver", "LT": "Offensive tackle",
"RT": "Offensive tackle", "IDL": "Interior DL", "CB": "Cornerback", "S": "Safety", "LB": "Off-ball linebacker",
"TE": "Tight end", "RB": "Running back", "LG": "Guard or center", "RG": "Guard or center",
"C": "Guard or center"}
_act = CONTRACTS[(CONTRACTS.is_active == True) & CONTRACTS.apy_cap_pct.notna()] # noqa: E712
_act = _act.sort_values("year_signed").drop_duplicates("otc_id", keep="last")
_act = _act.assign(grp=_act.position.map(MKT_GROUP)).dropna(subset=["grp"])
TOP10 = (_act.sort_values("apy_cap_pct", ascending=False).groupby("grp").head(10)
.groupby("grp").apy_cap_pct.agg(["mean", "max", "min"]).sort_values("mean"))
_ot10 = _act[_act.position.isin(["LT", "RT"])].sort_values("apy_cap_pct", ascending=False).head(10)
N_RT_TOP10 = int((_ot10.position == "RT").sum()) # right tackles among the ten richest tackle deals
def pct(x, d=0):
return f"{100 * x:.{d}f}%"
def money(x):
"""$ millions -> '$1.2 million' / '$53 million'."""
return f"${x:,.1f} million" if x < 10 else f"${x:,.0f} million"
def say(ax, x, y, text, color=style.INK_2, fontsize=7.5, ha="center", va="center", **kw):
return ax.text(x, y, text, fontsize=fontsize, color=color, ha=ha, va=va, zorder=9,
bbox=dict(boxstyle="round,pad=0.2", fc=style.SURFACE, ec="none", alpha=0.92), **kw)