Skip to main content

Set-piece metrics and mplsoccer pitch visualizations (penalties, kick-offs, free kicks, corners, throw-ins, goal kicks) from Opta F24 event data, including second phases, xT, zones and retention

Project description

wa-setpieces

Set-piece metrics for football (soccer) matches from Opta / Stats Perform F24 event-feed JSON exports: penalties, kick-offs, free kicks, corners, throw-ins and goal kicks.

Given a raw F24 match file, this package tags every set-piece restart, aggregates attempts/success rates by team and player, tracks pass end locations for delivery maps, and links each set piece to the shot or goal it produced (via Opta's assist-chain qualifier). It also covers, for corners and free kicks specifically: second-phase detection, Expected Threat (xT), pitch zones/thirds/channels, and possession retention — with pitch plots built on mplsoccer.

Corner delivery map drawn with mplsoccer

Full documentation, with a runnable plot gallery: https://waltzinganalytics.readthedocs.io

Install

pip install wa-setpieces

Not yet published to PyPI? Install from source instead:

git clone https://github.com/marclamberts/waltzinganalytics.git
cd waltzinganalytics
pip install -e .

Quickstart

from wa_setpieces import load_events, set_piece_summary

match = load_events("match.json")
summary = set_piece_summary(match.events)
print(summary)
              contestantId set_piece_type  attempts  successful  success_rate  shots  goals
cxb4hqite921i...      corner         2           1         0.500      1      0
cxb4hqite921i...   free_kick        12           9         0.750      0      0
cxb4hqite921i...   goal_kick         8           5         0.625      0      0
cxb4hqite921i...    kick_off         1           1         1.000      0      0
cxb4hqite921i...    throw_in        20          16         0.800      1      0
...

Second phases, xT, zones and retention

from wa_setpieces import (
    second_phases, second_phase_summary,   # corner/free-kick second-phase shots
    retention_detail, retention_rate,      # possession retained N seconds later
    add_thirds, add_channels, add_zone_grid,  # pitch location tagging
    XTModel, set_piece_delivery_xt, set_piece_xt_summary,  # Expected Threat
)

second_phases(match.events, "corner")           # per-corner: cleared / first-phase shot / second-phase shot
second_phase_summary(match.events, "free_kick") # per-team roll-up

retention_rate(match.events, "corner")          # per-team: % of corners where the ball is retained ~8s later

tagged = add_thirds(match.events)               # defensive_third / middle_third / attacking_third
tagged = add_channels(tagged, n=5)              # wide / half-space / central

model = XTModel.fit(match.events)               # fit an xT grid (fit on many matches for real use!)
set_piece_xt_summary(match.events, "corner", model)  # total/average xT added per team

All four are derived heuristics, not raw Opta fields — see docs/source/advanced.rst (or the hosted docs) for the exact assumptions and tunable thresholds behind each one.

Plots

pip install -e ".[viz]"   # matplotlib + mplsoccer
from wa_setpieces.viz import (
    plot_delivery_map,      # arrow map of deliveries, colored by outcome
    plot_zone_heatmap,      # where events happen, gridded onto the pitch
    plot_xt_grid,           # a fitted XTModel's grid, as a heatmap
    plot_second_phase,      # one corner/free-kick's phase sequence, numbered
    plot_team_comparison,   # grouped bars: both teams, every set-piece type
    plot_xt_added_bars,     # diverging bar chart of xT added per delivery
    plot_corner_sonar,      # polar plot of delivery angle + distance
    plot_match_timeline,    # every set piece on one shared match-minute axis
    plot_dashboard,         # one-figure report card combining several of the above
)

plot_delivery_map(delivery_locations(match.events, "corner"), title="Corner deliveries")
plot_dashboard(match.events, team_id, set_piece_type="corner")  # the "hero" figure

Every plotting function returns (fig, ax) (plot_dashboard returns just fig, being multi-panel) for further customization. Colors are assigned by the job they do — a validated categorical palette for team identity, a status pair for success/fail, single-hue sequential ramps for magnitude, and a diverging pair for signed quantities like xT added — not picked for looks; see wa_setpieces/theme.py. See the gallery for all nine plots with full source code.

Command line

wa-setpieces match.json
wa-setpieces match.json --csv summary.csv
wa-setpieces match.json --xt   # also fit + print xT for this match (illustrative on one match)

What counts as a set piece

Type Detected on Opta qualifierId
Penalty shot event (miss/post/saved/goal) 9
Kick-off pass event 279
Free kick pass event (corners excluded) 5
Corner pass event 6
Throw-in pass event 107
Goal kick pass event 124

These qualifier IDs are the standard Opta/Stats Perform F24 vocabulary and were cross-checked against a real match export (see tests/data/sample_match.json and tests/test_filters.py): tagged events line up with their expected pitch location (corner arc, touchline, centre spot, six-yard line).

Package layout

  • wa_setpieces.loader — parse F24 JSON into a tidy pandas.DataFrame; load_events_multi stacks a whole season.
  • wa_setpieces.constants — Opta typeId / qualifierId reference.
  • wa_setpieces.filters — extract/tag each set-piece type.
  • wa_setpieces.metrics — team/player counts, success rates, delivery locations.
  • wa_setpieces.chains — link set pieces to the shots/goals they produced.
  • wa_setpieces.zones — pitch thirds, channels and a configurable zone grid.
  • wa_setpieces.phases — second-phase detection for corners/free kicks.
  • wa_setpieces.retention — possession retention after any restart.
  • wa_setpieces.xt — grid-based Expected Threat (xT), fit from data.
  • wa_setpieces.viz — mplsoccer/matplotlib plots: delivery maps, heatmaps, sonar, timeline, dashboard (optional viz extra).
  • wa_setpieces.theme — the validated color palette every plot draws from.
  • wa_setpieces.cliwa-setpieces command-line tool.

Development

pip install -e ".[dev]"
pytest

Releasing

Publishing to PyPI is automated via GitHub Actions trusted publishing (.github/workflows/publish.yml) — no API token stored anywhere. One-time setup (only a PyPI project owner can do this, since it requires logging into PyPI):

  1. On PyPI: https://pypi.org/manage/account/publishing/ → add a pending trusted publisher with project name wa-setpieces, owner marclamberts, repository waltzinganalytics, workflow publish.yml, environment pypi.
  2. From then on, publishing a GitHub Release (or pushing a v* tag) builds the sdist/wheel and uploads them automatically.

Docs

Docs are built with Sphinx (pydata-sphinx-theme + sphinx-gallery, the same stack mplsoccer's docs use) and hosted on Read the Docs (.readthedocs.yaml at the repo root). The gallery under examples_gallery/ is executed at build time, so its plots and DataFrame outputs are always current. To build locally:

pip install -e ".[docs]"
sphinx-build -b html docs/source docs/_build/html

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

wa_setpieces-0.4.0.tar.gz (37.3 kB view details)

Uploaded Source

Built Distribution

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

wa_setpieces-0.4.0-py3-none-any.whl (34.8 kB view details)

Uploaded Python 3

File details

Details for the file wa_setpieces-0.4.0.tar.gz.

File metadata

  • Download URL: wa_setpieces-0.4.0.tar.gz
  • Upload date:
  • Size: 37.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wa_setpieces-0.4.0.tar.gz
Algorithm Hash digest
SHA256 26962981bddb348c2a2525384b0717309b6fe1282e75614039d0ea23717a53f6
MD5 e3a58578793d9568dc355a0e780cee7a
BLAKE2b-256 01203cd58b1b73a156cd21f663c9d1edf03a8ee787fdc20510bdc48c515180e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for wa_setpieces-0.4.0.tar.gz:

Publisher: publish.yml on marclamberts/waltzinganalytics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wa_setpieces-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: wa_setpieces-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 34.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wa_setpieces-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d7a46fa79f4240475924da5c8e3b0c81b2a8e07439efee2a766b9ae0d146302b
MD5 0b2119cfc9b4ee6c56062290ad7c9e76
BLAKE2b-256 ed148285d7ca6415505454d4b2f1cadea1d7ee555cf22fe5000c158bbb46df6e

See more details on using hashes here.

Provenance

The following attestation bundles were made for wa_setpieces-0.4.0-py3-none-any.whl:

Publisher: publish.yml on marclamberts/waltzinganalytics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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