Modules¶
Calculate Packing¶
-
class
packing.
packing
(sender_xy: numpy.array, receiver_xy: numpy.array, defending_team_xy: pandas.core.frame.DataFrame, col_label_x: str, col_label_y: str, defend_side: str)[source]¶ Find the packing for a given pass
- Parameters
- sender_xyndarray
Sender XY coordinates as numpy array
- receiver_xyndarray
Receiver XY coordinates as numpy array
- defending_team_xyDataFrame
DataFrame with the defending team coordinates Do not include any passing team XY or other columns as it’ll have an impact on plotting function.
- col_label_xString
The column label for defending team’s X coordinate in defending_team_xy
- col_label_yString
The column label for defending team’s Y coordinate in defending_team_xy
- defend_sideString
The side of the defending team on the football pitch. Left/Right, not case sensitive
- goal_centerDict
Center of goal selected based on defend_side {‘left’: [0, 0.5], ‘right’: [1, 0.5]}
- Returns
- packing_dfDataFrame
Returns a dataframe with the following new columns along with existing columns that was provided. New Columns : [triangle_area, rect_length, rect_width, area_diff, method_1, method2_dist, method_2, method3_angle_s, method3_angle_r, method_3, method_1_update, packing_rate, col_label_x, col_label_y]
- packing_rateFloat
Packing rate for that given pass scenario Packing rate will be multiplied by a factor based on the pass type: 1.0 : Forward Pass -1.0 : Back Pass 0.5 : Side pass
- pass_pressureInteger
Defending players who are closer to sender/receiver but not involved in packing. Indicator to see if players take high risk pass. For eg: packing rate could be lower but pass pressure can be higher if pass sender/receiver are heavily marked.
How packing is calculated?¶
A brief explanation on how packing rate is calculated. There are 3 methods which look at different aspects of the pass and defending player’s relationship to the pass.
Method 1
looks at the space between the sender and receiver and checks if any
defending players is within that space. A bounding box (green box here)
is created between the sender and receiver and the defending players inside the box
(and certain distance threshold outside the box) are marked as 1.
Method 2
looks at the distance between the defender and line of pass. If the defender is
within a certain distance (method2_radius), they are marked as 1. This helps to consider defenders
who are only within the range of the pass.
Method 3
looks at the angle between the sender & receiver to the defender. In order to consider
the lines of the defender, instead of just making a vertical line, based on the direction of pass angles
are calculated. This is seen with an example here.
Method 1
gets a final update based on a specific condition as mentioned
in this section.
Method 1¶
-
packing.calculate_packing.
method_1
(self, box_a, box_b, box_c, box_d, df_method1, col_label_x, col_label_y, rect_thresh=0.01)¶ Method 1 : Draw a rectangle box between sender and receiver to see if any player is inside the bounding box. A rect_thresh of 0.01 is used to consider players on the edge of the box.
- Parameters
- box_andarray
A ndarray of [‘sender_x’, ‘sender_y’]
- box_bndarray
A ndarray of [‘sender_x’, ‘receiver_y’]
- box_cndarray
A ndarray of [‘receiver_x’, ‘receiver_y’]
- box_dndarray
A ndarray of [‘receiver_x’, ‘sender_y’]
- df_method1DataFrame
A copy of defending_team_xy dataframe
- col_label_xString
The column label for defending team’s X coordinate in defending_team_xy
- col_label_yString
The column label for defending team’s Y coordinate in defending_team_xy
- rect_threshFloat, default 0.015
A threshold to check if any player is outside/on the edge of the box within the threshold distance
- Returns
- df_method1DataFrame
A copy of original DataFrame with 1/0 for Method 1 and the following new columns : triangle_area : Float, rect_length : Float, rect_width : Float, method_1 : Binary
Method 2¶
-
packing.calculate_packing.
method_2
(self, sender_xy, receiver_xy, df_method2, col_label_x, col_label_y, method2_radius=0.12)¶ Method 2 : Check if player is within a certain distance to line of pass, so that the pass can potentially be intersected (assuming the speed of pass is not a factor).
For a given defender, assume the defender xy to be center of circle. Find the perpendicular distance from player xy to the line of pass. If the distance is <= method2_radius, then method_2 returns as 1, else 0.
- Parameters
- sender_xyndarray
A ndarray of [‘sender_x’, ‘sender_y’]
- receiver_xyndarray
A ndarray of [‘receiver_x’, ‘receiver_y’]
- df_method2DataFrame
A copy of defending_team_xy dataframe, updated from Method 1
- radiusFloat, default 0.150
search radius for find if player can potentially intersect the pass by being within a given distance
- Returns
- df_method2DataFrame
A copy of original DataFrame with 1/0 for Method 2 and the following new columns : method2_dist : Distance of player to line of pass, method_2 : Binary, (1/0)
Method 3¶
-
packing.calculate_packing.
method_3
(self, sender_xy, receiver_xy, df_method3, col_label_x, col_label_y)¶ Method 3 : Check defender angle with respect to sender & receiver. One of the draw back of method_2 is that defender can be close to line to pass but still be beyond the sender or receiver (one of angle b/w defender & sender/receiver > 90). This method checks this condition.
- Parameters
- sender_xyndarray
A ndarray of [‘sender_x’, ‘sender_y’]
- receiver_xyndarray
A ndarray of [‘receiver_x’, ‘receiver_y’]
- df_method3DataFrame
A copy of defending_team_xy dataframe, updated from Method 2
- Returns
- df_method3DataFrame
A copy of original DataFrame with 1/0 for Method 3 and the following new columns : method3_angle_s : Angle between defender & sender, method3_angle_r : Angle between defender & receiver, method_3 : Binary, (1/0)
Method 1 - Update¶
-
packing.calculate_packing.
update_method_1
(self, df_update)¶ Method 1 Update : For special cases where bounding box from Method 1 is almost a line i.e: either width/length <= 0.07 units (both sender and receiver are in similar X or Y coordinate). In this case, update the value of method_1 value to 1 if both method_2 and method_3 are 1.
- Parameters
- df_updateDataFrame
The copy of DataFrame after Methods 1,2 & 3.
- Returns
- df_updateDataFrame
Final Dataframe with updated 1/0 for Method 1
Pass Pressure¶
-
packing.calculate_packing.
get_pass_pressure
(self, sender_xy, receiver_xy, defending_team_xy, col_label_x, col_label_y)¶ For defender who are not in the packing rate, if they are close (<=0.05 units) to the sender/receiver, they’re considered to have an influence on the pass by increasing the pressure of the pass.
- Parameters
- sender_xyndarray
Sender XY coordinates as numpy array
- receiver_xyndarray
Receiver XY coordinates as numpy array
- defending_team_xyDataFrame
DataFrame with the defending team coordinates
- col_label_xString
The column label for defending team’s X coordinate in defending_team_xy
- col_label_yString
The column label for defending team’s Y coordinate in defending_team_xy
- Returns
- total_pressureInt
Total count of defenders applying pressure on the sender & receiver, but not involved in packing rate.
Visualize Packing¶
-
class
plot_packing.
plot_packing
(passer_team_df, packing_df, col_label_x, col_label_y, packing_rate, pass_pressure, sender_xy, receiver_xy, x_range, y_range, path_to_save, pass_frame=None, bcg_img=None, file_name='packing')[source]¶ Plot the player location on the pitch and highlight the defending team players that might have been calculated in packing.
- Parameters
- passer_team_dfDataFrame
DataFrame with the passing team coordinates Column name with id or _id are considered player ids (Only 1 column with such name).
- packing_dfDataFrame
Resulting DataFrame from packing module (should not be altered). Column name with id or _id are considered player ids (Only 1 column with such name).
- col_label_xString
The column label for defending team’s X coordinate in defending_team_xy
- col_label_yString
The column label for defending team’s Y coordinate in defending_team_xy
- packing_rateFloat
Resulting output from packing module (should not be altered)
- pass_pressureInt
Defending players who are closer to sender/receiver but not involved in packing
- sender_xyndarray
Sender XY coordinates as numpy array
- receiver_xyndarray
Receiver XY coordinates as numpy array
- x_range[start, end] list
List of range of x-axis of the pitch, Eg: [0, 100] or [-5250, 5250]
- y_range[start, end] list
List of range of y-axis of the pitch, Eg: [0, 100]`or `[3400, -3400]
- path_to_save :
A path to save the output html file. Path should end with a /
- pass_frameString, Optional, default None
Identifier to display pass event time on plot
- bcg_imgString, default None
Path to background image
- file_nameString, default packing
Filename to save the plot
- Returns
- Defending players who have been calcuated in packing will be marked in a green border.
- show() :
Plot is shown on the browser. If module is run on jupyter notebook, plot will be shown in the notebook.
- save() :
Plot saved locally to path specified under path_to_save. Note: If file_name is not changed every time module is run, plots will be overwritten.