Skip to main content

Single-match team report generator for football: 18-page PDF (overview, per-team passing/carries/defense/network, individual maps, shots, momentum, top-performer tables) from SPADL event data.

Project description

tmviz

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tmviz-0.1.0.tar.gz (45.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tmviz-0.1.0-py3-none-any.whl (55.7 kB view details)

Uploaded Python 3

File details

Details for the file tmviz-0.1.0.tar.gz.

File metadata

  • Download URL: tmviz-0.1.0.tar.gz
  • Upload date:
  • Size: 45.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for tmviz-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d0f47f81f7f921591d67d5dfe79e4c17f6348be836b2fa3403d5990bdcca4945
MD5 39c1c4965a44fb4ed79ed072a66fb469
BLAKE2b-256 b0390228c8ebb33aa0b01a33a0bf41b894d906330f5d802174b4bff31083f2fd

See more details on using hashes here.

File details

Details for the file tmviz-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: tmviz-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 55.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for tmviz-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 35d0b78d251c5b35f736aaf3dff5e8a15e890e1a82184ce3bc120ce3a38fd080
MD5 a5408effce7a760d67e7911f03919c58
BLAKE2b-256 ed8d9a83106cfe207eb881f671296996d05860e35b162298ada02e1978f6b25c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page