def make_dataset(play, event_frame, metrica_attack, metrica_defence, bokeh_attack, bokeh_defence, field_dimen = (106.,68.,), new_grid_size = 500):

        params = mpc.default_model_params(3) 

        event = events_df.loc[[(play, int(event_frame))]]
        tracking_frame = event['Start Frame'][0]

        att_frame = bokeh_attack.loc[(play,tracking_frame)]
        att_player_frame = att_frame[att_frame['player'] != "ball"]
        att_player_frame['Shirt Number'] = att_player_frame['player'].map(int).map(shirt_mapping[play]).fillna("")

        def_frame = bokeh_defence.loc[(play,tracking_frame)]
        def_player_frame = def_frame[def_frame['player'] != "ball"]
        def_player_frame['Shirt Number'] = def_player_frame['player'].map(int).map(shirt_mapping[play]).fillna("")

        ball_frame = att_frame[att_frame['player'] == "ball"]

        PPCF,xgrid,ygrid = pvm.lastrow_generate_pitch_control_for_event(play,event_frame, events_df, metrica_attack, metrica_defence, params, field_dimen = (106.,68.,), n_grid_cells_x = 50)
        PT = pvm.generate_relevance_at_event(play,event_frame, events_df, PPCF, params)
        PS = pvm.generate_scoring_opportunity(field_dimen = (106.,68.,),n_grid_cells_x = 50)
        PPV = pvm.generate_pitch_value(PPCF,PT,PS,field_dimen = (106.,68.,),n_grid_cells_x = 50)
        RPPV = pvm.generate_relative_pitch_value(play, event_frame, events_df, metrica_attack, PPV, xgrid, ygrid)

        xgrid_new = np.linspace( -field_dimen[0]/2., field_dimen[0]/2., new_grid_size)
        ygrid_new = np.linspace( -field_dimen[1]/2., field_dimen[1]/2., new_grid_size)

        PPCF_int = interpolate.interp2d(xgrid, ygrid, PPCF, kind = 'cubic')
        PPCF_new = PPCF_int(xgrid_new, ygrid_new)
        PPCF_dict = dict(image = [PPCF_new],x = [xgrid.min()],y = [ygrid.min()],dw = [field_dimen[0]], dh = [field_dimen[1]])
        PT_int = interpolate.interp2d(xgrid, ygrid, PT, kind = 'cubic')
        PT_new = PT_int(xgrid_new, ygrid_new)
        PT_dict = dict(image = [PT_new],x = [xgrid.min()],y = [ygrid.min()],dw = [field_dimen[0]], dh = [field_dimen[1]])
        PS_int = interpolate.interp2d(xgrid, ygrid, PS, kind = 'cubic')
        PS_new = PS_int(xgrid_new, ygrid_new)
        PS_dict = dict(image = [PS_new],x = [xgrid.min()],y = [ygrid.min()],dw = [field_dimen[0]], dh = [field_dimen[1]])
        PPV_int = interpolate.interp2d(xgrid, ygrid, PPV, kind = 'cubic')
        PPV_new = PPV_int(xgrid_new, ygrid_new)
        PPV_dict = dict(image = [PPV_new],x = [xgrid.min()],y = [ygrid.min()],dw = [field_dimen[0]], dh = [field_dimen[1]])
        RPPV_int = interpolate.interp2d(xgrid, ygrid, RPPV, kind = 'cubic')
        RPPV_new = RPPV_int(xgrid_new, ygrid_new)
        RPPV_dict = dict(image = [RPPV_new],x = [xgrid.min()],y = [ygrid.min()],dw = [field_dimen[0]], dh = [field_dimen[1]])


        event_src = ColumnDataSource(event)
        att_src = ColumnDataSource(att_player_frame)
        def_src = ColumnDataSource(def_player_frame)
        ball_src = ColumnDataSource(ball_frame)
        PPCF_src = ColumnDataSource(PPCF_dict)
        PT_src = ColumnDataSource(PT_dict)
        PS_src = ColumnDataSource(PS_dict)
        PPV_src = ColumnDataSource(PPV_dict)
        RPPV_src = ColumnDataSource(RPPV_dict)

        return event_src, att_src, def_src, ball_src, PPCF_src, PT_src, PS_src, PPV_src, RPPV_src, xgrid, ygrid
