Skip to content

yureed/tmviz

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tmviz

PyPI version Python versions License: MIT GitHub stars

Single-match team report generator for football. Feed it one SPADL-style event CSV; get back an 18-page report (per-team passing, carries, defensive activity, individual maps, shot map, match-flow momentum, top performers) plus a stitched PDF.

python -m tmviz make <match.csv> --home X --away Y [...flags]   # one-shot, scriptable
python -m tmviz wizard <match.csv>                              # interactive prompts
python -m tmviz render <config.yml>                             # re-render a saved config
python -m tmviz pages                                           # list available pages

Install

git clone https://github.com/yureed/tmviz.git
cd tmviz
pip install -e .
playwright install chromium             # one-time

Quickstart

python -m tmviz make match.csv \
    --home "Arsenal" --away "Atletico" \
    --matchday 35 --date 2026-04-26 \
    --venue "Emirates Stadium" \
    --competition "Champions League 25/26" \
    --out-dir out/arsenal_atletico

Renders 18 PNGs and one combined PDF to out/arsenal_atletico/. Run with --help to see every flag.

Python API

from tmviz import generate_report

generate_report(
    csv="match.csv",
    home="Arsenal", away="Atletico",
    matchday=35, date="2026-04-26",
    venue="Emirates Stadium",
    competition="Champions League 25/26",
    out_dir="out/arsenal_atletico",
)

Returns {"html_paths": [...], "png_paths": [...], "pdf_path": Path}.

Wizard

For interactive use — auto-detects team_ids, lists each detected goal so you can flag own-goals, collects metadata, and saves a YAML config you can re-render later:

python -m tmviz wizard match.csv

Data format

One row per event. Required columns:

column type notes
type_name str event verb — see vocabulary below
team_id int one of two team ids in the file
period_id int 1, 2 (3, 4 if extra time)
time_seconds float seconds within the period
start_x, start_y float Opta 0–100 coordinates
end_x, end_y float same scale

type_name vocabulary — tmviz uses the SPADL standard. The names that map to common concepts:

concept type_name value(s)
pass pass
cross cross
carry (a player moving with the ball) dribble
take-on (1v1 dribble past a defender) take_on
shot shot
direct free-kick shot shot_freekick
penalty shot shot_penalty
corner delivery (in-swinger / out-swinger) corner_crossed
corner played short corner_short
free-kick whipped into the box freekick_crossed
free-kick played short freekick_short
throw-in throw_in
tackle tackle
interception interception
clearance clearance
header (any of above when contested in the air) bodypart_name = head

If you have data from a different schema, you'll need a thin transform to remap your event names to these strings before handing the CSV to tmviz. The vocabulary above is the SPADL convention used by socceraction and most public xT/xG models.

Player names — exactly one of:

  • a player_name column inline in the main CSV (preferred), or
  • a player_id column + a separate file passed via --players-csv (cols: player_id, player_name). tmviz joins it in at load.

Team names come from the --home / --away flags (or wizard prompts). Optional: pass --teams-csv (cols: team_id, team_name) to give the wizard nicer name suggestions.

Recommended (better output if present)

column what improves
result_name success/fail — feeds pass-completion %, take-on success rate, etc.
is_goal flags goals on the shot map and in the goals timeline

Optional (auto-used if present, ignored if not)

column what it does
xG (or xg) sizes shot circles by chance quality, adds team xG totals + an xG column on the tables page, and switches the match-flow chart to xG-based momentum
xT_added per-event expected-threat. If absent, tmviz auto-computes it on load using the bundled Karun Singh xT grid — you only need raw coordinates.

Coordinate orientation

tmviz expects each team's events in their own attacking direction (low x = own goal, high x = opp goal — SPADL canon). If your input uses absolute coordinates (one fixed system where home attacks right and away attacks left), tmviz detects it from per-team mean shot start_x and flips the away team automatically. You'll see Note: detected absolute coords — flipped team_id N in the load output when this happens.

Pages

name what
overview Score, goals timeline, both-team shot dots on a mini pitch, head-to-head stat comparison (possession, shots, xG/xT, pass %, prog passes, prog carries, take-ons, box entries, defensive actions)
passing_home, passing_away Full-pitch open-play pass map per team. Forward = ink, backward = grey, failed = red dotted, progressive = gold. Side panel: top 5 progressive passers + key team rates
network_home, network_away Pass network: nodes at average position sized by passes attempted, edges sized by combination count, top 8 combinations listed
players_pass_home, players_pass_away One mini-pitch per player who featured, showing their passes for the match
carries_home, carries_away All carries (progressive in gold) + take-on attempts (won/lost), top 5 carriers + take-on winners
players_carry_home, players_carry_away One mini-pitch per player, showing their carries + take-ons
defense_home, defense_away Defensive actions heatmap + shape markers (tackle / interception / clearance / aerial duel won-or-lost)
players_defense_home, players_defense_away One mini-pitch per player, showing their defensive actions
shots Both teams' shots on a single full pitch — colored by team, sized by xG (if present), goals haloed in gold
flow Match-flow momentum graph: rolling 5-minute danger signal per team plotted around a zero line (above = home on top, below = away). Uses xG if available, otherwise xT. Goals planted on the zero line.
tables 6 (or 7 with xG) side-by-side per-team tables: top 5 in xT, prog passes, prog carries, take-ons, defensive actions, shots

Use --pages overview,shots,flow,tables (or any subset) to generate fewer pages.

Output

For each match:

  • out/<dir>/01_overview.html18_tables.html
  • One PNG per page (rendered at 2× device scale)
  • One combined PDF: <home>_<score>_<away>_md<n>.pdf

Themes

cream (default) — newsprint paper, ink black, red/gold/blue accents.

To add a theme: drop a dataclass into tmviz/themes/, register it in tmviz/themes/__init__.py:THEMES. Pages read all colors via CSS variables so a theme swap restyles every page.

Adding a new page

  1. Subclass tmviz.pages.base.BasePage and implement build(cfg, df, derived) -> str returning the inner HTML (the shell adds top strip + footer + styles).
  2. Register in tmviz/pages/__init__.py:REGISTRY.
  3. Add the page name to cfg.pages in any config that wants it.

License

MIT.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages