df_pass = df.loc[mask_team1, ['x', 'y', 'end_x', 'end_y', 'outcome_name']] mask_complete = df_pass.outcome_name.isnull() ############################################################################## # Setup the pitch and number of bins pitch = Pitch(pitch_type='statsbomb', line_zorder=2, line_color='#c7d5cc', pitch_color='#22312b') bins = (6, 4) ############################################################################## # Plotting using a single color and length fig, ax = pitch.draw(figsize=(16, 11), constrained_layout=True, tight_layout=False) fig.set_facecolor('#22312b') # plot the heatmap - darker colors = more passes originating from that square bs_heatmap = pitch.bin_statistic(df_pass.x, df_pass.y, statistic='count', bins=bins) hm = pitch.heatmap(bs_heatmap, ax=ax, cmap='Blues') # plot the pass flow map with a single color ('black') and length of the arrow (5) fm = pitch.flow(df_pass.x, df_pass.y, df_pass.end_x, df_pass.end_y, color='black', arrow_type='same',
# 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() ############################################################################## # Plotting Messi's first game as a False-9 pitch = Pitch(pitch_type='statsbomb', pitch_color='grass', stripe=True) fig, ax = pitch.draw(figsize=(16, 11)) # plotting ax.set_title('The first Game Messi played in the false 9 role', fontsize=30, pad=20) # plot the kernel density estimation pitch.kdeplot(df_false9.x, df_false9.y, ax=ax, cmap='plasma', linewidths=3) # annotate pitch.annotate('6-2 thrashing \nof Real Madrid', (25, 10), color='white', fontsize=25, ha='center', va='center',
df_away.head() ############################################################################## # Show the home data df_home.head() ############################################################################## # Show the ball data df_ball.head() ############################################################################## # Plot the animation # First set up the figure, the axis pitch = Pitch(pitch_type='metricasports', goal_type='line', pitch_width=68, pitch_length=105) fig, ax = pitch.draw(figsize=(16, 10.4)) # then setup the pitch plot markers we want to animate marker_kwargs = {'marker': 'o', 'markeredgecolor': 'black', 'linestyle': 'None'} ball, = ax.plot([], [], ms=6, markerfacecolor='w', zorder=3, **marker_kwargs) away, = ax.plot([], [], ms=10, markerfacecolor='#b94b75', **marker_kwargs) # red/maroon home, = ax.plot([], [], ms=10, markerfacecolor='#7f63b8', **marker_kwargs) # purple # animation function def animate(i): """ Function to animate the data. Each frame it sets the data for the players and the ball.""" # set the ball data with the x and y positions for the ith frame ball.set_data(df_ball.iloc[i, 3], df_ball.iloc[i, 4]) # get the frame id for the ith frame frame = df_ball.iloc[i, 1]
# ###################### # load the image IMAGE_URL = 'https://upload.wikimedia.org/wikipedia/commons/b/b8/Messi_vs_Nigeria_2018.jpg' image = Image.open(urlopen(IMAGE_URL)) ############################################################################## # Plotting an image over a pitch # ############################## # # To plot images you use ``Axes.imshow()`` in matplotlib. # We are going to draw a pitch and then overlay ontop an image of Messi on a new axis. # draw the pitch pitch = Pitch(line_zorder=2) fig, ax = pitch.draw(figsize=(16, 9), tight_layout=False) # add an image ax_image = add_image(image, fig, left=0.55, bottom=0.2, width=0.2, alpha=0.9, interpolation='hanning') ############################################################################## # Photo from: https://en.wikipedia.org/wiki/Lionel_Messi#/media/File:Messi_vs_Nigeria_2018.jpg; # License: https://creativecommons.org/licenses/by-sa/3.0/; # Creator: Кирилл Венедиктов ############################################################################## # More control over the images and axis # ##################################### # # For more control over where the images are placed,
path_effects=text_effects, ha='right', color=LINE_COLOR, fontsize=30, fontproperties=fm.prop) # plotting the glow effect. it is essentially a loop that plots the line with # a low alpha (transparency) value and gradually increases the linewidth. # This way the center will have more color than the outer area. # you could break this up into two loops if you wanted the pitch lines to have wider glow for i in range(1, NUM_GLOW_LINES + 1): pitch = Pitch(line_color=LINE_COLOR, pitch_color=BACKGROUND_COLOR, linewidth=LINEWIDTH + (DIFF_LINEWIDTH * i), line_alpha=ALPHA_PITCH_LINE / NUM_GLOW_LINES, goal_alpha=ALPHA_PITCH_LINE / NUM_GLOW_LINES, goal_type='box') pitch.draw( ax=ax['pitch']) # we plot on-top of our previous axis from pitch.grid pitch.lines( df_pass.x, df_pass.y, df_pass.end_x, df_pass.end_y, linewidth=LINEWIDTH + (DIFF_LINEWIDTH * i), capstyle='round', # capstyle round so the glow extends past the line alpha=ALPHA_PASS_LINE / NUM_GLOW_LINES, color=PASS_COLOR, comet=True, ax=ax['pitch'])
============ First we import the Pitch classes and matplotlib """ import matplotlib.pyplot as plt from mplsoccer import Pitch, VerticalPitch ############################################################################## # Draw a pitch on a new axis # -------------------------- # Let's plot on a new axis first. pitch = Pitch() # specifying figure size (width, height) fig, ax = pitch.draw(figsize=(8, 4)) ############################################################################## # Draw on an existing axis # ------------------------ # mplsoccer also plays nicely with other matplotlib figures. To draw a pitch on an # existing matplotlib axis specify an ``ax`` in the ``draw`` method. fig, axs = plt.subplots(nrows=1, ncols=2) pitch = Pitch() pie = axs[0].pie(x=[5, 15]) pitch.draw(ax=axs[1]) ############################################################################## # Supported data providers # ------------------------
############################################################################## # Plot the percentages # setup a mplsoccer pitch pitch = Pitch(line_zorder=2, line_color='black') # mplsoccer calculates the binned statistics usually from raw locations, such as pressure events # for this example we will create a binned statistic dividing # the pitch into thirds for one point (0, 0) # we will fill this in a loop later with each team's statistics from the dataframe bin_statistic = pitch.bin_statistic([0], [0], statistic='count', bins=(3, 1)) # Plot fig, axes = pitch.draw(figsize=(16, 9), ncols=5, nrows=4, tight_layout=False, constrained_layout=True) axes = axes.ravel() teams = df['Squad'].values vmin = df[pressure_cols].min().min( ) # we normalise the heatmaps with the min / max values vmax = df[pressure_cols].max().max() for i, ax in enumerate(axes[:len(teams)]): ax.set_title(teams[i], fontsize=20) # fill in the bin statistics from df and plot the heatmap bin_statistic['statistic'] = df.loc[df.Squad == teams[i], pressure_cols].values heatmap = pitch.heatmap(bin_statistic, ax=ax, cmap='coolwarm',
""" =========== Quick start =========== """ from mplsoccer import Pitch pitch = Pitch(pitch_color='grass', line_color='white', stripe=True) fig, ax = pitch.draw()
kwargs = { 'related_event_df': False, 'shot_freeze_frame_df': False, 'tactics_lineup_df': False, 'warn': 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 messi's actions (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']] ############################################################################## # plotting pitch = Pitch(pitch_type='statsbomb', pitch_color='#22312b', stripe=False, line_zorder=2) fig, ax = pitch.draw( figsize=(16, 9), nrows=1, ncols=2, ) pitch.hexbin(df_before_false9.x, df_before_false9.y, ax=ax[0], cmap='Blues') pitch.hexbin(df_false9.x, df_false9.y, ax=ax[1], cmap='Blues') TITLE_STR1 = 'Messi in the game directly before \n playing in the false 9 role' TITLE_STR2 = 'The first Game Messi \nplayed in the false 9 role' title1 = ax[0].set_title(TITLE_STR1, fontsize=25, pad=20) title2 = ax[1].set_title(TITLE_STR2, fontsize=25, pad=20)
'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 = Pitch(pitch_type='statsbomb', line_zorder=2, line_color='white') # draw fig, ax = pitch.draw(figsize=(16, 9)) bin_statistic = pitch.bin_statistic(df.x, df.y, statistic='count', bins=(25, 25)) bin_statistic['statistic'] = gaussian_filter(bin_statistic['statistic'], 1) pcm = pitch.heatmap(bin_statistic, ax=ax, cmap='hot', edgecolors='#22312b') cbar = fig.colorbar(pcm, ax=ax) TITLE_STR = 'Location of pressure events - 3 home games for Chelsea FC Women' title = fig.suptitle(TITLE_STR, x=0.4, y=0.98, fontsize=23)
height6 = BOTTOM_WIDTH / pitch6.ax_aspect * FIG_ASPECT # calculate pitch offsets from center / title locations vertical_axes_space = (1 - (height1 + height4 + TITLE_HEIGHT + TITLE_HEIGHT)) / 5 bottom_offset = ((1 - height4) / 2) - vertical_axes_space title1_bottom = 1 - vertical_axes_space - TITLE_HEIGHT title2_bottom = 1 - (vertical_axes_space * 3) - (TITLE_HEIGHT * 2) - height1 top_offset = (1 - title1_bottom - title2_bottom - TITLE_HEIGHT) / 2 # draw pitches # top left LEFT1 = TOP_SPACE bottom1 = (1 - height1) / 2 - top_offset ax1 = fig.add_axes((LEFT1, bottom1, TOP_WIDTH, height1)) pitch1.draw(ax=ax1) # top middle left2 = (TOP_SPACE * 2) + TOP_WIDTH bottom2 = (1 - height2) / 2 - top_offset ax2 = fig.add_axes((left2, bottom2, TOP_WIDTH, height2)) pitch2.draw(ax=ax2) # top right left3 = (TOP_SPACE * 3) + (TOP_WIDTH * 2) bottom3 = (1 - height3) / 2 - top_offset ax3 = fig.add_axes((left3, bottom3, TOP_WIDTH, height3)) pitch3.draw(ax=ax3) # bottom left LEFT4 = BOTTOM_SPACE
import matplotlib.pyplot as plt # read data df = read_event(f'{EVENT_SLUG}/7478.json', related_event_df=False, shot_freeze_frame_df=False, tactics_lineup_df=False)['event'] ############################################################################## # Filter passes by Jodie Taylor df = df[(df.player_name == 'Jodie Taylor') & (df.type_name == 'Pass')].copy() ############################################################################## # Plotting pitch = Pitch() fig, ax = pitch.draw(figsize=(8, 6)) hull = pitch.convexhull(df.x, df.y) poly = pitch.polygon(hull, ax=ax, edgecolor='cornflowerblue', facecolor='cornflowerblue', alpha=0.3) scatter = pitch.scatter(df.x, df.y, ax=ax, edgecolor='black', facecolor='cornflowerblue') plt.show( ) # if you are not using a Jupyter notebook this is necessary to show the plot
'ha': 'center', 'va': 'bottom', 'fontweight': 'bold', 'fontstyle': 'italic', 'c': FONTCOLOR } for idx, pt in enumerate(pitch_types): if pt in ['tracab', 'metricasports', 'custom', 'skillcorner']: pitch = Pitch(pitch_type=pt, pitch_length=105, pitch_width=68, **pitch_kwargs) else: pitch = Pitch(pitch_type=pt, **pitch_kwargs) pitch.draw(axes[idx]) xmin, xmax, ymin, ymax = pitch.extent if pitch.dim.aspect != 1: TEXT = 'data coordinates \n are square (1:1) \n scale up to a real-pitch size' axes[idx].annotate(TEXT, xy=(xmin, ymin), xytext=(0 + (xmax - xmin) / 2, ymin), **font_kwargs) axes[idx].xaxis.set_ticks([xmin, xmax]) axes[idx].yaxis.set_ticks([ymin, ymax]) axes[idx].tick_params(labelsize=15) if pt == 'skillcorner': axes[idx].set_title('skillcorner / secondspectrum', fontsize=20, c='#9749b9', pad=15)