Esempio n. 2
0
def calculate_epv_events_per_match(base_file, folder):
    """
    Calculates the EPV and optimal EPV values for an input DataFrame of passes.

    Parameters
    -----------
        base_file: input string corresponding to the match CSVs, from which we read the data
        folder: folder path
    Returns
    -----------
       EPV_df: is the original events DataFrame with only the transition passes
       and includes the outcomes of the EPV calculations
    """
    # make path string
    preprocessed_tracking_home_path = f'{folder}\\preprocessed\\{base_file}_tracking_home_processed.csv'
    preprocessed_tracking_away_path = f'{folder}\\preprocessed\\{base_file}_tracking_away_processed.csv'
    transition_passes_path = f'{folder}\\transition_passes\\{base_file}_transition_passes.csv'

    # load data
    tracking_home = pd.read_csv(preprocessed_tracking_home_path, index_col=0)
    tracking_away = pd.read_csv(preprocessed_tracking_away_path, index_col=0)
    events = pd.read_csv(transition_passes_path, index_col=0)

    # select only transition passes with an origin in the midfield:
    events = events[(events['Start X'] > -17.5) & (events['Start X'] < 17.5)]
    """ *** UPDATES TO THE MODEL: OFFSIDES """
    # first get pitch control model parameters
    params = mpc.default_model_params()
    # find goalkeepers for offside calculation
    gk_numbers = [
        mio.find_goalkeeper(tracking_home),
        mio.find_goalkeeper(tracking_away)
    ]
    # get EPV surface
    epv = mepv.load_EPV_grid(DATADIR + '/EPV_grid.csv')
    # generate EPV values and append to events DataFrame
    epv_df = generate_epv_df(events, tracking_home, tracking_away, gk_numbers,
                             epv, params)
    return epv_df
Esempio n. 3
0
    def player_pitch_control_impact(self):
        st.subheader("Simulation")
        # read dataset
        df_dict, color_dict, events_df = read_dataset(self.base_dir, self.play,
                                                      self.args)

        # show dataframe
        st.markdown("event dataframe is ...")
        st.table(events_df)
        event_id = st.selectbox("Select a event id for analysis",
                                events_df.index,
                                index=events_df.index[-1])

        team = st.selectbox(
            "Select a team for analysis",
            [events_df.at[event_id, "Team"]] + [
                k for k in list(df_dict.keys())
                if k != events_df.at[event_id, "Team"]
            ],
        )
        # sort player num based on end location
        end_frame = events_df.at[event_id, "End Frame"]
        ball_loc = events_df.loc[event_id, ["End X", "End Y"]].values
        player_num_list = list(
            set([
                c.split("_")[1] for c in df_dict[team].columns
                if c.startswith(team)
            ]))
        sorted_index = np.argsort([
            np.linalg.norm(df_dict[team].loc[
                end_frame, [f"{team}_{player_num}_{c}"
                            for c in ["x", "y"]]].values - ball_loc)
            for player_num in player_num_list
        ])
        player_num = st.selectbox(
            "Select a player number for analysis",
            np.array(player_num_list)[sorted_index],
        )

        verification_mode = st.selectbox(
            "Select the verification mode",
            [
                "movement:How much space created during event??",
                "presense:How much space occupied during event??",
                "location:if positions changed, how much space difference during event??",
            ],
        ).split(":")[0]

        params = mpc.default_model_params(3)
        example_player_analysis_away = PlayerPitchControlAnalysisPlayer(
            df_dict=df_dict,
            params=params,
            events=events_df,
            event_id=event_id,
            team_player_to_analyze=team,
            player_to_analyze=str(player_num),
            field_dimens=(106.0, 68.0),
            n_grid_cells_x=50,
        )

        with st.spinner("wait for computing ..."):
            if verification_mode == "movement":
                st.markdown(
                    example_player_analysis_away.team_player_to_analyze +
                    " Player " +
                    str(example_player_analysis_away.player_to_analyze) +
                    " created " + str(
                        int(
                            example_player_analysis_away.
                            calculate_space_created(
                                replace_function="movement",
                                replace_x_velocity=0,
                                replace_y_velocity=0,
                            ))) +
                    " m^2 of space with his movement during event " +
                    str(example_player_analysis_away.event_id))
                # Now, let's plot the space created and conceded by his run
                fig, ax = example_player_analysis_away.plot_pitch_control_difference(
                    replace_function="movement",
                    replace_x_velocity=0,
                    replace_y_velocity=0,
                    team_color_dict=color_dict,
                )
                st.pyplot(fig, bbox_layout="tight")

            elif verification_mode == "presense":
                st.markdown(
                    example_player_analysis_away.team_player_to_analyze +
                    " Player " +
                    str(example_player_analysis_away.player_to_analyze) +
                    " occupied " + str(
                        int(
                            example_player_analysis_away.
                            calculate_space_created(
                                replace_function="presence"))) +
                    " m^2 of space during event " +
                    str(example_player_analysis_away.event_id))
                fig, ax = example_player_analysis_away.plot_pitch_control_difference(
                    replace_function="presence", team_color_dict=color_dict)
                st.pyplot(fig, bbox_layout="tight")

            elif verification_mode == "location":
                st_frame = events_df.at[event_id, "Start Frame"]
                x, y = (
                    df_dict[team].at[st_frame, f"{team}_{player_num}_x"],
                    df_dict[team].at[st_frame, f"{team}_{player_num}_y"],
                )
                max_x, min_x = int(x_size / 2 - x), -int(x_size / 2 + x)
                max_y, min_y = int(y_size / 2 - y), -int(y_size / 2 + y)
                relative_x = st.slider("relative x",
                                       min_value=min_x,
                                       max_value=max_x,
                                       value=0,
                                       step=1)
                relative_y = st.slider("relative y",
                                       min_value=min_y,
                                       max_value=max_y,
                                       value=0,
                                       step=1)

                st.markdown(
                    example_player_analysis_away.team_player_to_analyze +
                    " Player " +
                    str(example_player_analysis_away.player_to_analyze) +
                    " would have occupied a difference of " + str(
                        int(-1 * example_player_analysis_away.
                            calculate_space_created(
                                replace_function="location",
                                relative_x_change=relative_x,
                                relative_y_change=relative_y,
                            ))) + " m^2 of space during event " +
                    str(example_player_analysis_away.event_id) +
                    " if they were changed to x, y = " + str(relative_x) +
                    ", " + str(relative_y))
                fig, ax = example_player_analysis_away.plot_pitch_control_difference(
                    replace_function="location",
                    relative_x_change=relative_x,
                    relative_y_change=relative_y,
                    team_color_dict=color_dict,
                )
                st.pyplot(fig, bbox_layout="tight")
        st.success("done !!")
Esempio n. 4
0
# Calculate player velocities
# tracking_home = mvel.calc_player_velocities(tracking_home, smoothing=True)
# tracking_away = mvel.calc_player_velocities(tracking_away, smoothing=True)
#%%
# **** NOTE *****
# if the lines above produce an error (happens for one version of numpy) change them to the lines below:
# ***************
tracking_home = mvel.calc_player_velocities(tracking_home,
                                            smoothing=True,
                                            filter_='moving_average')
tracking_away = mvel.calc_player_velocities(tracking_away,
                                            smoothing=True,
                                            filter_='moving_average')
""" *** UPDATES TO THE MODEL: OFFSIDES """
# first get pitch control model parameters
params = mpc.default_model_params()
# find goalkeepers for offside calculation
GK_numbers = [
    mio.find_goalkeeper(tracking_home),
    mio.find_goalkeeper(tracking_away)
]
#%%
GK_numbers

#%%
""" *** GET EPV SURFACE **** """
home_attack_direction = mio.find_playing_direction(
    tracking_home, 'Home')  # 1 if shooting left-right, else -1

#%%
EPV = mepv.load_EPV_grid(DATADIR + '/EPV_grid.csv')
def calculate_pitch_control_towards_goal(frame, team, event_id, events,
                                         tracking_home, tracking_away,
                                         column_name):
    """
    Calculates the pitch control percentage of the tiles between the passer and the goal

    Parameters
    -----------
        frame: frame of corresponding tracking row
        team: string 'Home' or 'Away'
        event_id: index corresponding to the passing event
        events: all transition pass events of this match
        tracking_home: tracking DataFrame for the Home team
        tracking_away: tracking DataFrame for the Away team
        column_name: the passing player's corresponding base column name for the tracking data
    Returns
    -----------
       percentage_pitch_control: percentage of pitch control of the attacking team of the tile between the passer,
        and the goal
    """
    # first get pitch control model parameters
    params = mpc.default_model_params()
    # find goalkeepers for offside calculation
    gk_numbers = [
        mio.find_goalkeeper(tracking_home),
        mio.find_goalkeeper(tracking_away)
    ]
    # evaluated pitch control surface for pass event
    PPCa, xgrid, ygrid = mpc.generate_pitch_control_for_event(
        event_id,
        events,
        tracking_home,
        tracking_away,
        params,
        gk_numbers,
        field_dimen=(
            105.,
            68.,
        ),
        n_grid_cells_x=50,
        offsides=True)

    # get playing_direction and x position of passing player
    if team == 'Home':
        player_x = tracking_home.loc[frame, column_name + '_x']
        playing_direction = mio.find_playing_direction(tracking_home, team)
        # player_y = tracking_home.loc[frame, column_name + '_y']
    else:
        player_x = tracking_away.loc[frame, column_name + '_x']
        playing_direction = mio.find_playing_direction(tracking_away, team)

    # divide the playing field into grid cells
    n_grid_cells_x = 32
    n_grid_cells_y = 50
    field_dimen = [105, 68]

    # get grid cell of passing player
    dx = field_dimen[0] / n_grid_cells_x
    x_grid = np.arange(n_grid_cells_x) * dx - field_dimen[0] / 2. + dx / 2.

    # calculate the pitch control value of the grids towards goal,
    # and calculate the maximum pitch control for that area:
    if playing_direction == 1:  # direction: left -> right
        # get number of grids closer to goal
        num_grids_to_goal = len([i for i in x_grid if i > player_x])

        # maximum == number of grids to goal and a Pitch Control value of 1,
        # meaning that it is totally controlled by attacker
        max_pitch_control = num_grids_to_goal * n_grid_cells_y
        # get the pitch control using the pitch control values that are created above (PPCa)
        pitch_control_att_team = sum(sum(PPCa[-num_grids_to_goal:]))

    else:  # direction: right -> left
        num_grids_to_goal = len([i for i in x_grid if i < player_x])
        max_pitch_control = num_grids_to_goal * n_grid_cells_y
        pitch_control_att_team = sum(sum(PPCa[:num_grids_to_goal]))

    percentage_pitch_control = round(
        (pitch_control_att_team / max_pitch_control) * 100, 2)
    return percentage_pitch_control