# Load in the Pitch() function from the mlpsoccer module to avoid having to build your own football pitch in a plot
from mplsoccer.pitch import Pitch
# pandas and numpy modules are loaded as pd and np to help with data handling
import pandas as pd
import numpy as np
# Using pandas' read_csv() function you can read in the snippets of tracking data'
# The function need you to write r'PATH TO YOUR DATA'
home = pd.read_csv(r'C:\\Users\\YOUR_USER\\Desktop\\Github\\DFDA\\Data\\Tracking Data\\home.csv')
away = pd.read_csv(r'C:\\Users\\YOUR_USER\\Desktop\\Github\\DFDA\\Data\\Tracking Data\\away.csv')
info = pd.read_csv(r'C:\\Users\\YOUR_USER\\Desktop\\Github\\DFDA\\Data\\Tracking Data\\info.csv')
# Again using head() you can take a look at the data
home.head()
# You can select a series of frames by first using unique() and then [:x] to select x number of frames
frames = info.frameIdx.unique()[:1]
frames
# Subsetting the full dataset to only include the select frames is done by the isin() function
homePlot = home[home['frameIdx'].isin(frames)]
awayPlot = away[away['frameIdx'].isin(frames)]
ballPlot = info[info['frameIdx'].isin(frames)]
# To allow for an easier annotation of shirt numbers later you can extract the x, y, and shirtnumber column from each team
homeNumbers=homePlot[["x","y","number","team"]]
awayNumbers=awayPlot[["x","y","number","team"]]
# And then combine them, one data set after the other by using pandas' concat() function
numbers = pd.concat([homeNumbers, awayNumbers], ignore_index=True)
# To understand how the code below adds shirt numbers to the plot - a breif description of loops are required
# If you already understand loops just skip to the plot
# You can make python go through certain things one step at a time by using loops
# The following loop prints all the shirt numbers in the numbers data frame one at a time
for i in range(0,len(numbers)):
print(numbers.team[i],numbers.number[i], "- row", i+1, "done")
# This prints the team, the shirt number and the row number+1 (as python starts counting from 0)
# It might go faster than you can notice, but the code does run one row at a time
# If you have chosen a single frame, the following will plot that frame
# If you have chosen multiple frames, the plot will include all frames and be useless
# First start by plotting a pitch, this time using second spectrum coordinates and setting the length and width of the pitch
pitch = Pitch(pitch_type='secondspectrum', # Using second spectrum to fit with tracking data
pitch_width=68, pitch_length=105, # Setting pitch size to danish standard
goal_type='box', # Add "nets" to goals
pitch_color='grass', # Setting the color to be grass
line_color='white', # Setting the lines on the pitch to be white
stripe=True, # Add stripes to the grass color
corner_arcs=True, # Add corner arcs
)
fig, ax = pitch.draw(figsize=(16,10.4))
# Then for each team plot the players by using a pitch.scatter() function
scatter = pitch.scatter(homePlot.x, # x coordinate
homePlot.y, # y coordinate
ax=ax, # What plot to add them to
edgecolor='black', # Edge color of the point
c=homePlot.GK, # Color of the point
s=250, # Size of the points
cmap='autumn' # Color map - field players will be red and keeper yellow
)
scatter = pitch.scatter(awayPlot.x, # x coordinate
awayPlot.y, # y coordinate
ax=ax, # What plot to add them to
edgecolor='black', # Edge color of the point
c=awayPlot.GK, # Color of the point
s=250, # Size of the points
cmap='Set2' #Color map - field players will be green and keeper grey
)
# Add the ball first at a larger size, then a smaller size to create a point inside a point
scatter = pitch.scatter(ballPlot.xBall, # x coordinate
ballPlot.yBall, # y coordinate
ax=ax, # What plot to add them to
edgecolor='black', # Edge color of the point
c='black', # Color of the point
s=100 # Size of the points
)
scatter = pitch.scatter(ballPlot.xBall, # x coordinate
ballPlot.yBall, # y coordinate
ax=ax, # What plot to add them to
edgecolor='black', # Edge color of the point
c='white', # Color of the point
s=40 # Size of the points
)
# Lastly loop over all the rows in the numbers dataframe and annotate each player with his shirt number
for i in range(0,len(numbers)): # Loops from 0 to the number of rows - remember that python starts counting at 0
annotate = pitch.annotate(text=numbers.number[i], # Which text is printed - here the shirtnumber of row number i
xy=(numbers.x[i],numbers.y[i]), # Where to print it - here x,y of row number i
ax=ax, # What plot to add them to
va='center', # Align the text at vertical center of x,y
ha='center' # Align the text at horizontal center of x,y
)
# To move from a single plot to an animation you need to choose a series of frames
# The snippet variable has been created to split the data into segments each containing a goal - so you can subset on that
# Or you can choose a series of frames like above - or subset based on the game clock by looking at info.gameClock
# To plot it faster, you can plot every second frame - hence you can use [::2]
frames = info.loc[info["snippet"]==1].frameIdx.unique()[::2]
df_ball=info[info['frameIdx'].isin(frames)]
df_home=home[home['frameIdx'].isin(frames)]
df_away=away[away['frameIdx'].isin(frames)]
# The function which creates and saves the plot are located in the Jupyter Notebook folder
# To some extend it follows the ideas already used to plot a single frame
from functions import save_match_clip
# Saving the animation to your locals folder - might take a while depending on the number of frames!
# Creators run time was 8+ minutes for all frames in snippet 1
save_match_clip(df_ball, df_home, df_away, fpath="C:\\Users\\YOUR_USER\\Desktop\\Github\\DFDA\\Local", fname='Clip', frames_per_second=12.5)