📍 Recipe: Drawing a Pass Map#
This example demonstrates how to visualize a player’s passes using Flow to process StatsBomb data and mplsoccer to draw the pitch.
🧰 What You’ll Learn#
How to filter for completed passes
How to extract pass start and end locations
How to use
.assign()to extract nested data as an alternative to using.select()+.rename()How to use
.split_array()to extract the location array into multiple fieldsHow to optimize the flow for better performance
How to plot them using the
penaltyblogPitchclass
Imports#
[1]:
from IPython.display import HTML
from penaltyblog.matchflow import Flow, where_equals, get_field
from penaltyblog.viz import Pitch
import plotly.io as pio
Load the Data#
[2]:
# Load events for a StatsBomb match
match_id = 22912 # Champions League Final 2018/2019
flow = Flow.statsbomb.events(match_id)
Extract the Passes#
[3]:
passes = (
flow.filter(where_equals("player.name", "Harry Kane"))
.filter(where_equals("type.name", "Pass"))
.filter(lambda r: get_field(r, "pass.outcome.name") is None)
.split_array("location", ["start_x", "start_y"])
.split_array("pass.end_location", ["end_x", "end_y"])
.select("start_x", "start_y", "end_x", "end_y")
.rename(start_x="x", start_y="y", end_x="x2", end_y="y2")
.dropna()
)
for pass_ in passes.head(3):
print(pass_)
/Users/martin/repos/penaltyblog/venv/lib/python3.13/site-packages/statsbombpy/api_client.py:21: NoAuthWarning: credentials were not supplied. open data access only
warnings.warn(
{'x': 60.0, 'y': 40.0, 'x2': 43.4, 'y2': 40.3}
{'x': 39.6, 'y': 63.4, 'x2': 39.8, 'y2': 55.0}
{'x': 86.5, 'y': 47.8, 'x2': 75.6, 'y2': 55.6}
Plotting the Passes#
[4]:
pitch = Pitch(
provider="statsbomb",
orientation="horizontal",
view="full",
theme="night",
show_axis=False,
show_legend=False,
width=400,
height=400,
title="Harry Kane – Completed Passes",
)
pitch.plot_arrows(passes)
# NOTE: normally we'd just call `pitch.show()` here, but since
# we're exporting to HTML docs, we need to use `HTML` to export
# the plot
# pitch.show()
HTML(pio.to_html(pitch.fig, include_plotlyjs="cdn"))
/Users/martin/repos/penaltyblog/venv/lib/python3.13/site-packages/statsbombpy/api_client.py:21: NoAuthWarning:
credentials were not supplied. open data access only
[4]: