Example #1
0
import pandas as pd

from mplsoccer import VerticalPitch
from mplsoccer.statsbomb import read_event, EVENT_SLUG

# get data
match_files = ['19789.json', '19794.json', '19805.json']
kwargs = {
    'related_event_df': False,
    'shot_freeze_frame_df': False,
    'tactics_lineup_df': False,
    'warn': False
}
df = pd.concat([
    read_event(f'{EVENT_SLUG}/{file}', **kwargs)['event']
    for file in match_files
])
# filter chelsea pressure events
mask_chelsea_pressure = (df.team_name == 'Chelsea FCW') & (df.type_name
                                                           == 'Pressure')
df = df.loc[mask_chelsea_pressure, ['x', 'y']]

##############################################################################
# Plot the heatmaps

# setup pitch
pitch = VerticalPitch(pitch_type='statsbomb',
                      line_zorder=2,
                      pitch_color='#22312b',
                      line_color='white')
Example #2
0
This example shows how to plot the passes from a team as a pass flow plot.
"""

from matplotlib import rcParams
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

from mplsoccer import Pitch, FontManager
from mplsoccer.statsbomb import read_event, EVENT_SLUG

rcParams['text.color'] = '#c7d5cc'  # set the default text color

# get event dataframe for game 7478, create a dataframe of the passes,
# and a boolean mask for the outcome
df = read_event(f'{EVENT_SLUG}/7478.json',
                related_event_df=False,
                shot_freeze_frame_df=False,
                tactics_lineup_df=False)['event']

##############################################################################
# Boolean mask for filtering the dataset by team

team1, team2 = df.team_name.unique()
mask_team1 = (df.type_name == 'Pass') & (df.team_name == team1)

##############################################################################
# Filter dataset to only include one teams passes and get boolean mask for the completed passes

df_pass = df.loc[mask_team1, ['x', 'y', 'end_x', 'end_y', 'outcome_name']]
mask_complete = df_pass.outcome_name.isnull()

##############################################################################
Example #3
0
This example shows how to plot the location of events occurring in a match
 using kernel density estimation (KDE).
"""

from mplsoccer import Pitch
from mplsoccer.statsbomb import read_event, EVENT_SLUG

##############################################################################
# load first game that Messi played as a false-9 and the match before as dataframes

kwargs = {
    'related_event_df': False,
    'shot_freeze_frame_df': False,
    'tactics_lineup_df': False
}
df_false9 = read_event(f'{EVENT_SLUG}/69249.json', **kwargs)['event']
df_before_false9 = read_event(f'{EVENT_SLUG}/69251.json', **kwargs)['event']

##############################################################################
# Filter the dataframes to only include Messi's events and the starting positions

df_false9 = df_false9.loc[df_false9.player_id == 5503, ['x', 'y']]
df_before_false9 = df_before_false9.loc[df_before_false9.player_id == 5503,
                                        ['x', 'y']]

##############################################################################
# View a dataframe

df_false9.head()

##############################################################################
Example #4
0
                      # they are not plotted. note this automatically
                      # sets the endnote/title space to zero
                      # so the grid starts at the bottom/left location
                      endnote_height=0, title_height=0)

##############################################################################
# Pass maps
# ---------
# The following example plots pass maps for each player on a team.
# The plot design is copied from
# `Brad @DymondFormation <https://twitter.com/DymondFormation>`_.
#
# First we need to get the StatsBomb events, tactics, and lineup data
JSON = '15946.json'
kwargs = {'related_event_df': False, 'shot_freeze_frame_df': False, 'tactics_lineup_df': True}
event_dict = read_event(f'{EVENT_SLUG}/{JSON}', **kwargs)
events = event_dict['event']
tactics = event_dict['tactics_lineup']
# read the lineup (has all the players even if they didn't play)
lineup = read_lineup(f'{LINEUP_SLUG}/{JSON}', warn=False)

##############################################################################
# Add on the subbed on/ off times to the lineup dataframe

# dataframe with player_id and when they were subbed off
time_off = events.loc[(events.type_name == 'Substitution'),
                      ['player_id', 'minute']]
time_off.rename({'minute': 'off'}, axis='columns', inplace=True)
# dataframe with player_id and when they were subbed on
time_on = events.loc[(events.type_name == 'Substitution'),
                     ['substitution_replacement_id', 'minute']]
Example #5
0
This example shows how to plot passes between players in a set formation.
"""

import pandas as pd
from mplsoccer.pitch import Pitch
from matplotlib.colors import to_rgba
import numpy as np
from mplsoccer.statsbomb import read_event, EVENT_SLUG

##############################################################################
# Set team and match info, and get event and tactics dataframes for the defined match_id

match_id = 15946
team = 'Barcelona'
opponent = 'Alavés (A), 2018/19 La Liga'
event_dict = read_event(f'{EVENT_SLUG}/{match_id}.json', warn=False)
players = event_dict['tactics_lineup']
events = event_dict['event']

##############################################################################
# Adding on the last tactics id and formation for the team for each event

events.loc[events.tactics_formation.notnull(), 'tactics_id'] = events.loc[
    events.tactics_formation.notnull(), 'id']
events[['tactics_id', 'tactics_formation']] = events.groupby('team_name')[[
    'tactics_id', 'tactics_formation']].ffill()

##############################################################################
# Add the abbreviated player position to the players dataframe

formation_dict = {1: 'GK', 2: 'RB', 3: 'RCB', 4: 'CB', 5: 'LCB', 6: 'LB', 7: 'RWB',
Example #6
0
# https://github.com/koenvo/wyscout-soccer-match-event-dataset
wyscout_id = df_overlap.iloc[IDX].wyscout_json
WYSCOUT_URL = (
    f'https://raw.githubusercontent.com/koenvo/wyscout-soccer-match-event-dataset/'
    f'main/processed/files/{wyscout_id}')

# Here we get the url of the cooresponding statsbomb match
statsbomb_id = df_overlap.iloc[IDX].statsbomb_json
STATSBOMB_URL = f'{EVENT_SLUG}/{statsbomb_id}'

##############################################################################
# Get the StatsBomb data as a dataframe
# -------------------------------------

df_statsbomb = read_event(STATSBOMB_URL,
                          related_event_df=False,
                          shot_freeze_frame_df=False,
                          tactics_lineup_df=False)['event']

##############################################################################
# Get the Wyscout data as a dataframe using Kloppy
# ------------------------------------------------
# We first save the file locally and then load it in Kloppy as a dataframe

# create the data/wyscout directories to store the file if they don't exist
WYSCOUT_PATH = os.path.join('data', 'wyscout')
if os.path.exists(WYSCOUT_PATH) is False:
    os.makedirs(WYSCOUT_PATH)

# Save the Wyscout json in the data/wyscout directory
WYSCOUT_JSON_PATH = os.path.join(WYSCOUT_PATH, wyscout_id)
if os.path.exists(
Example #7
0
"""

import numpy as np
import pandas as pd
from matplotlib.colors import to_rgba

from mplsoccer import Pitch
from mplsoccer.statsbomb import read_event, EVENT_SLUG

##############################################################################
# Set team and match info, and get event and tactics dataframes for the defined match_id

MATCH_ID = 15946
TEAM = 'Barcelona'
OPPONENT = 'Alavés (A), 2018/19 La Liga'
event_dict = read_event(f'{EVENT_SLUG}/{MATCH_ID}.json', warn=False)
players = event_dict['tactics_lineup']
events = event_dict['event']

##############################################################################
# Adding on the last tactics id and formation for the team for each event

events.loc[events.tactics_formation.notnull(),
           'tactics_id'] = events.loc[events.tactics_formation.notnull(), 'id']
events[['tactics_id', 'tactics_formation'
        ]] = events.groupby('team_name')[['tactics_id',
                                          'tactics_formation']].ffill()

##############################################################################
# Add the abbreviated player position to the players dataframe
Example #8
0
    df_lineup.to_parquet(os.path.join(DATA_FOLDER, 'lineup.parquet'))
    df_lineup.info()

##############################################################################
# Event data
# ----------
# We will also loop through the first five event files.
# However, the ``read_event`` function returns a dictionary of four dataframes:
# 'event', 'related_event', 'shot_freeze_frame' and 'tactics_lineup'.
# It's possible to alter ``read_event`` to return fewer dataframes (see the API docs).

# loop through all the changed links and store as parquet files - small and fast files
for file in event_links:
    save_path = f'{os.path.basename(file)[:-4]}parquet'
    try:
        dict_event = sbapi.read_event(file, warn=False)
        # save to parquet files
        # using the dictionary key to access the dataframes from the dictionary
        dict_event['event'].to_parquet(
            os.path.join(DATA_FOLDER, 'event_raw', save_path))
        dict_event['related_event'].to_parquet(
            os.path.join(DATA_FOLDER, 'related_raw', save_path))
        dict_event['shot_freeze_frame'].to_parquet(
            os.path.join(DATA_FOLDER, 'freeze_raw', save_path))
        dict_event['tactics_lineup'].to_parquet(
            os.path.join(DATA_FOLDER, 'tactic_raw', save_path))
    except ValueError:
        print('Skipping:', file)

##############################################################################
#  Get a list of match_ids to update
Shot freeze frame
=================

This example shows how to plot a shot freeze frame.
"""

from mplsoccer.pitch import Pitch
from mplsoccer.statsbomb import read_event, read_lineup, EVENT_SLUG, LINEUP_SLUG
import matplotlib.pyplot as plt
plt.style.use('ggplot')

# get event and lineup dataframes for game 7478

# event data
dict_event = read_event(f'{EVENT_SLUG}/7478.json',
                        related_event_df=False,
                        tactics_lineup_df=False,
                        warn=False)
df_event = dict_event['event']
df_freeze = dict_event['shot_freeze_frame']

# lineup data
df_lineup = read_lineup(f'{LINEUP_SLUG}/7478.json', warn=False)
df_lineup = df_lineup[['player_id', 'player_jersey_number',
                       'team_name']].copy()

##############################################################################
# Subset a shot

shot_id = '8bb8bbc2-68a6-4c01-93de-53a194e7a1cf'
df_freeze_frame = df_freeze[df_freeze.id == shot_id].copy()
df_shot_event = df_event[df_event.id == shot_id].dropna(axis=1,
Example #10
0
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.colors import LinearSegmentedColormap
import cmasher as cmr

from mplsoccer import VerticalPitch
from mplsoccer.statsbomb import read_event, EVENT_SLUG
from mplsoccer.utils import FontManager

# get data
match_files = ['19789.json', '19794.json', '19805.json']
kwargs = {'related_event_df': False, 'shot_freeze_frame_df': False,
          'tactics_lineup_df': False, 'warn': False}
df = pd.concat([read_event(f'{EVENT_SLUG}/{file}', **kwargs)['event'] for file in match_files])
# filter chelsea pressure events
mask_chelsea_pressure = (df.team_name == 'Chelsea FCW') & (df.type_name == 'Pressure')
df = df.loc[mask_chelsea_pressure, ['x', 'y']]

##############################################################################
# cmasher colormaps
# -----------------------
# Cmasher colormaps are scientific colormaps that have been designed to be
# perceptually uniform (i.e. color changes visually look the same as the value changes)
# and mostly colorblind friendly. A great choice
# to get started and potentially more exciting than the default matplotlib choices.
#
# Let's first get a dictionary of all the colormaps
#
# See the docs for more info: https://cmasher.readthedocs.io/.
Example #11
0
import pandas as pd
import seaborn as sns
from matplotlib.cm import get_cmap

from mplsoccer import Pitch, VerticalPitch
from mplsoccer.statsbomb import read_event, EVENT_SLUG
from mplsoccer.utils import FontManager

# get data for a Sevilla versus Barcelona match with a high amount of shots
kwargs = {
    'related_event_df': False,
    'shot_freeze_frame_df': False,
    'tactics_lineup_df': False,
    'warn': False
}
df = read_event(f'{EVENT_SLUG}/9860.json', **kwargs)['event']

# setup the mplsoccer StatsBomb Pitches
# note not much padding around the pitch so the marginal axis are tight to the pitch
# if you are using a different goal type you will need to increase the padding to see the goals
pitch = Pitch(pad_top=0.05,
              pad_right=0.05,
              pad_bottom=0.05,
              pad_left=0.05,
              line_zorder=2)
vertical_pitch = VerticalPitch(half=True,
                               pad_top=0.05,
                               pad_right=0.05,
                               pad_bottom=0.05,
                               pad_left=0.05,
                               line_zorder=2)
Example #12
0
"""

import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib.cm import get_cmap
import matplotlib.pyplot as plt

from mplsoccer import Pitch, VerticalPitch
from mplsoccer.statsbomb import read_event, EVENT_SLUG
from mplsoccer.utils import FontManager

# get data for a Sevilla versus Barcelona match with a high amount of shots
kwargs = {'related_event_df': False, 'shot_freeze_frame_df': False,
          'tactics_lineup_df': False, 'warn': False}
df = read_event(f'{EVENT_SLUG}/9860.json', **kwargs)['event']

# setup the mplsoccer StatsBomb Pitches
# note not much padding around the pitch so the marginal axis are tight to the pitch
# if you are using a different goal type you will need to increase the padding to see the goals
pitch = Pitch(pad_top=0.05, pad_right=0.05, pad_bottom=0.05, pad_left=0.05, line_zorder=2)
vertical_pitch = VerticalPitch(half=True, pad_top=0.05, pad_right=0.05, pad_bottom=0.05,
                               pad_left=0.05, line_zorder=2)

# setup a mplsoccer FontManager to download google fonts (Roboto-Regular / SigmarOne-Regular)
fm = FontManager()
fm_rubik = FontManager(('https://github.com/google/fonts/blob/main/ofl/rubikmonoone/'
                        'RubikMonoOne-Regular.ttf?raw=true'))

##############################################################################
# Subset the shots for each team and move Barcelona's shots to the other side of the pitch.