Outcome shot map

A colored-scatter “shot map” for set pieces: every corner/free-kick delivery, plotted where the outcome happened and colored by what that outcome was – short corner, direct shot, second-phase shot, aerial duel (“50/50”), cleared, or which team won the first touch. Goals get a ring around the marker.

wa_setpieces.core.outcomes builds this on top of wa_setpieces.core.phases, adding short-corner detection (a short pass along the byline rather than a cross – inferred from delivery distance, since a corner starts right at the corner arc already) and aerial-duel detection (typeId 44, a contested header – football’s “50/50”).

from pathlib import Path

from wa_setpieces import load_matches
from wa_setpieces.core.outcomes import delivery_outcomes, outcome_summary
from wa_setpieces.viz.plots import plot_set_piece_outcomes

try:
    _here = Path(__file__).resolve().parent
except NameError:
    _here = Path.cwd()
DATA = _here.parent / "tests" / "data" / "sample_match.json"

events = load_matches(DATA)

Every corner, classified:

corner_outcomes = delivery_outcomes(events, "corner")
corner_outcomes
matchId delivery_event_id set_piece_type contestantId playerId playerName delivery_outcome x y is_goal aerial_winner_contestant_id aerial_winner_player_id aerial_winner_player_name
0 sample_match 191 corner f2yd0yzt0om6qhks9gbowu1d6 d6gphu89283pngbaenacu1cr9 R. Jaramillo first_touch_lost 91.7 28.2 False NaN NaN NaN
1 sample_match 223 corner cxb4hqite921i36gwrezdts7c cebzrizhi195acmaw8c4cku09 A. Tobar first_touch_won 99.3 74.8 False NaN NaN NaN
2 sample_match 404 corner cxb4hqite921i36gwrezdts7c cebzrizhi195acmaw8c4cku09 A. Tobar first_touch_lost 91.1 50.5 False NaN NaN NaN
3 sample_match 482 corner f2yd0yzt0om6qhks9gbowu1d6 c9htznfxd2gjo5s3klq2tvlqt D. Armas first_touch_lost 88.3 42.2 False NaN NaN NaN
4 sample_match 610 corner f2yd0yzt0om6qhks9gbowu1d6 c74dqd8wbe059xsmdo2twmec4 S. Vasquez second_phase_shot 91.1 67.3 False NaN NaN NaN
5 sample_match 613 corner f2yd0yzt0om6qhks9gbowu1d6 c74dqd8wbe059xsmdo2twmec4 S. Vasquez aerial_duel 96.0 61.1 False cxb4hqite921i36gwrezdts7c eu1htvf3chz0kcrl5paflxzv9 Deyverson
6 sample_match 723 corner f2yd0yzt0om6qhks9gbowu1d6 c74dqd8wbe059xsmdo2twmec4 S. Vasquez short_corner 95.7 89.9 False NaN NaN NaN
7 sample_match 730 corner f2yd0yzt0om6qhks9gbowu1d6 9k61c9b8xjgh6jy6tziw11905 P. Velasco second_phase_shot 84.5 46.7 False NaN NaN NaN
8 sample_match 786 corner f2yd0yzt0om6qhks9gbowu1d6 1ucqsxxm3m3imvujk6av8c0oa V. Burgoa first_touch_lost 90.8 49.4 False NaN NaN NaN


fig, ax = plot_set_piece_outcomes(corner_outcomes, title="Corner outcomes")
plot 13 outcome shot map

Free kicks spread across the whole pitch, not just the box – they’re taken from wherever the foul was:

fk_outcomes = delivery_outcomes(events, "free_kick")
fig, ax = plot_set_piece_outcomes(fk_outcomes, title="Free-kick outcomes")
plot 13 outcome shot map

Rolled up per team:

outcome_summary(events, "corner")
contestantId delivery_outcome count
0 cxb4hqite921i36gwrezdts7c first_touch_lost 1
1 cxb4hqite921i36gwrezdts7c first_touch_won 1
2 f2yd0yzt0om6qhks9gbowu1d6 aerial_duel 1
3 f2yd0yzt0om6qhks9gbowu1d6 first_touch_lost 3
4 f2yd0yzt0om6qhks9gbowu1d6 second_phase_shot 2
5 f2yd0yzt0om6qhks9gbowu1d6 short_corner 1


Gallery generated by Sphinx-Gallery