{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Load in the Pitch() function from the mlpsoccer module to avoid having to build your own football pitch in a plot\n", "\n", "from mplsoccer.pitch import Pitch\n", "\n", "# Load in the opta functions from the kloppy module to help with loading event data\n", "\n", "from kloppy import opta\n", "\n", "# pandas and numpy modules are loaded as pd and np to help with data handling\n", "# Both of these shorthands are conventions in python\n", "\n", "import pandas as pd\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using the opta.load() function you can now load in the event data without working with troublesome XML files\n", "# Adding additional columns to the to_pandas() function to get player and team names added as columns\n", "\n", "dataset = opta.load(\n", " f7_data=\"C:\\\\Users\\\\YOUR_USER\\\\Desktop\\\\Github\\\\DFDA\\\\Data\\\\Event Data\\\\F7.xml\",\n", " f24_data=\"C:\\\\Users\\\\YOUR_USER\\\\Desktop\\\\Github\\\\DFDA\\\\Data\\\\Event Data\\\\F24.xml\",\n", " coordinates=\"opta\"\n", " \n", ").to_pandas(\n", " additional_columns={\n", " 'player': lambda event: str(event.player),\n", " 'team': lambda event: str(event.team)\n", " }\n", ")\n", "\n", "# Subsetting the data to shots by Vejle BK as you have done in earlier notebooks\n", "\n", "shots=dataset.loc[(dataset['event_type']=='SHOT') & (dataset['team']=='Vejle BK')]\n", "\n", "# To be able to color your plot based on results - you need to convert the result column to a numerical column\n", "# In the code below, this is solved by adding a new colum named \"goal\"\n", "\n", "# Firstly the new column is assigned and given a value of 0\n", "\n", "shots=shots.assign(goal=0)\n", "\n", "# Then you can use numpy's where() function to change the value of goal to 1 when ever the result of the shot was a goal\n", "# where() works just like a if() statement in other languanges\n", "\n", "shots['goal']=np.where(shots.result=='GOAL',1,0)\n", "\n", "# Using head(10) you can inspect if you have done it right - the last of the 10 rows should have a column with goal set to 1\n", "\n", "shots.head(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# To plot a football pitch you can simply use the Pitch() function from mlpsoccer\n", "\n", "pitch = Pitch()\n", "\n", "# To actually show the plot you need to call the function pitch.draw()\n", "# And as a convention in python plots are called fig and ax\n", "\n", "fig, ax = pitch.draw()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Going from a white pitch to something resembling a real pitch is as simple as changing a few settings in the pitch() function\n", "# Like with head(x) Pitch() has multiple settings which can be used to alter the look of the pitch\n", "\n", "# See this link to for further options:\n", "# https://mplsoccer.readthedocs.io/en/latest/gallery/pitch_setup/plot_pitches.html\n", "\n", "pitch = Pitch(pitch_color='grass', # Setting the color to be grass \n", " line_color='white', # Setting the lines on the pitch to be white\n", " goal_type='box', # Add \"nets\" to goals\n", " stripe=True, # Add stripes to the grass color\n", " corner_arcs=True, # Add corner arcs\n", " pitch_type='opta' # Set coordinates to be opta based for your event data to work\n", " )\n", " \n", " \n", "fig, ax = pitch.draw(figsize=(16, 11) # Increase the size of the plot\n", " )\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# To plot some events on the pitch you first call the code from above to create a pitch\n", "\n", "pitch = Pitch(pitch_color='grass', line_color='white', stripe=True, pitch_type='opta',corner_arcs=True,goal_type='box')\n", "fig, ax = pitch.draw(figsize=(16, 11))\n", "\n", "# Then add something to it\n", "# Below is the code to add the shots you subsetted before as points - using scatter\n", "\n", "scatter = pitch.scatter(shots.coordinates_x, # x coordinate\n", " shots.coordinates_y, # y coordinate\n", " ax=ax, # What plot to add them to \n", " edgecolor='black', # Edge color of the point\n", " c=shots.goal, # Color of the point\n", " s=250 # Size of the points\n", " )\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Moving to something other than shots - you can extract all the crosses from Vejle in open play in this way\n", "\n", "cross=dataset.loc[(dataset['pass_type']=='CROSS') & \n", " (dataset['team']=='Vejle BK') & \n", " (dataset['set_piece_type'].isna()) # if set_piece_type is empty then the cross is in open play\n", " ]\n", "\n", "# Subsetting in completed and incompleted passes\n", "\n", "incomplete = cross[cross['result']=='INCOMPLETE'] # == means is equal to\n", "complete = cross[cross['result']!='INCOMPLETE'] # != means NOT equal to\n", "\n", "# Extract Vejle BK by picking the first value of unique teams in the cross dataset\n", "# Given that python starts counting at 0 the first value are called by writing [0] rather than [1]\n", "\n", "team = cross.team.unique()[0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# To plot some events on the pitch you first call the code from above to create a pitch\n", "\n", "pitch = Pitch(pitch_color='grass', line_color='white', stripe=True, pitch_type='opta',corner_arcs=True,goal_type='box')\n", "fig, ax = pitch.draw(figsize=(15, 10))\n", "\n", "# After creating the pitch you can add the completed crosses by using pitch.lines()\n", "\n", "lc1 = pitch.lines(complete.coordinates_x, # x coordinate start\n", " complete.coordinates_y, # y coordinate start\n", " complete.end_coordinates_x, # x coordinate end\n", " complete.end_coordinates_y, # y coordinate end\n", " ax=ax, # What plot to add them to \n", " lw=10, # Linewidth \n", " comet=True, # Setting line style to be comet - wider at end than at start\n", " color='blue', # Color of the line\n", " capstyle=\"round\", # Rounding off end rather than a flat end\n", " label='Completed', # What to call the lines in the legend\n", " zorder=1 # What order to add the lines to the plot\n", " )\n", "\n", "# Similar to the completed crosses you can then add incomplete and assign them a red color\n", "\n", "lc2 = pitch.lines(incomplete.coordinates_x,\n", " incomplete.coordinates_y,\n", " incomplete.end_coordinates_x,\n", " incomplete.end_coordinates_y,\n", " ax=ax, lw=10,\n", " comet=True, capstyle=\"round\",color='red', label='Incomplete', zorder=1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# You can then add a few more details to make the plot a bit nicer to look at\n", "\n", "# Start by repeating the process from above\n", "# To plot some events on the pitch you first call the code from above to create a pitch\n", "\n", "pitch = Pitch(pitch_color='grass', line_color='white', stripe=True, pitch_type='opta',corner_arcs=True,goal_type='box')\n", "fig, ax = pitch.draw(figsize=(15, 10))\n", "\n", "# After creating the pitch you can add the completed crosses by using pitch.lines()\n", "\n", "lc1 = pitch.lines(complete.coordinates_x, # x coordinate start\n", " complete.coordinates_y, # y coordinate start\n", " complete.end_coordinates_x, # x coordinate end\n", " complete.end_coordinates_y, # y coordinate end\n", " ax=ax, # What plot to add them to \n", " lw=10, # Linewidth \n", " comet=True, # Setting line style to be comet - wider at end than at start\n", " color='blue', # Color of the line\n", " capstyle=\"round\", # Rounding off end rather than a flat end\n", " label='Completed', # What to call the lines in the legend\n", " zorder=1 # What order to add the lines to the plot\n", " )\n", "\n", "# Similar to the completed crosses you can then add incomplete and assign them a red color\n", "\n", "lc2 = pitch.lines(incomplete.coordinates_x,\n", " incomplete.coordinates_y,\n", " incomplete.end_coordinates_x,\n", " incomplete.end_coordinates_y,\n", " ax=ax, lw=10,\n", " comet=True, capstyle=\"round\",color='red', label='Incomplete', zorder=1)\n", "\n", "# Adding a title by using the team name extracted above\n", "# Writing \"f'SOMETHING'\" allows you to combine variables and text\n", "# You simply need to enclose a variable in {} to use it\n", "\n", "ax_title = ax.set_title(f'{team} crosses', fontsize=30)\n", "\n", "# Adding some points without color fill might help pick out each cross a bit better\n", "# First you can add colorless points to the end coordinate\n", "\n", "scatter = pitch.scatter(cross.end_coordinates_x, # x coordinate\n", " cross.end_coordinates_y, # y coordinate\n", " ax=ax, # Which plot to add them to\n", " edgecolor='black', # Edge color of the point\n", " c=\"None\", # Fill color - set to none to get an empty point\n", " s=100, # Size of the point\n", " zorder=2 # Plotting at a higher level than the lines to ensure the point are on top\n", " )\n", "\n", "# Likewise you can add smaller points to the start coordinates\n", "\n", "scatter = pitch.scatter(cross.coordinates_x, cross.coordinates_y, ax=ax, edgecolor='black',c=\"None\", s=50, zorder=2)\n", "\n", "# Lastly you can add a legend to tell the enduser what the different color of lines means\n", "\n", "ax.legend(fontsize=17, # Size of text in the legend\n", " bbox_to_anchor=(0.2, 0.925) # Placement of the legend - here placed at the top right by setting\n", " #(x value low and y value close to one)\n", " )\n", "\n", "# You can then simply right click the plot and copy it into your presentation or report\n", "# Or you can begin subsetting crosses from the left or right side - seen from the offensive point of view\n", "# Do this by only including crosses with a y coordinate < 50 (right side) or y coordinate > 50 (left side)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" } }, "nbformat": 4, "nbformat_minor": 4 }