import matplotlib.pyplot as plt import numpy as np from PIL import Image from highlight_text import ax_text from mplsoccer import Pitch, VerticalPitch, add_image, FontManager from mplsoccer.statsbomb import read_event, read_lineup, EVENT_SLUG, LINEUP_SLUG ############################################################################## # Single Pitch # ------------ # You can also use grid to plot a single pitch with an endnote and title axis. # The defaults setup a pitch with a 2.5% # (of the figure height/ width) border around the sides. pitch = Pitch() fig, axs = pitch.grid() ############################################################################## # Multiple Pitches side by side # ----------------------------- # Next up let's plot 3 pitches side-by-side. pitch = VerticalPitch() fig, axs = pitch.grid(figheight=15, ncols=3) ############################################################################## # Grid of Pitches # --------------- # Here's how to plot a grid of pitches pitch = Pitch(linewidth=4) fig, axs = pitch.grid(nrows=3, ncols=4, # number of rows/ columns figheight=25, # the figure height in inches
# Plotting with an endnote/title # We will use mplsoccer's grid function to plot a pitch with a title axis. pitch = Pitch(pitch_type='statsbomb', pad_bottom=1, pad_top=1, pad_left=1, pad_right=1, line_zorder=2, line_color='#c7d5cc', pitch_color='#22312b') fig, axs = pitch.grid( figheight=8, endnote_height=0.03, endnote_space=0, title_height=0.1, title_space=0, grid_height=0.82, # Turn off the endnote/title axis. I usually do this after # I am happy with the chart layout and text placement axis=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=axs['pitch'], 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,
# by setting ``constrained_layout=True`` and ``tight_layout=False``, which may look better. # See: https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html. pitch = Pitch() fig, axs = pitch.draw(nrows=2, ncols=3, tight_layout=False, constrained_layout=True) ############################################################################## # If you want more control over how pitches are placed # you can use the grid method. This also works for one pitch (nrows=1 and ncols=1). # It also plots axes for an endnote and title (see the plot_grid example for more information). pitch = Pitch() fig, axs = pitch.grid(nrows=3, ncols=3, figheight=10, # the grid takes up 71.5% of the figure height grid_height=0.715, # 5% of grid_height is reserved for space between axes space=0.05, # centers the grid horizontally / vertically left=None, bottom=None) ############################################################################## # Pitch orientation # ----------------- # There are four basic pitch orientations. # To get vertical pitches use the VerticalPitch class. # To get half pitches use the half=True argument. # # Horizontal full pitch = Pitch(half=False) fig, ax = pitch.draw()
# '#00ff41' (matrix green), 'r' (red), '#9467bd' (viloet) BACKGROUND_COLOR = '#212946' PASS_COLOR = '#FE53BB' LINE_COLOR = '#08F7FE' # plot as initial pitch and the lines with alpha=1 # I have used grid to get a title and endnote axis automatically, but you could you pitch.draw() pitch = Pitch(line_color=LINE_COLOR, pitch_color=BACKGROUND_COLOR, linewidth=LINEWIDTH, line_alpha=1, goal_alpha=1, goal_type='box') fig, ax = pitch.grid(grid_height=0.9, title_height=0.06, axis=False, endnote_height=0.04, title_space=0, endnote_space=0) fig.set_facecolor(BACKGROUND_COLOR) pitch.lines( df_pass.x, df_pass.y, df_pass.end_x, df_pass.end_y, capstyle='butt', # cut-off the line at the end-location. linewidth=LINEWIDTH, color=PASS_COLOR, comet=True, ax=ax['pitch']) # plotting the titles and endnote
ncols=3, tight_layout=False, constrained_layout=True) ############################################################################## # If you want more control over how pitches are placed # you can use the grid method. This also works for one pitch (nrows=1 and ncols=1). # It also plots axes for an endnote and title (see the plot_grid example for more information). pitch = Pitch() fig, axs, ax_title, ax_endnote = pitch.grid( nrows=3, ncols=3, figheight=10, # the grid takes up 71.5% of the figure height grid_height=0.715, # 5% of grid_height is reserved for space between axes space=0.05, # centers the grid horizontally left=None, # grid starts 2.5% up from the bottom of the figure bottom=0.025) ############################################################################## # Pitch orientation # ----------------- # There are four basic pitch orientations. # To get vertical pitches use the VerticalPitch class. # To get half pitches use the half=True argument. # # Horizontal full
# setup a mplsoccer pitch pitch = Pitch(line_zorder=2, line_color='black', pad_top=20) # 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)) GRID_HEIGHT = 0.8 CBAR_WIDTH = 0.03 fig, axs = pitch.grid(nrows=4, ncols=5, figheight=20, # leaves some space on the right hand side for the colorbar grid_width=0.88, left=0.025, endnote_height=0.06, endnote_space=0, # Turn off the endnote/title axis. I usually do this after # I am happy with the chart layout and text placement axis=False, title_space=0.02, title_height=0.06, grid_height=GRID_HEIGHT) fig.set_facecolor('white') 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(axs['pitch'].flat[:len(teams)]): # the top of the StatsBomb pitch is zero # plot the title half way between zero and -20 (the top padding) ax.text(60, -10, teams[i], ha='center', va='center', fontsize=50, fontproperties=fm.prop)
pad_left=2, pad_right=2, pitch_color='#22312b') # calculate the maximum grid_height/ width GRID_WIDTH, GRID_HEIGHT = pitch.calculate_grid_dimensions(figwidth=FIGWIDTH, figheight=FIGHEIGHT, nrows=NROWS, ncols=NCOLS, max_grid=MAX_GRID, space=0) # plot using the mplsoccer grid function fig, ax = pitch.grid(figheight=FIGHEIGHT, grid_width=GRID_WIDTH, grid_height=GRID_HEIGHT, title_height=0, endnote_height=0) fig.set_facecolor('#22312b') ############################################################################## # 16 by 9 horizontal grass # ------------------------ # Now let's get the largest pitch possible for a 16:9 figure but with grassy stripes. # See `Caley Graphics <https://twitter.com/Caley_graphics>`_ for some inspiration # on how you might add titles on the pitch. FIGWIDTH = 16 FIGHEIGHT = 9 NROWS = 1 NCOLS = 1