Note
Click here to download the full example code
Plotting passes
Making a pass map using Statsbomb data
#importing necessary libraries
import matplotlib.pyplot as plt
import numpy as np
from mplsoccer import Pitch, Sbopen
Opening the dataset
We open the data, using SBopen, then we filter the dataframe so that only passes are left, This includes remioing throw-ins.
parser = Sbopen()
df, related, freeze, tactics = parser.event(69301)
passes = df.loc[df['type_name'] == 'Pass'].loc[df['sub_type_name'] != 'Throw-in'].set_index('id')
Making the pass map using iterative solution
Draw the pitch and iterate through the passes. We check if a pass was made by Lucy Bronze. If so, we take the starting coordinates of a pass and plot a circle. Then we subtract the coordinates beginning of the pass from the end of passes in order to draw pass arrows.
#drawing pitch
pitch = Pitch(line_color = "black")
fig, ax = pitch.draw(figsize=(10, 7))
for i,thepass in passes.iterrows():
#if pass made by Lucy Bronze
if thepass['player_name']=='Lucy Bronze':
x=thepass['x']
y=thepass['y']
#plot circle
passCircle=plt.Circle((x,y),2,color="blue")
passCircle.set_alpha(.2)
ax.add_patch(passCircle)
dx=thepass['end_x']-x
dy=thepass['end_y']-y
#plot arrow
passArrow=plt.Arrow(x,y,dx,dy,width=3,color="blue")
ax.add_patch(passArrow)
ax.set_title("Lucy Bronze passes against Sweden", fontsize = 24)
fig.set_size_inches(10, 7)
plt.show()
Making the pass map using mplsoccer functions
Again, we filter out passes made by Lucy Bronze. Then, we take only the columns needed to plot passes - coordinates of start and end of a pass. We draw a pitch and using arrows method we plot the passes. Using scatter method we draw circles where the pass started filter the dataset to completed passes for Lucy Bronze.
mask_bronze = (df.type_name == 'Pass') & (df.player_name == "Lucy Bronze")
df_pass = df.loc[mask_bronze, ['x', 'y', 'end_x', 'end_y']]
pitch = Pitch(line_color='black')
fig, ax = pitch.grid(grid_height=0.9, title_height=0.06, axis=False,
endnote_height=0.04, title_space=0, endnote_space=0)
pitch.arrows(df_pass.x, df_pass.y,
df_pass.end_x, df_pass.end_y, color = "blue", ax=ax['pitch'])
pitch.scatter(df_pass.x, df_pass.y, alpha = 0.2, s = 500, color = "blue", ax=ax['pitch'])
fig.suptitle("Lucy Bronze passes against Sweden", fontsize = 30)
plt.show()
Plotting multiple pass maps on one figure
mplsoccer allows to draw multiple plots on one plot. Let’s demonstrate how to do that by plotting passes made by all of England’s players. To do so we first filter out players from England. We plot 16 pitches in 4 rows and columns. Then, for each player, on a separate axis, their pass map is plotted. As the last step, we remove unnecessary pitches (during 2019 World Cup only 3, not 5, changes were allowed) and set the title.
#prepare the dataframe of passes by England that were no-throw ins
mask_england = (df.type_name == 'Pass') & (df.team_name == "England Women's") & (df.sub_type_name != "Throw-in")
df_passes = df.loc[mask_england, ['x', 'y', 'end_x', 'end_y', 'player_name']]
#get the list of all players who made a pass
names = df_passes['player_name'].unique()
#draw 4x4 pitches
pitch = Pitch(line_color='black', pad_top=20)
fig, axs = pitch.grid(ncols = 4, nrows = 4, grid_height=0.85, title_height=0.06, axis=False,
endnote_height=0.04, title_space=0.04, endnote_space=0.01)
#for each player
for name, ax in zip(names, axs['pitch'].flat[:len(names)]):
#put player name over the plot
ax.text(60, -10, name,
ha='center', va='center', fontsize=14)
#take only passes by this player
player_df = df_passes.loc[df_passes["player_name"] == name]
#scatter
pitch.scatter(player_df.x, player_df.y, alpha = 0.2, s = 50, color = "blue", ax=ax)
#plot arrow
pitch.arrows(player_df.x, player_df.y,
player_df.end_x, player_df.end_y, color = "blue", ax=ax, width=1)
#We have more than enough pitches - remove them
for ax in axs['pitch'][-1, 16 - len(names):]:
ax.remove()
#Another way to set title using mplsoccer
axs['title'].text(0.5, 0.5, 'England passes against Sweden', ha='center', va='center', fontsize=30)
plt.show()
Total running time of the script: ( 0 minutes 2.332 seconds)