By routine
The same pick-one-see-what-it-does reference By set piece gives set pieces, for the layer that describes how a restart was taken – a rule-based taxonomy, a data-driven alternative, and two type-specific layers (throw-ins, penalties) that don’t fit the general shape.
Routine taxonomy
- What it describes
A rule-based
routine_typeper delivery (short / central-six-yard / penalty-area / recycled / deep for corners, an equivalent taxonomy per type), plus geometry (distance, angle, progression, side/third/channel) and a stableroutine_key. For corners/free kicks specifically:delivery_technique("inswinger"/"outswinger", from Opta qualifiers 223/224) andpost_target("near_post"/"far_post"/"central").- Requirements
Any set-piece type – works generically, with extra columns unlocked for corner/free kick.
Compute it
from wa_setpieces import restart_routines, analyze_routines
restart_routines(events, "corner")
analyze_routines(events, "corner", min_taker_attempts=3)
# .detail / .summary / .team_profiles / .taker_profiles / .target_matrix
- Where it’s used
run_workflow()’sroutines/routine_summary/routine_team_profiles/routine_taker_profiles/routine_target_matrixfields, for every type in By set piece.
Data-driven clusters
- What it describes
Deliveries grouped by geometric similarity (k-means over start/end x/y by default) instead of a fixed, hand-picked taxonomy – surfaces whatever patterns a team actually repeats.
- Requirements
The
mlextra (pip install "wa-setpieces[ml]", scikit-learn).
Compute it
from wa_setpieces import cluster_routines, cluster_summary
clustered = cluster_routines(events, "corner", n_clusters=5)
# restart_routines' detail plus `cluster` (int, -1 = unclustered) and
# an auto-generated `cluster_label` (e.g. "short, forward, central")
cluster_summary(clustered) # per-cluster usage/outcome roll-up
- Where it’s used
plot_routine_clusters()in the Gallery;run_workflow’sroutine_clustersfield.
Long throws
- What it describes
The one throw-in pattern that plays like a corner – a direct ball into a crowded box, where a genuine long-throw specialist is a real tactical weapon. Per-player usage/threat, and flick-on/knockdown detection restricted to throws past a distance threshold.
- Requirements
throw_inonly.
Compute it
from wa_setpieces import long_throw_taker_summary, long_throw_second_phases
long_throw_taker_summary(events, min_distance=25.0)
# per-player usage share and threat created (shots/goals via the
# assist-chain link) among throw-ins that travel at least min_distance
long_throw_second_phases(events, min_distance=25.0)
# event-sequence-based flick-on/knockdown detection, restricted to
# those same long throws
- Where it’s used
The throw-in section of By set piece – the closest thing throw-ins have to a value model, since there’s no xT path for this type (see By value model).
Penalty placement
- What it describes
Where in the goal each penalty was placed –
goal_y_norm/goal_h_norm(0-1 across/up the frame),corner_zone(a 3x3 grid),placement_score(distance from center) – plus per-taker conversion rate.- Requirements
penaltyonly – penalties are shots, not passes, detected on shot events rather than the pass-based machinery everything else here uses. Pure geometry, no optional dependency needed.
Compute it
from wa_setpieces import penalty_placement_detail, penalty_taker_summary
penalty_placement_detail(events)
penalty_taker_summary(events)
- Where it’s used
The penalty section of By set piece; shares its goal-mouth geometry with
wa_setpieces.ml.shot_value(By value model).