Defensive positioning — visual EDA¶

Mission: Football defensive positioning. How can tracking and contextual data help us better understand the way players and teams defend?

Dataset: 20 A-League 2024/25 matches (SkillCorner Open Data) — phases of play + dynamic events (pressure, engagements, structure labels). Tracking JSONL stubs are not used here; contextual fields already encode shape, pressure, and marking.

Counts: 8,834 phases · 18,710 possessions · 17,445 on-ball engagements.

In [1]:
from pathlib import Path
from IPython.display import Image, display, Markdown
FIG = Path('output/figures')
print('Figures:', sorted(p.name for p in FIG.glob('*.png')))
Figures: ['01_phase_mix.png', '02_shape_scatter.png', '03_compactness_violin.png', '04_pressure_ladder.png', '05_pressure_x_block_heatmap.png', '06_engagement_outcomes.png', '07_engagement_heatmaps.png', '08_structure_labels.png', '09_line_height_by_block.png', '10_decision_flags.png', '11_pressing_chains.png', '12_team_defense_board.png', '13_engagement_spacing.png', '14_compactness_vs_pressure_gradients.png', '15_third_channel_heatmap.png', '16_free_attackers_by_role.png']

1. Team defensive context (phase mix)¶

Organized blocks dominate minutes; shot rate climbs as the block drops.

In [2]:
display(Image(filename=str(FIG / '01_phase_mix.png')))
No description has been provided for this image

2. Team shape¶

OOP width × length. Shot phases (red) sit toward the compact side of the cloud.

In [3]:
display(Image(filename=str(FIG / '02_shape_scatter.png')))
No description has been provided for this image

3. Compactness¶

Box area / width / length split by shot vs no-shot inside each organized block.

In [4]:
display(Image(filename=str(FIG / '03_compactness_violin.png')))
No description has been provided for this image

4. Pressure¶

On-ball overall_pressure is a steep ladder for shot rate and EPV conceded.

In [5]:
display(Image(filename=str(FIG / '04_pressure_ladder.png')))
No description has been provided for this image

5. Pressure × block¶

Pressure still separates danger inside low, medium, and high blocks.

In [6]:
display(Image(filename=str(FIG / '05_pressure_x_block_heatmap.png')))
No description has been provided for this image

6. Marking / pressing actions¶

Engagement subtypes: volume, regain rate, lead-to-shot.

In [7]:
display(Image(filename=str(FIG / '06_engagement_outcomes.png')))
No description has been provided for this image

7. Where defenders engage¶

Pitch heatmaps by engagement subtype.

In [8]:
display(Image(filename=str(FIG / '07_engagement_heatmaps.png')))
No description has been provided for this image

8. Defensive structure labels¶

Organised defense, number of lines, ball inside shape.

In [9]:
display(Image(filename=str(FIG / '08_structure_labels.png')))
No description has been provided for this image

9. Line height¶

Last defensive line height distributions validate block labels.

In [10]:
display(Image(filename=str(FIG / '09_line_height_by_block.png')))
No description has been provided for this image

10. Defensive decisions¶

Force backward / stop danger / beaten flags vs subsequent shot rate.

In [11]:
display(Image(filename=str(FIG / '10_decision_flags.png')))
No description has been provided for this image

11. Pressing chains¶

Coordinated pressure sequences.

In [12]:
display(Image(filename=str(FIG / '11_pressing_chains.png')))
No description has been provided for this image

12. Team board¶

Which sides defend in a bigger box — and how that relates to shots against.

In [13]:
display(Image(filename=str(FIG / '12_team_defense_board.png')))
No description has been provided for this image

13. Spacing at engagement¶

Distance to ball-carrier by subtype and shot rate by distance bin.

In [14]:
display(Image(filename=str(FIG / '13_engagement_spacing.png')))
No description has been provided for this image

14. Two axes of defense¶

Within-block compactness tertiles vs pressure gradients.

In [15]:
display(Image(filename=str(FIG / '14_compactness_vs_pressure_gradients.png')))
No description has been provided for this image

15. Spatial danger map¶

Possessions that become shots by pitch third × channel.

In [16]:
display(Image(filename=str(FIG / '15_third_channel_heatmap.png')))
No description has been provided for this image

Takeaways for coaches / analysts¶

  • Organized block height sets the base shot rate: low (~18.5%) ≫ medium (~9.0%) > high (~6.0%).
  • Shot phases sit in a smaller OOP bounding box — compactness co-moves with danger, strongest in the low block.
  • On-ball pressure separates outcomes (~2% no pressure → ~21% very high), but high bands are endogenous with already-dangerous moments — treat as context, not pure cause.
  • Keeping the block organised (~2.5% shot rate) and the ball outside the shape (~5.8% vs ~11.5% inside) are the clearest structure signals; line count barely moves.
  • Engagement mix matters: pressing/counter-press regain more often; beaten-by-possession/movement flags precede shots.
  • Team board: mean OOP box area and width profile which A-League sides concede more in organized defense — compactness alone does not rank the table.

Next film questions: (1) moments where the box looks compact but pressure is low; (2) engagements where the defender is beaten by movement; (3) team outliers on the compactness–shot board.