#!/usr/bin/env python # coding: utf-8 # In[749]: import pandas as pd import numpy as np import scipy.stats as stats from scipy.stats import zscore import matplotlib.pyplot as plt from soccerplots.radar_chart import Radar from mplsoccer import PyPizza, add_image, FontManager import math from PIL import Image import imageio # In[770]: #Read in CSV file df = pd.read_csv('HeartsDataset-statsbomb.csv') #Duplciate and rename these three columns as we want them at the end df['PLAYER NUMBER NAME'] = df['PLAYER NUMBER'] df['Age_'] = df['Age'] # In[771]: #Dataset Preview df.head() # In[772]: #Filter the dataset #Minimum 500 mins #27 years old or younger df = df.loc[(df['Age']<28) & (df['Minutes Played']>500)] # In[773]: #Seperating dataframe for player key information df1 = df.filter(['PLAYER NUMBER NAME','Competition','Season'], axis=1) # In[774]: #Convert all numeric values to Z-Scores, this is the maths distribution used to generate ratings numeric_cols = df.select_dtypes(include=[np.number]).columns df2 = df[numeric_cols].apply(zscore) # In[775]: #Combine both the player info dataframe and Z-Score data frame together #Values used to standarise z-scores to allow ratings to be on a 100 scale newdf = pd.concat([df1,df2 * 15 + 50], axis = 1) # In[776]: #Preview of dataframe with all zscores newdf.head() # In[777]: # Weight and Ratings for metrics #Overall minutes score newdf['Minutes Score - (15%)'] = newdf['Minutes Played'] #Defending metrics newdf['PAdjClearances'] = newdf['PAdj Clearances'] *0.1 newdf['PAdjTackles&Interceptions'] = newdf['PAdj Tackles & Interceptions'] *0.4 newdf['Blocks/Shot'] = newdf['Blocks/Shot'] *0.1 newdf['DribblesSuccessfullyDefended%'] = newdf['Dribbles Successfully Defended%'] *0.2 newdf['DefensiveActionRegains'] = newdf['Defensive Action Regains'] *0.2 #Overall defending score newdf['Defending Score - (20%)'] = newdf['PAdjClearances'] + newdf['PAdjTackles&Interceptions'] + newdf['Blocks/Shot'] + newdf['DribblesSuccessfullyDefended%'] + newdf['DefensiveActionRegains'] #Aerial metrics newdf['AerialWins'] = newdf['Aerial Wins'] *0.35 newdf['AerialWin%'] = newdf['Aerial Win%'] *0.65 #Overall aerial score newdf['Aerial Score - (7.5%)'] = newdf['AerialWins'] + newdf['AerialWin%'] #Crossing metrics newdf['SuccessfulCrosses'] = newdf['Successful Crosses'] *0.6 newdf['SuccessfulBoxCross%'] = newdf['Successful Box Cross%'] *0.4 #Overall crossing score newdf['Crossing Score - (10%)'] = newdf['SuccessfulCrosses'] + newdf['SuccessfulBoxCross%'] #Dribbling metrixs newdf['Dribble&CarryOBV'] = newdf['Dribble & Carry OBV'] *0.5 newdf['SuccessfulDribbles'] = newdf['Successful Dribbles'] *0.3 newdf['Carries_'] = newdf['Carries'] *0.2 #Overall dribbling score newdf['Dribbling Score - (15%)'] = newdf['Dribble&CarryOBV'] + newdf['SuccessfulDribbles'] + newdf['Carries_'] #Creativity metrics newdf['OBV_'] = newdf['OBV'] *0.5 newdf['OpenPlayxGAssisted'] = newdf['Open Play xG Assisted'] *0.3 newdf['OpenPlayKeyPasses'] = newdf['Open Play Key Passes'] *0.2 #Overall creativity score newdf['Creativity Score - (20%)'] = newdf['OBV_'] + newdf['OpenPlayxGAssisted'] + newdf['OpenPlayKeyPasses'] #Ball Quality metrics newdf['xGBuildup_'] = newdf['xGBuildup'] *0.4 newdf['DeepProgressions'] = newdf['Deep Progressions'] *0.3 newdf['OPPassesIntoBox'] = newdf['OP Passes Into Box'] *0.2 newdf['OpenPlayFinalThirdPasses'] = newdf['Open Play Final Third Passes'] *0.1 #Overall ball quality score newdf['BallQuality Score - (12.5%)'] = newdf['xGBuildup_'] + newdf['DeepProgressions'] + newdf['OPPassesIntoBox'] + newdf['OpenPlayFinalThirdPasses'] # In[778]: #Creating a new dataframe with all attributes newdf.drop(newdf.columns.difference(['PLAYER NUMBER NAME','Competition','Season','Minutes Score - (15%)','Defending Score - (20%)','Aerial Score - (7.5%)','Crossing Score - (10%)','Dribbling Score - (15%)','Creativity Score - (20%)','BallQuality Score - (12.5%)']), 1, inplace=True) df3 = newdf df3.columns = ['Player', 'Competition','Season','PLAYER NUMBER NAME', 'Minutes Score - (15%)', 'Defending Score - (20%)', 'Aerial Score - (7.5%)', 'Crossing Score - (10%)', 'Dribbling Score - (15%)', 'Creativity Score - (20%)', 'BallQuality Score - (12.5%)'] df3 = df3.drop('PLAYER NUMBER NAME', axis=1) #Round overall attributes df3 = df3.round({'Minutes Score - (15%)': 2}) df3 = df3.round({'Defending Score - (20%)': 2}) df3 = df3.round({'Aerial Score - (7.5%)': 2}) df3 = df3.round({'Crossing Score - (10%)': 2}) df3 = df3.round({'Dribbling Score - (15%)': 2}) df3 = df3.round({'Creativity Score - (20%)': 2}) df3 = df3.round({'BallQuality Score - (12.5%)': 2}) df3.head() # In[779]: #Seperating dataframe from player key information dfviz = df3.filter(['Player','Minutes Score - (15%)', 'Defending Score - (20%)', 'Aerial Score - (7.5%)', 'Crossing Score - (10%)', 'Dribbling Score - (15%)', 'Creativity Score - (20%)', 'BallQuality Score - (12.5%)'], axis=1) # In[780]: #Rating Breakdown visual #get parameters params = list(dfviz.columns) print(params) #drop the first list team because we don't need player name. Start at first metric params = params[1:] #Input player name or number here values = dfviz.loc[dfviz['Player']==77].reset_index() values = list(values.loc[0]) values = values[2:] #Getting the min and max values for the ranges for the data visual min_range = [] max_range = [] for x in params: a = min(dfviz[params][x]) b = max(dfviz[params][x]) min_range.append((a)) max_range.append((b)) #Creating pizza chart for rating breakdown visual baker = PyPizza( params=params, background_color="white", straight_line_color="#000000", min_range=min_range, # min range values max_range=max_range, # max range values last_circle_color="#000000", last_circle_lw=2.5, straight_line_lw=1, other_circle_lw=0, other_circle_color="#000000", inner_circle_size=16.5, ) # plot pizza fig, ax = baker.make_pizza( values, # list of values figsize=(10, 10), # adjust figsize according to your need color_blank_space="same", # use same color to fill blank space blank_alpha=0.4, # alpha for blank-space colors kwargs_slices=dict( facecolor="#660000",edgecolor="white", zorder=2, linewidth=1 ), # values to be used when plotting slices kwargs_params=dict( color="#000000", fontsize=13, ), # values to be used when adding parameter kwargs_values=dict( color="white", fontsize=13, bbox=dict( edgecolor="white", facecolor="#660000", boxstyle="round,pad=0.2", lw=1 ) ) # values to be used when adding parameter-values ) # Add Title / Edit Player Name and Club fig.text( 0.515, 0.975, "Player Number 77 - Premiership 2021/2022", size=18, fontweight='bold', ha="center", color="#000000" ) # Add Subtitle fig.text( 0.515, 0.956, "Fullback / Wingback Rating Breakdown | Hearts Dataset", size=14, ha="center", color="#000000" ) # add credits CREDIT_1 = "Graphic: @HenshawAnalysis" CREDIT_2 = "Data is via Statsbomb" CREDIT_3 = "Template: Fullback / Wingback Rating Breakdown" CREDIT_4 = "Notes: Value in brackets is the weighting for that attribute" fig.text( 0.935, 0.000, f"{CREDIT_1}\n{CREDIT_2}\n{CREDIT_3}\n{CREDIT_4}", size=9, color="#545454", ha="right" ) fig.text (0.511, 0.509, "Overall\nRating", size=12, ha="center", fontweight='bold') fig.text (0.511, 0.48, "65.31", size=16, ha="center", fontweight='bold') # add image im2 = imageio.imread('HeartsLogo.png') ax_image = add_image( im2, fig, left=0.09, bottom=-0.01, width=0.13, height=0.127 ) # these values might differ when you are plotting plt.show() # In[781]: #Weight the overall ratings df3['Minutes Score - (15%)'] = df3['Minutes Score - (15%)'] *0.15 df3['Defending Score - (20%)'] = df3['Defending Score - (20%)'] *0.2 df3['Aerial Score - (7.5%)'] = df3['Aerial Score - (7.5%)'] *0.075 df3['Crossing Score - (10%)'] = df3['Crossing Score - (10%)'] *0.1 df3['Dribbling Score - (15%)'] = df3['Dribbling Score - (15%)'] *0.15 df3['Creativity Score - (20%)'] = df3['Creativity Score - (20%)'] *0.2 df3['BallQuality Score - (12.5%)'] = df3['BallQuality Score - (12.5%)'] *0.125 df3['FBWB_Rating'] = df3['Minutes Score - (15%)'] + df3['Defending Score - (20%)'] + df3['Aerial Score - (7.5%)'] + df3['Crossing Score - (10%)'] + df3['Creativity Score - (20%)'] + df3['BallQuality Score - (12.5%)'] #Round overall ratings df3 = df3.round({'FBWB_Rating': 2}) df3.sort_values("FBWB_Rating", ascending=False) # In[782]: #Download as ratings to CSV df3.to_csv('HeartsDataTaskRatings.csv', index=False) # In[ ]: # In[783]: #PIZZA CHART DATA VISUAL BELOW # In[784]: #Filter metrics for Pizza Chart dfviz = df.filter(['PLAYER NUMBER','Successful Crosses','Successful Dribbles','Touches In Box','Dribble & Carry OBV','xGBuildup','Open Play xG Assisted','Open Play Key Passes','Deep Progressions','OP Passes Into Box','Passing%','PAdj Tackles & Interceptions','Dribbles Successfully Defended%','Defensive Action Regains','Aerial Win%','Aerial Wins'], axis=1) # In[785]: #Rename metrics for visual dfviz.columns = ['PLAYER NUMBER','Successful Crosses','Successful Dribbles','Touches In Box','Dribble & Carry OBV','xGBuildup','Open Play xG\nAssisted','Open Play Key\nPasses','Deep Progressions','OP Passes Into Box','Passing%','PAdj Tackles &\nInterceptions','Dribbles Successfully\nDefended%','Defensive Action\nRegains','Aerial Win%','Aerial Wins'] # In[786]: dfviz.head() # In[787]: #get parameters params = list(dfviz.columns) #drop the first list team because we don't need player name. Start at first metric params = params[1:] #NEW DATA FRAME FOR YOUR PLAYER / EDIT NAME Player = dfviz.loc[dfviz['PLAYER NUMBER']==77].reset_index() Player = list(Player.loc[0]) Player = Player[2:] #Creating the percentile rank score values = [] for x in range(len(params)): values.append(math.floor(stats.percentileofscore(dfviz[params[x]],Player[x]))) # color for the slices and text slice_colors = ["#660000"] * 5 + ["#014F8A"] * 5 + ["grey"] * 5 text_colors = ["white"] * 15 # instantiate PyPizza class baker = PyPizza( params=params, # list of parameters background_color='white', # background color straight_line_color="#EBEBE9", # color for straight lines straight_line_lw=1, # linewidth for straight lines last_circle_lw=0, # linewidth of last circle other_circle_lw=0, # linewidth for other circles inner_circle_size=5 # size of inner circle ) # plot pizza fig, ax = baker.make_pizza( values, # list of values figsize=(10, 10), # adjust figsize according to your need color_blank_space="same", # use same color to fill blank space slice_colors=slice_colors, # color for individual slices value_colors=text_colors, # color for the value-text value_bck_colors=slice_colors, # color for the blank spaces blank_alpha=0.4, # alpha for blank-space colors kwargs_slices=dict( edgecolor="#F2F2F2", zorder=2, linewidth=1 ), # values to be used when plotting slices kwargs_params=dict( color="#000000", fontsize=11, ), # values to be used when adding parameter kwargs_values=dict( color="#000000", fontsize=12, bbox=dict( edgecolor="white", facecolor="cornflowerblue", boxstyle="round,pad=0.2", lw=1 ) ) # values to be used when adding parameter-values ) # add title fig.text( 0.515, 0.975, "Player Number 77 - Premiership 2021/2022", size=16, fontweight='bold', ha="center", color="#000000" ) # add subtitle fig.text( 0.515, 0.956, "Percentile Rank vs Fullbacks / Wingbacks | Hearts Dataset", size=14, ha="center", color="#000000" ) # add credits CREDIT_1 = "Inspired by: @Worville, @FootballSlices, @somazerofc & @Soumyaj15209314" CREDIT_2 = "Graphic: @HenshawAnalysis" CREDIT_3 = "Template: Fullback / Wingback" CREDIT_4 = "Data is via Statsbomb" fig.text( 0.94, 0.000, f"{CREDIT_1}\n{CREDIT_2}\n{CREDIT_3}\n{CREDIT_4}", size=9, color="#545454", ha="right" ) # add text fig.text( 0.35, 0.93, "Attacking Possession Defending", size=14, color="#000000" ) # add rectangles fig.patches.extend([ plt.Rectangle( (0.32, 0.9275), 0.025, 0.021, fill=True, color="#660000", transform=fig.transFigure, figure=fig ), plt.Rectangle( (0.445, 0.9275), 0.025, 0.021, fill=True, color="#014F8A", transform=fig.transFigure, figure=fig ), plt.Rectangle( (0.582, 0.9275), 0.025, 0.021, fill=True, color="grey", transform=fig.transFigure, figure=fig ), ]) im2 = imageio.imread('HeartsLogo.png') # add image ax_image = add_image( im2, fig, left=0.09, bottom=-0.01, width=0.13, height=0.127 ) # these values might differ when you are plotting plt.show() # In[ ]: # In[ ]: # In[ ]: