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

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.

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.1.tar.gz (46.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.1-py3-none-any.whl (56.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: tmviz-0.1.1.tar.gz
  • Upload date:
  • Size: 46.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.1.tar.gz
Algorithm Hash digest
SHA256 856fa3666e0ff31b019e679d1eba9f07ee610f1b5bcf6495f09a0b8bb53e600b
MD5 0129bbc6a10663eefe511289ad2f98e2
BLAKE2b-256 6d1459500400349e6717dfbc27e6571720df1ea59af271e660cc793c80d17c69

See more details on using hashes here.

File details

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

File metadata

  • Download URL: tmviz-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 56.6 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 83fdcc55ba7b8e54220a03ea5b0ac44e9b411bf42eca95a404bdb4526cbc3a88
MD5 7604f5f0bc7181af50d789cb963ab28f
BLAKE2b-256 f82cb62f474d0d154a2df6ec89cbcfa9f00ca39481c6ac069f77a4c8d095fe1a

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