Modules — Football Packing 0.1 documentation

# 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)

  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')

  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.