figsize=(16, 9), ncols=3, nrows=1, ) # heatmap specified by (nx, ny) for horizontal pitch bins = [(6, 5), (1, 5), (6, 1)] for i, bin_dimension in enumerate(bins): bin_statistic = pitch.bin_statistic(df.x, df.y, statistic='count', bins=bin_dimension) # draw pitch.heatmap(bin_statistic, ax=ax[i], cmap='coolwarm', edgecolors='#22312b') pitch.scatter(df.x, df.y, c='white', s=2, ax=ax[i]) # replace raw counts with percentages and add percentage sign # (note immutable named tuple so used _replace) bin_statistic['statistic'] = ((pd.DataFrame( (bin_statistic['statistic'] / bin_statistic['statistic'].sum() ))).applymap(lambda x: '{:.0%}'.format(x)).values) pitch.label_heatmap(bin_statistic, color='white', fontsize=18, ax=ax[i], ha='center', va='bottom') TITLE_STR = 'Location of pressure events - 3 home games for Chelsea FC Women' title = fig.suptitle(TITLE_STR, x=0.5, y=0.98, fontsize=30)
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, how='all').copy() ############################################################################## # Location dataset df = pd.concat([df_shot_event[['x', 'y']], df_freeze_frame[['x', 'y']]]) x = df.x.values y = df.y.values teams = np.concatenate([[True], df_freeze_frame.player_teammate.values]) ############################################################################## # Plotting # draw plot pitch = VerticalPitch(half=True) fig, ax = pitch.draw(figsize=(8, 6.2)) # Plot Voronoi team1, team2 = pitch.voronoi(x, y, teams) t1 = pitch.polygon(team1, ax=ax, fc='#c34c45', ec='white', lw=3, alpha=0.4) t2 = pitch.polygon(team2, ax=ax, fc='#6f63c5', ec='white', lw=3, alpha=0.4) # Plot players sc1 = pitch.scatter(x[teams], y[teams], ax=ax, c='#c34c45', s=150) sc2 = pitch.scatter(x[~teams], y[~teams], ax=ax, c='#6f63c5', s=150)
custom_pitch = VerticalPitch(pitch_type='custom', line_color='black', half=True, pitch_length=105, pitch_width=68, line_zorder=3) ax_custom = fig.add_axes( (0.55, 0.05, 0.4, 0.4 * FIGWIDTH / FIGHEIGHT / custom_pitch.ax_aspect)) custom_pitch.draw(ax=ax_custom) # draw the original event points fm = FontManager() # a mplsoccer fontmanager with the default Robotto font opta_pitch.scatter(x, y, s=250, marker='x', alpha=0.8, edgecolor='black', facecolor='#6778d0', ax=ax_opta) TEXT = ('The initial points are inside\n' 'the penalty area, six yard box,\n' 'and on the penalty-spot') _ = ax_text(50, 70, TEXT, va='center', ha='center', fontproperties=fm.prop, fontsize=20, ax=ax_opta)
grid_height=0.7, marginal=0.1, # plot without endnote/ title axes endnote_height=0, title_height=0, # here we filter out the left and top marginal axes ax_top=False, ax_bottom=True, ax_left=False, ax_right=True) # typical shot map where the scatter points vary by the expected goals value # using alpha for transparency as there are a lot of shots stacked around the six-yard box sc_team2 = vertical_pitch.scatter(df_team2.x, df_team2.y, s=df_team2.shot_statsbomb_xg * 700, alpha=0.5, ec='black', color='#697cd4', ax=axes[0]) # kdeplots on the marginals # remember to flip the coordinates y=x, x=y for the marginals when using vertical orientation team2_hist_x = sns.kdeplot(y=df_team2.x, ax=axes[3], color='#697cd4', shade=True) team2_hist_y = sns.kdeplot(x=df_team2.y, ax=axes[4], color='#697cd4', shade=True) txt1 = axes[0].text(x=40, y=80,
# By multiplying the expected goals amount by 900 and adding 100 # we essentially get a size that varies between 100 and 1000. # For choosing color schemes, I really like this website # `iWantHue <https://medialab.github.io/iwanthue/>`_. pitch = VerticalPitch( pad_bottom=0.5, # pitch extends slightly below halfway line half=True, # half of a pitch goal_type='box', goal_alpha=0.8) # control the goal transparency fig, ax = pitch.draw(figsize=(12, 10)) sc = pitch.scatter( df_shots_barca.x, df_shots_barca.y, # size varies between 100 and 1000 (points squared) s=(df_shots_barca.shot_statsbomb_xg * 900) + 100, c='#b94b75', # color for scatter in hex format edgecolors='#383838', # give the markers a charcoal border # for other markers types see: https://matplotlib.org/api/markers_api.html marker='h', ax=ax) txt = ax.text( x=40, y=80, s='Barcelona shots\nversus Sevilla', size=30, # here i am using a downloaded font from google fonts instead of passing a fontdict fontproperties=fm_rubik.prop, color=pitch.line_color, va='center', ha='center')
fig, ax = pitch.draw(figsize=(16, 9)) fm = FontManager() # a mplsoccer fontmanager with the default Robotto font # subset portugals shots for both data providers mask_portugal_sb = df_statsbomb.team_name == 'Portugal' mask_shot_sb = df_statsbomb.type_name == 'Shot' mask_portugal_wyscout = df_wyscout.team_name == 'Portugal' mask_shot_wyscout = df_wyscout.event_type == 'SHOT' df_wyscout_portugal = df_wyscout[mask_shot_wyscout & mask_portugal_wyscout].copy() df_statsbomb_portugal = df_statsbomb[mask_shot_sb & mask_portugal_sb].copy() # plotting the shots as a scatter plot with a legend pitch.scatter(df_wyscout_portugal.coordinates_x, df_wyscout_portugal.coordinates_y, ax=ax, color='#56ae6c', label='wyscout', s=250) pitch.scatter(df_statsbomb_portugal.x, df_statsbomb_portugal.y, ax=ax, color='#7f63b8', label='statsbomb', s=250) # plotting the text and using adjust text so it doesn't overlap texts = [] for i in range(len(df_wyscout_portugal)): text = ax.text(df_wyscout_portugal['coordinates_y'].iloc[i], df_wyscout_portugal['coordinates_x'].iloc[i], df_wyscout_portugal['last_name'].iloc[i],
df_pass.y, df_pass.end_x, df_pass.end_y, lw=10, transparent=True, comet=True, cmap='jet', label='pass leading to shot', ax=ax) # Plot the goals pitch.scatter(df_pass[mask_goal].end_x, df_pass[mask_goal].end_y, s=700, marker='football', edgecolors='black', c='white', zorder=2, label='goal', ax=ax) pitch.scatter(df_pass[~mask_goal].end_x, df_pass[~mask_goal].end_y, edgecolors='white', c='#22312b', s=700, zorder=2, label='shot', ax=ax) # Set the title ax.set_title(f'{TEAM1} passes leading to shots \n vs {TEAM2}', fontsize=30)
# We will use mplsoccer's grid function to plot a pitch with a title axis. fig, axs = pitch.grid( figheight=8, endnote_height=0, # no endnote title_height=0.1, title_space=0.02, # Turn off the endnote/title axis. I usually do this after # I am happy with the chart layout and text placement axis=False, grid_height=0.83) # Plot the players sc1 = pitch.scatter(df_team1.x, df_team1.y, s=600, c='#727cce', label='Attacker', ax=axs['pitch']) sc2 = pitch.scatter(df_team2_other.x, df_team2_other.y, s=600, c='#5ba965', label='Defender', ax=axs['pitch']) sc4 = pitch.scatter(df_team2_goal.x, df_team2_goal.y, s=600, ax=axs['pitch'], c='#c15ca5', label='Goalkeeper')