nesticot commited on
Commit
944be2e
·
verified ·
1 Parent(s): 8fc72fb

Update functions/rolling_batter_functions.py

Browse files
Files changed (1) hide show
  1. functions/rolling_batter_functions.py +337 -337
functions/rolling_batter_functions.py CHANGED
@@ -1,338 +1,338 @@
1
- import pandas as pd
2
- import numpy as np
3
- import matplotlib.pyplot as plt
4
- import seaborn as sns
5
- import numpy as np
6
- from scipy.stats import gaussian_kde
7
- import matplotlib
8
- from matplotlib.ticker import MaxNLocator
9
- from matplotlib.gridspec import GridSpec
10
- from scipy.stats import zscore
11
- import math
12
- import matplotlib
13
- from adjustText import adjust_text
14
- import matplotlib.ticker as mtick
15
- import pandas as pd
16
- from matplotlib.pyplot import text
17
- import inflect
18
-
19
-
20
- colour_palette = ['#FFB000','#648FFF','#785EF0',
21
- '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
22
-
23
- plot_dict = {
24
- 'k':{'x_axis':'Plate Appearances','y_axis':'K%','title':'K%','x_value':'k','x_range':[0.0,0.1,0.2,0.3,0.4],'percent':True,'percentile_label':'k_percent','flip_p':True,'percentile':False,'avg_adjust':False},
25
- 'bb':{'x_axis':'Plate Appearances','y_axis':'BB%','title':'BB%','x_value':'bb','x_range':[0.0,0.1,0.2,0.3],'percent':True,'percentile_label':'bb_percent','flip_p':False,'percentile':False,'avg_adjust':False},
26
- 'bb_minus_k':{'x_axis':'Plate Appearances','y_axis':'BB-K%','title':'BB-K%','x_value':'bb_minus_k','x_range':[-0.3,-0.2,-0.1,0,0.1,0.2],'percent':True,'percentile_label':'bb_minus_k_percent','flip_p':False,'percentile':False,'avg_adjust':False},
27
- 'csw':{'x_axis':'Pitches','y_axis':'CSW%','title':'CSW%','x_value':'csw','x_range':[.2,.25,.3,.35,.4],'percent':True,'percentile_label':'csw_percent','flip_p':True,'percentile':False,'avg_adjust':False},
28
- 'woba':{'x_axis':'wOBA PA','y_axis':'wOBA','title':'wOBA','x_value':'woba','x_range':[.20,.30,.40,.50],'percent':False,'percentile_label':'woba_percent','flip_p':False,'percentile':False,'avg_adjust':True},
29
- 'launch_speed':{'x_axis':'Balls In Play','y_axis':'Exit Velocity','title':'Exit Velocity','x_value':'launch_speed','x_range':[85,90,95,100],'percent':False,'percentile_label':'launch_speed','flip_p':False,'percentile':False,'avg_adjust':False},
30
- 'launch_speed_90':{'x_axis':'Balls In Play','y_axis':'90th Percentile Exit Velocity','title':'90th Percentile Exit Velocity','x_value':'launch_speed','x_range':[95,100,105,110,115],'percent':False,'percentile_label':'launch_speed_90','flip_p':False,'percentile':True,'avg_adjust':False},
31
- 'hard_hit':{'x_axis':'Balls In Play','y_axis':'HardHit%','title':'HardHit%','x_value':'hard_hit','x_range':[0.2,0.3,0.4,0.5,0.6,0.7],'percent':True,'percentile_label':'hard_hit_percent','flip_p':False,'percentile':False,'avg_adjust':False},
32
- 'sweet_spot':{'x_axis':'Balls In Play','y_axis':'SweetSpot%','title':'SweetSpot%','x_value':'sweet_spot','x_range':[0.2,0.3,0.4,0.5],'percent':True,'percentile_label':'sweet_spot_percent','flip_p':False,'percentile':False,'avg_adjust':False},
33
- 'launch_angle':{'x_axis':'Balls In Play','y_axis':'Launch Angle','title':'Launch Angle','x_value':'launch_angle','x_range':[-20,-10,0,10,20],'percent':False,'percentile_label':'launch_angle','flip_p':False,'percentile':False,'avg_adjust':False},
34
- 'barrel':{'x_axis':'Balls In Play','y_axis':'Barrel%','title':'Barrel%','x_value':'barrel','x_range':[0,0.05,0.10,.15,.20],'percent':True,'percentile_label':'barrel_percent','flip_p':False,'percentile':False,'avg_adjust':False},
35
- 'zone_percent':{'x_axis':'Pitches','y_axis':'Zone%','title':'Zone%','x_value':'in_zone','x_range':[0.3,0.4,0.5,0.6,0.7],'percent':True,'percentile_label':'zone_percent','flip_p':False,'percentile':False,'avg_adjust':False},
36
- 'swing_percent':{'x_axis':'Pitches','y_axis':'Swing%','title':'Swing%','x_value':'swings','x_range':[0.2,0.3,0.4,0.5,0.6,0.7,0.8],'percent':True,'percentile_label':'swing_percent','flip_p':False,'percentile':False,'avg_adjust':False},
37
- 'whiff_percent':{'x_axis':'Swings','y_axis':'Whiff%','title':'Whiff%','x_value':'whiffs','x_range':[0.0,0.1,0.2,0.3,0.4,0.5],'percent':True,'percentile_label':'whiff_rate','flip_p':True,'percentile':False,'avg_adjust':False},
38
- 'sw_str':{'x_axis':'Pitches','y_axis':'SwStr%','title':'SwStr%','x_value':'whiffs','x_range':[0.0,0.05,0.1,0.15,0.2,0.25],'percent':True,'percentile_label':'swstr_rate','flip_p':True,'percentile':False,'avg_adjust':False},
39
- 'zone_swing':{'x_axis':'In-Zone Pitches','y_axis':'Z-Swing%','title':'Z-Swing%','x_value':'zone_swing','x_range':[0.3,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1],'percent':True,'percentile_label':'zone_swing_percent','flip_p':False,'percentile':False,'avg_adjust':False},
40
- 'zone_contact':{'x_axis':'In-Zone Swings','y_axis':'Z-Contact%','title':'Z-Contact%','x_value':'zone_contact','x_range':[0.5,0.6,0.7,0.8,0.9,1],'percent':True,'percentile_label':'zone_contact_percent','flip_p':False,'percentile':False,'avg_adjust':False},
41
- 'chase_percent':{'x_axis':'Out-of-Zone Pitches','y_axis':'O-Swing%','title':'O-Swing%','x_value':'ozone_swing','x_range':[0.0,0.1,0.2,0.3,0.4,0.5],'percent':True,'percentile_label':'chase_percent','flip_p':True,'percentile':False,'avg_adjust':False},
42
- 'chase_contact':{'x_axis':'Out-of-Zone Swings','y_axis':'O-Contact%','title':'O-Contact%','x_value':'ozone_contact','x_range':[0.2,0.3,0.4,0.5,0.6,0.7,0.8],'percent':True,'percentile_label':'chase_contact','flip_p':False,'percentile':False,'avg_adjust':False},}
43
-
44
-
45
- level_dict = {'MLB':'MLB','AAA':'AAA','AA':'AA','A+':'A+','A':'A'}
46
-
47
-
48
- woba_list = ['woba']
49
- pa_list = ['k','bb','bb_minus_k']
50
- balls_in_play_list = ['hard_hit','launch_speed','launch_speed_90','launch_angle','barrel','sweet_spot']
51
- pitches_list = ['zone_percent','swing_percent','sw_str','csw']
52
- swings_list = ['whiff_percent']
53
- in_zone_pitches_list = ['zone_swing']
54
- in_zone_swings_list = ['zone_contact']
55
- out_zone_pitches_list = ['chase_percent']
56
- out_zone_swings_list = ['chase_contact']
57
-
58
- plot_dict_small = {
59
- 'k':'K%',
60
- 'bb':'BB%',
61
- 'bb_minus_k':'BB-K%',
62
- 'csw':'CSW%',
63
- 'woba':'wOBA',
64
- 'launch_speed':'Exit Velocity',
65
- 'launch_speed_90':'90th Percentile Exit Velocity',
66
- 'hard_hit':'HardHit%',
67
- 'sweet_spot':'SweetSpot%',
68
- 'launch_angle':'Launch Angle',
69
- 'zone_percent':'Zone%',
70
- 'barrel':'Barrel%',
71
- 'swing_percent':'Swing%',
72
- 'whiff_percent':'Whiff%',
73
- 'sw_str':'SwStr%',
74
- 'zone_swing':'Z-Swing%',
75
- 'zone_contact':'Z-Contact%',
76
- 'chase_percent':'O-Swing%',
77
- 'chase_contact':'O-Contact%',}
78
-
79
-
80
-
81
- def rolling_plot(df,df_summ,player_id,stat_id,batter_dict,window_select,level_id):
82
- season_title = df['game_date'].str[0:4].values[0]
83
- sns.set_theme(style="whitegrid", palette="pastel")
84
- if player_id == "":
85
- fig = plt.figure(figsize=(12, 12))
86
- fig.text(s='Please Select a Pitcher',x=0.5,y=0.5)
87
- return
88
-
89
-
90
-
91
- swing_min = int(window_select)
92
- fig, ax = plt.subplots(1, 1, figsize=(10, 10))
93
-
94
- fig.set_facecolor('white')
95
- #ax.set_facecolor('white')
96
- #fig.patch.set_facecolor('lightblue')
97
-
98
- print(stat_id)
99
-
100
- if stat_id in pa_list:
101
- print('we hAVE MADE IT TO THIS PART OF THE CODE')
102
-
103
-
104
- if stat_id in pa_list:
105
- elly_zone_df = df[(df.pa==1)&(df.batter_id == int(player_id))&(df.level==level_id)]
106
- divisor_x = 'pa'
107
- print('this is short')
108
- print(elly_zone_df)
109
-
110
-
111
- if stat_id in balls_in_play_list:
112
- elly_zone_df = df[(df.bip)&(df.batter_id == int(player_id))&(df.level==level_id)]
113
- divisor_x = 'bip'
114
- #print('this is short')
115
-
116
- if stat_id in balls_in_play_list:
117
- elly_zone_df = df[(df.bip)&(df.batter_id == int(player_id))&(df.level==level_id)]
118
- divisor_x = 'bip'
119
- print('this is short')
120
-
121
- if stat_id in pitches_list:
122
- elly_zone_df = df[(df.pitches == 1)&(df.batter_id == int(player_id))&(df.level==level_id)]
123
- divisor_x = 'pitches'
124
-
125
- if stat_id in swings_list:
126
- elly_zone_df = df[(df.swings == 1)&(df.batter_id == int(player_id))&(df.level==level_id)]
127
- divisor_x = 'swings'
128
-
129
-
130
- if stat_id in in_zone_pitches_list:
131
- elly_zone_df = df[(df.in_zone)&(df.batter_id == int(player_id))&(df.level==level_id)]
132
- divisor_x = 'in_zone'
133
-
134
-
135
- if stat_id in in_zone_swings_list:
136
- elly_zone_df = df[(df.zone_swing)&(df.batter_id == int(player_id))&(df.level==level_id)]
137
- divisor_x = 'zone_swing'
138
-
139
-
140
- if stat_id in out_zone_pitches_list:
141
- elly_zone_df = df[(df.in_zone == False)&(df.batter_id == int(player_id))&(df.level==level_id)]
142
- divisor_x = 'out_zone'
143
-
144
-
145
- if stat_id in out_zone_swings_list:
146
- elly_zone_df = df[(df.ozone_swing)&(df.batter_id == int(player_id))&(df.level==level_id)]
147
- divisor_x = 'ozone_swing'
148
-
149
- if stat_id in woba_list:
150
- elly_zone_df = df[(df.woba_codes==1)&(df.batter_id == int(player_id))&(df.level==level_id)]
151
- divisor_x = 'woba_codes'
152
-
153
- # penguins = sns.load_dataset("penguins")
154
- # sns.histplot(data=penguins, x="flipper_length_mm")
155
- # print('we made it here:')
156
- # print(int(player_id))
157
- # print(stat_id)
158
- # print(level_id)
159
- # print(df[(df.batter_id == int(player_id))&(df.level==level_id)])
160
- # print(df.columns)
161
- # print(elly_zone_df[plot_dict[stat_id]["x_value"]].sum())
162
-
163
- df_summ_new = df_summ.copy()
164
- df_summ_new = df_summ_new.set_index('batter_id','batter_name','level')
165
- df_summ_new = df_summ_new[df_summ_new[divisor_x] >= int(window_select)]
166
- df_summ_new = df_summ_new[df_summ_new.level==level_id]
167
-
168
- df_summ_rank = df_summ_new.rank(method='max',ascending=False)
169
- df_summ_rank.columns = df_summ_rank.columns+['_rank']
170
-
171
- df_summ_rank_percent = df_summ_new.rank(pct=True)
172
- df_summ_rank_percent.columns = df_summ_rank_percent.columns+['_percent']
173
-
174
-
175
- df_summ_new = df_summ_new.reset_index()
176
- df_summ_rank = df_summ_rank.reset_index()
177
- df_summ_rank_percent = df_summ_rank_percent.reset_index()
178
- print('Table columns:')
179
-
180
- df_summ_new.batter_id = df_summ_new.batter_id.astype(int)
181
- df_summ_rank.batter_id = df_summ_rank.batter_id.astype(int)
182
- df_summ_rank_percent.batter_id = df_summ_rank_percent.batter_id.astype(int)
183
-
184
- print('Table columns2:')
185
- df_summ_new = df_summ_new.merge(df_summ_rank,left_on=['batter_id'],right_on=['batter_id'],how='left',suffixes=['','_rank'])
186
-
187
- df_summ_new = df_summ_new.merge(df_summ_rank_percent,left_on=['batter_id'],right_on=['batter_id'],how='left',suffixes=['','_percent'])
188
-
189
-
190
- print(df_summ_new)
191
- print(df_summ_rank)
192
- print(df_summ_rank_percent)
193
-
194
-
195
-
196
-
197
- #sns.scatterplot(x=data_df.launch_speed_90,y=data_df.zone_contact,color=colour_palette[0],s=75,label=int(player_id))
198
-
199
- df_summ_new_select = df_summ_new[df_summ_new.batter_id == int(player_id)].reset_index(drop=True)
200
- print('whiffing')
201
- print(df)
202
- print('Player _df:')
203
- print(df_summ_new_select)
204
-
205
- if len(df_summ_new_select) < 1:
206
- ax.text(x=0.5,y=0.5,s='Please Select Different Parameters to Produce a plot',fontsize=18,ha='center')
207
- return
208
-
209
- p = inflect.engine()
210
-
211
- df_summ_new_select = df_summ_new_select.loc[:,~df_summ_new_select.columns.duplicated(keep='last')].copy()
212
- print('Table for the player:')
213
- print(list(df_summ_new_select.columns))
214
- print(plot_dict[stat_id]["percentile_label"])
215
- print(plot_dict[stat_id]["percentile_label"]+'_percent')
216
- print(df_summ_new_select)
217
- print(1*plot_dict[stat_id]["flip_p"])
218
- print(round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))
219
- print((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)
220
-
221
- # print(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+'_percent'])
222
-
223
- if plot_dict[stat_id]['percent']:
224
- label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum():.1%}'
225
- label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
226
- #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'
227
- ax.yaxis.set_major_formatter(mtick.PercentFormatter(1))
228
-
229
- else:
230
- label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum():.1f}'
231
- label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1f} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
232
- #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1f}'
233
- #ax.yaxis.set_major_formatter(mtick.int)
234
-
235
-
236
- if plot_dict[stat_id]['percentile']:
237
- label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].quantile(0.9):.1f}'
238
- label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].quantile(0.9):.1f} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
239
- #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'
240
- #ax.yaxis.set_major_formatter(mtick.int)
241
-
242
- if plot_dict[stat_id]['avg_adjust']:
243
- label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum():.3f}'
244
- label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.3f} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
245
- #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'
246
- #ax.yaxis.set_major_formatter(mtick.int)
247
-
248
- print(plot_dict[stat_id]["x_value"])
249
- print(divisor_x)
250
-
251
- # df_summ_new = df_summ.copy()
252
- # df_summ_new = df_summ_new[df_summ_new.balls_in_play >= int(window_select)]
253
- # df_summ_new = df_summ_new[df_summ_new.level==level_id]
254
-
255
-
256
- print('this is here:')
257
- print(df_summ_new.head())
258
- print(df_summ_new.columns)
259
-
260
-
261
- if plot_dict[stat_id]["flip_p"] == False:
262
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[2],linestyle='dotted',alpha=0.5)
263
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[3],linestyle='dotted',alpha=0.5)
264
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[4],linestyle='dotted',alpha=0.5)
265
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[5],linestyle='dotted',alpha=0.5)
266
-
267
-
268
- hard_hit_dates = [(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),
269
- (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),
270
- (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),
271
- (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1)]
272
- hard_hit_text = ['90th %','75th %','25th %','10th %']
273
- for i, x in enumerate(hard_hit_dates):
274
- text(min(window_select+window_select/100,+window_select+1), x ,hard_hit_text[i], rotation=0, ha='left',
275
- bbox=dict(facecolor='white',alpha=0.5, edgecolor=colour_palette[2+i], pad=2))
276
-
277
-
278
-
279
- if plot_dict[stat_id]["flip_p"] == True:
280
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[2],linestyle='dotted',alpha=0.5)
281
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[3],linestyle='dotted',alpha=0.5)
282
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[4],linestyle='dotted',alpha=0.5)
283
- ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[5],linestyle='dotted',alpha=0.5)
284
-
285
- hard_hit_dates = [(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),
286
- (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),
287
- (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),
288
- (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1)]
289
- hard_hit_text = ['10th %','25th %','75th %','90th %']
290
- for i, x in enumerate(hard_hit_dates):
291
- text(min(window_select+window_select/100,window_select+window_select+3), x ,hard_hit_text[i], rotation=0, ha='left',
292
- bbox=dict(facecolor='white',alpha=0.5, edgecolor=colour_palette[2+i], pad=2))
293
-
294
-
295
-
296
-
297
-
298
-
299
- if plot_dict[stat_id]["percentile"] == False:
300
- ax.hlines(y=df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum(),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[1],linestyle='-.',label=label_1)
301
-
302
- ax.hlines(y=elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum(),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[0],linestyle='--',label=label_2)
303
-
304
- sns.lineplot(x=range(1,len(elly_zone_df)+1),y=elly_zone_df[plot_dict[stat_id]["x_value"]].fillna(0).rolling(window=swing_min).sum()/swing_min,color=colour_palette[0],linewidth=3,ax=ax)
305
-
306
-
307
-
308
- if plot_dict[stat_id]["percentile"] == True:
309
-
310
- ax.hlines(y=df[df.level == level_id][plot_dict[stat_id]["x_value"]].quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[1],linestyle='-.',label=label_1)
311
-
312
- ax.hlines(y=elly_zone_df[plot_dict[stat_id]["x_value"]].fillna(0).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[0],linestyle='--',label=label_2)
313
-
314
- sns.lineplot(x=range(1,len(elly_zone_df)+1),y=elly_zone_df[plot_dict[stat_id]["x_value"]].fillna(0).rolling(window=swing_min).quantile(0.9),color=colour_palette[0],linewidth=3,ax=ax)
315
-
316
-
317
- #ax.set_xlim(window_select,exit_velo_df_small.pitch.max())
318
- #plt.yticks([0,0.2,0.4,0.6,0.8,1])
319
- #ax.set_ylim(math.floor((min(df_summ.zone_contact)/5)*100)*5/100,1)
320
- ax.set_xlim(math.floor(swing_min),len(elly_zone_df))
321
- ax.set_title(f'{batter_dict[int(player_id)]} - {season_title} - {level_id} - {swing_min} {plot_dict[stat_id]["x_axis"]} Rolling {plot_dict[stat_id]["title"]}', fontsize=16,fontname='Century Gothic',)
322
- #vals = ax.get_yticks()
323
- ax.set_xlabel(plot_dict[stat_id]['x_axis'], fontsize=16,fontname='Century Gothic')
324
- ax.set_ylabel(plot_dict[stat_id]['y_axis'], fontsize=16,fontname='Century Gothic')
325
-
326
- #fig.axes[0].invert_yaxis()
327
-
328
- #fig.subplots_adjust(wspace=.02, hspace=.02)
329
- #ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))
330
- ax.set_yticks(plot_dict[stat_id]["x_range"])
331
- #fig.colorbar(plot_dist, ax=ax)
332
- #fig.colorbar(plot_dist)
333
- #fig.axes[0].invert_yaxis()
334
- ax.legend(fontsize='16')
335
- fig.text(x=0.03,y=0.02,s='By: @TJStats',fontname='Century Gothic')
336
- fig.text(x=1-0.03,y=0.02,s='Data: MLB',ha='right',fontname='Century Gothic')
337
- fig.tight_layout()
338
  return
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ import seaborn as sns
5
+ import numpy as np
6
+ from scipy.stats import gaussian_kde
7
+ import matplotlib
8
+ from matplotlib.ticker import MaxNLocator
9
+ from matplotlib.gridspec import GridSpec
10
+ from scipy.stats import zscore
11
+ import math
12
+ import matplotlib
13
+ from adjustText import adjust_text
14
+ import matplotlib.ticker as mtick
15
+ import pandas as pd
16
+ from matplotlib.pyplot import text
17
+ import inflect
18
+
19
+
20
+ colour_palette = ['#FFB000','#648FFF','#785EF0',
21
+ '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
22
+
23
+ plot_dict = {
24
+ 'k':{'x_axis':'Plate Appearances','y_axis':'K%','title':'K%','x_value':'k','x_range':[0.0,0.1,0.2,0.3,0.4],'percent':True,'percentile_label':'k_percent','flip_p':True,'percentile':False,'avg_adjust':False},
25
+ 'bb':{'x_axis':'Plate Appearances','y_axis':'BB%','title':'BB%','x_value':'bb','x_range':[0.0,0.1,0.2,0.3],'percent':True,'percentile_label':'bb_percent','flip_p':False,'percentile':False,'avg_adjust':False},
26
+ 'bb_minus_k':{'x_axis':'Plate Appearances','y_axis':'BB-K%','title':'BB-K%','x_value':'bb_minus_k','x_range':[-0.3,-0.2,-0.1,0,0.1,0.2],'percent':True,'percentile_label':'bb_minus_k_percent','flip_p':False,'percentile':False,'avg_adjust':False},
27
+ 'csw':{'x_axis':'Pitches','y_axis':'CSW%','title':'CSW%','x_value':'csw','x_range':[.2,.25,.3,.35,.4],'percent':True,'percentile_label':'csw_percent','flip_p':True,'percentile':False,'avg_adjust':False},
28
+ 'woba':{'x_axis':'wOBA PA','y_axis':'wOBA','title':'wOBA','x_value':'woba','x_range':[.20,.30,.40,.50],'percent':False,'percentile_label':'woba_percent','flip_p':False,'percentile':False,'avg_adjust':True},
29
+ 'launch_speed':{'x_axis':'Balls In Play','y_axis':'Exit Velocity','title':'Exit Velocity','x_value':'launch_speed','x_range':[85,90,95,100],'percent':False,'percentile_label':'launch_speed','flip_p':False,'percentile':False,'avg_adjust':False},
30
+ 'launch_speed_90':{'x_axis':'Balls In Play','y_axis':'90th Percentile Exit Velocity','title':'90th Percentile Exit Velocity','x_value':'launch_speed','x_range':[95,100,105,110,115],'percent':False,'percentile_label':'launch_speed_90','flip_p':False,'percentile':True,'avg_adjust':False},
31
+ 'hard_hit':{'x_axis':'Balls In Play','y_axis':'HardHit%','title':'HardHit%','x_value':'hard_hit','x_range':[0.2,0.3,0.4,0.5,0.6,0.7],'percent':True,'percentile_label':'hard_hit_percent','flip_p':False,'percentile':False,'avg_adjust':False},
32
+ 'sweet_spot':{'x_axis':'Balls In Play','y_axis':'SweetSpot%','title':'SweetSpot%','x_value':'sweet_spot','x_range':[0.2,0.3,0.4,0.5],'percent':True,'percentile_label':'sweet_spot_percent','flip_p':False,'percentile':False,'avg_adjust':False},
33
+ 'launch_angle':{'x_axis':'Balls In Play','y_axis':'Launch Angle','title':'Launch Angle','x_value':'launch_angle','x_range':[-20,-10,0,10,20],'percent':False,'percentile_label':'launch_angle','flip_p':False,'percentile':False,'avg_adjust':False},
34
+ 'barrel':{'x_axis':'Balls In Play','y_axis':'Barrel%','title':'Barrel%','x_value':'barrel','x_range':[0,0.05,0.10,.15,.20],'percent':True,'percentile_label':'barrel_percent','flip_p':False,'percentile':False,'avg_adjust':False},
35
+ 'zone_percent':{'x_axis':'Pitches','y_axis':'Zone%','title':'Zone%','x_value':'in_zone','x_range':[0.3,0.4,0.5,0.6,0.7],'percent':True,'percentile_label':'zone_percent','flip_p':False,'percentile':False,'avg_adjust':False},
36
+ 'swing_percent':{'x_axis':'Pitches','y_axis':'Swing%','title':'Swing%','x_value':'swings','x_range':[0.2,0.3,0.4,0.5,0.6,0.7,0.8],'percent':True,'percentile_label':'swing_percent','flip_p':False,'percentile':False,'avg_adjust':False},
37
+ 'whiff_percent':{'x_axis':'Swings','y_axis':'Whiff%','title':'Whiff%','x_value':'whiffs','x_range':[0.0,0.1,0.2,0.3,0.4,0.5],'percent':True,'percentile_label':'whiff_rate','flip_p':True,'percentile':False,'avg_adjust':False},
38
+ 'sw_str':{'x_axis':'Pitches','y_axis':'SwStr%','title':'SwStr%','x_value':'whiffs','x_range':[0.0,0.05,0.1,0.15,0.2,0.25],'percent':True,'percentile_label':'swstr_rate','flip_p':True,'percentile':False,'avg_adjust':False},
39
+ 'zone_swing':{'x_axis':'In-Zone Pitches','y_axis':'Z-Swing%','title':'Z-Swing%','x_value':'zone_swing','x_range':[0.3,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1],'percent':True,'percentile_label':'zone_swing_percent','flip_p':False,'percentile':False,'avg_adjust':False},
40
+ 'zone_contact':{'x_axis':'In-Zone Swings','y_axis':'Z-Contact%','title':'Z-Contact%','x_value':'zone_contact','x_range':[0.5,0.6,0.7,0.8,0.9,1],'percent':True,'percentile_label':'zone_contact_percent','flip_p':False,'percentile':False,'avg_adjust':False},
41
+ 'chase_percent':{'x_axis':'Out-of-Zone Pitches','y_axis':'O-Swing%','title':'O-Swing%','x_value':'ozone_swing','x_range':[0.0,0.1,0.2,0.3,0.4,0.5],'percent':True,'percentile_label':'chase_percent','flip_p':True,'percentile':False,'avg_adjust':False},
42
+ 'chase_contact':{'x_axis':'Out-of-Zone Swings','y_axis':'O-Contact%','title':'O-Contact%','x_value':'ozone_contact','x_range':[0.2,0.3,0.4,0.5,0.6,0.7,0.8],'percent':True,'percentile_label':'chase_contact','flip_p':False,'percentile':False,'avg_adjust':False},}
43
+
44
+
45
+ level_dict = {'MLB':'MLB','AAA':'AAA','AA':'AA','A+':'A+','A':'A'}
46
+
47
+
48
+ woba_list = ['woba']
49
+ pa_list = ['k','bb','bb_minus_k']
50
+ balls_in_play_list = ['hard_hit','launch_speed','launch_speed_90','launch_angle','barrel','sweet_spot']
51
+ pitches_list = ['zone_percent','swing_percent','sw_str','csw']
52
+ swings_list = ['whiff_percent']
53
+ in_zone_pitches_list = ['zone_swing']
54
+ in_zone_swings_list = ['zone_contact']
55
+ out_zone_pitches_list = ['chase_percent']
56
+ out_zone_swings_list = ['chase_contact']
57
+
58
+ plot_dict_small = {
59
+ 'k':'K%',
60
+ 'bb':'BB%',
61
+ 'bb_minus_k':'BB-K%',
62
+ 'csw':'CSW%',
63
+ 'woba':'wOBA',
64
+ 'launch_speed':'Exit Velocity',
65
+ 'launch_speed_90':'90th Percentile Exit Velocity',
66
+ 'hard_hit':'HardHit%',
67
+ 'sweet_spot':'SweetSpot%',
68
+ 'launch_angle':'Launch Angle',
69
+ 'zone_percent':'Zone%',
70
+ 'barrel':'Barrel%',
71
+ 'swing_percent':'Swing%',
72
+ 'whiff_percent':'Whiff%',
73
+ 'sw_str':'SwStr%',
74
+ 'zone_swing':'Z-Swing%',
75
+ 'zone_contact':'Z-Contact%',
76
+ 'chase_percent':'O-Swing%',
77
+ 'chase_contact':'O-Contact%',}
78
+
79
+
80
+
81
+ def rolling_plot(df,df_summ,player_id,stat_id,batter_dict,window_select,level_id):
82
+ season_title = df['game_date'].str[0:4].values[0]
83
+ sns.set_theme(style="whitegrid", palette="pastel")
84
+ if player_id == "":
85
+ fig = plt.figure(figsize=(12, 12))
86
+ fig.text(s='Please Select a Pitcher',x=0.5,y=0.5)
87
+ return
88
+
89
+
90
+
91
+ swing_min = int(window_select)
92
+ fig, ax = plt.subplots(1, 1, figsize=(10, 10))
93
+
94
+ fig.set_facecolor('white')
95
+ #ax.set_facecolor('white')
96
+ #fig.patch.set_facecolor('lightblue')
97
+
98
+ print(stat_id)
99
+
100
+ if stat_id in pa_list:
101
+ print('we hAVE MADE IT TO THIS PART OF THE CODE')
102
+
103
+
104
+ if stat_id in pa_list:
105
+ elly_zone_df = df[(df.pa==1)&(df.batter_id == int(player_id))&(df.level==level_id)].sort_values('start_time')
106
+ divisor_x = 'pa'
107
+ print('this is short')
108
+ print(elly_zone_df)
109
+
110
+
111
+ if stat_id in balls_in_play_list:
112
+ elly_zone_df = df[(df.bip)&(df.batter_id == int(player_id))&(df.level==level_id)]
113
+ divisor_x = 'bip'
114
+ #print('this is short')
115
+
116
+ if stat_id in balls_in_play_list:
117
+ elly_zone_df = df[(df.bip)&(df.batter_id == int(player_id))&(df.level==level_id)]
118
+ divisor_x = 'bip'
119
+ print('this is short')
120
+
121
+ if stat_id in pitches_list:
122
+ elly_zone_df = df[(df.pitches == 1)&(df.batter_id == int(player_id))&(df.level==level_id)]
123
+ divisor_x = 'pitches'
124
+
125
+ if stat_id in swings_list:
126
+ elly_zone_df = df[(df.swings == 1)&(df.batter_id == int(player_id))&(df.level==level_id)]
127
+ divisor_x = 'swings'
128
+
129
+
130
+ if stat_id in in_zone_pitches_list:
131
+ elly_zone_df = df[(df.in_zone)&(df.batter_id == int(player_id))&(df.level==level_id)]
132
+ divisor_x = 'in_zone'
133
+
134
+
135
+ if stat_id in in_zone_swings_list:
136
+ elly_zone_df = df[(df.zone_swing)&(df.batter_id == int(player_id))&(df.level==level_id)]
137
+ divisor_x = 'zone_swing'
138
+
139
+
140
+ if stat_id in out_zone_pitches_list:
141
+ elly_zone_df = df[(df.in_zone == False)&(df.batter_id == int(player_id))&(df.level==level_id)]
142
+ divisor_x = 'out_zone'
143
+
144
+
145
+ if stat_id in out_zone_swings_list:
146
+ elly_zone_df = df[(df.ozone_swing)&(df.batter_id == int(player_id))&(df.level==level_id)]
147
+ divisor_x = 'ozone_swing'
148
+
149
+ if stat_id in woba_list:
150
+ elly_zone_df = df[(df.woba_codes==1)&(df.batter_id == int(player_id))&(df.level==level_id)]
151
+ divisor_x = 'woba_codes'
152
+
153
+ # penguins = sns.load_dataset("penguins")
154
+ # sns.histplot(data=penguins, x="flipper_length_mm")
155
+ # print('we made it here:')
156
+ # print(int(player_id))
157
+ # print(stat_id)
158
+ # print(level_id)
159
+ # print(df[(df.batter_id == int(player_id))&(df.level==level_id)])
160
+ # print(df.columns)
161
+ # print(elly_zone_df[plot_dict[stat_id]["x_value"]].sum())
162
+
163
+ df_summ_new = df_summ.copy()
164
+ df_summ_new = df_summ_new.set_index('batter_id','batter_name','level')
165
+ df_summ_new = df_summ_new[df_summ_new[divisor_x] >= int(window_select)]
166
+ df_summ_new = df_summ_new[df_summ_new.level==level_id]
167
+
168
+ df_summ_rank = df_summ_new.rank(method='max',ascending=False)
169
+ df_summ_rank.columns = df_summ_rank.columns+['_rank']
170
+
171
+ df_summ_rank_percent = df_summ_new.rank(pct=True)
172
+ df_summ_rank_percent.columns = df_summ_rank_percent.columns+['_percent']
173
+
174
+
175
+ df_summ_new = df_summ_new.reset_index()
176
+ df_summ_rank = df_summ_rank.reset_index()
177
+ df_summ_rank_percent = df_summ_rank_percent.reset_index()
178
+ print('Table columns:')
179
+
180
+ df_summ_new.batter_id = df_summ_new.batter_id.astype(int)
181
+ df_summ_rank.batter_id = df_summ_rank.batter_id.astype(int)
182
+ df_summ_rank_percent.batter_id = df_summ_rank_percent.batter_id.astype(int)
183
+
184
+ print('Table columns2:')
185
+ df_summ_new = df_summ_new.merge(df_summ_rank,left_on=['batter_id'],right_on=['batter_id'],how='left',suffixes=['','_rank'])
186
+
187
+ df_summ_new = df_summ_new.merge(df_summ_rank_percent,left_on=['batter_id'],right_on=['batter_id'],how='left',suffixes=['','_percent'])
188
+
189
+
190
+ print(df_summ_new)
191
+ print(df_summ_rank)
192
+ print(df_summ_rank_percent)
193
+
194
+
195
+
196
+
197
+ #sns.scatterplot(x=data_df.launch_speed_90,y=data_df.zone_contact,color=colour_palette[0],s=75,label=int(player_id))
198
+
199
+ df_summ_new_select = df_summ_new[df_summ_new.batter_id == int(player_id)].reset_index(drop=True)
200
+ print('whiffing')
201
+ print(df)
202
+ print('Player _df:')
203
+ print(df_summ_new_select)
204
+
205
+ if len(df_summ_new_select) < 1:
206
+ ax.text(x=0.5,y=0.5,s='Please Select Different Parameters to Produce a plot',fontsize=18,ha='center')
207
+ return
208
+
209
+ p = inflect.engine()
210
+
211
+ df_summ_new_select = df_summ_new_select.loc[:,~df_summ_new_select.columns.duplicated(keep='last')].copy()
212
+ print('Table for the player:')
213
+ print(list(df_summ_new_select.columns))
214
+ print(plot_dict[stat_id]["percentile_label"])
215
+ print(plot_dict[stat_id]["percentile_label"]+'_percent')
216
+ print(df_summ_new_select)
217
+ print(1*plot_dict[stat_id]["flip_p"])
218
+ print(round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))
219
+ print((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)
220
+
221
+ # print(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+'_percent'])
222
+
223
+ if plot_dict[stat_id]['percent']:
224
+ label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum():.1%}'
225
+ label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
226
+ #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'
227
+ ax.yaxis.set_major_formatter(mtick.PercentFormatter(1))
228
+
229
+ else:
230
+ label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum():.1f}'
231
+ label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1f} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
232
+ #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1f}'
233
+ #ax.yaxis.set_major_formatter(mtick.int)
234
+
235
+
236
+ if plot_dict[stat_id]['percentile']:
237
+ label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].quantile(0.9):.1f}'
238
+ label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].quantile(0.9):.1f} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
239
+ #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'
240
+ #ax.yaxis.set_major_formatter(mtick.int)
241
+
242
+ if plot_dict[stat_id]['avg_adjust']:
243
+ label_1=f'{level_id} Average {df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum():.3f}'
244
+ label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.3f} ({p.ordinal(abs(int((1*plot_dict[stat_id]["flip_p"]-round(df_summ_new_select[plot_dict[stat_id]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'
245
+ #label_2=f'{batter_dict[int(player_id)]} Average {elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'
246
+ #ax.yaxis.set_major_formatter(mtick.int)
247
+
248
+ print(plot_dict[stat_id]["x_value"])
249
+ print(divisor_x)
250
+
251
+ # df_summ_new = df_summ.copy()
252
+ # df_summ_new = df_summ_new[df_summ_new.balls_in_play >= int(window_select)]
253
+ # df_summ_new = df_summ_new[df_summ_new.level==level_id]
254
+
255
+
256
+ print('this is here:')
257
+ print(df_summ_new.head())
258
+ print(df_summ_new.columns)
259
+
260
+
261
+ if plot_dict[stat_id]["flip_p"] == False:
262
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[2],linestyle='dotted',alpha=0.5)
263
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[3],linestyle='dotted',alpha=0.5)
264
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[4],linestyle='dotted',alpha=0.5)
265
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[5],linestyle='dotted',alpha=0.5)
266
+
267
+
268
+ hard_hit_dates = [(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),
269
+ (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),
270
+ (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),
271
+ (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1)]
272
+ hard_hit_text = ['90th %','75th %','25th %','10th %']
273
+ for i, x in enumerate(hard_hit_dates):
274
+ text(min(window_select+window_select/100,+window_select+1), x ,hard_hit_text[i], rotation=0, ha='left',
275
+ bbox=dict(facecolor='white',alpha=0.5, edgecolor=colour_palette[2+i], pad=2))
276
+
277
+
278
+
279
+ if plot_dict[stat_id]["flip_p"] == True:
280
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[2],linestyle='dotted',alpha=0.5)
281
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[3],linestyle='dotted',alpha=0.5)
282
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[4],linestyle='dotted',alpha=0.5)
283
+ ax.hlines(y=(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[5],linestyle='dotted',alpha=0.5)
284
+
285
+ hard_hit_dates = [(df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.9),
286
+ (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.75),
287
+ (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.25),
288
+ (df_summ_new[plot_dict[stat_id]["percentile_label"]]).quantile(0.1)]
289
+ hard_hit_text = ['10th %','25th %','75th %','90th %']
290
+ for i, x in enumerate(hard_hit_dates):
291
+ text(min(window_select+window_select/100,window_select+window_select+3), x ,hard_hit_text[i], rotation=0, ha='left',
292
+ bbox=dict(facecolor='white',alpha=0.5, edgecolor=colour_palette[2+i], pad=2))
293
+
294
+
295
+
296
+
297
+
298
+
299
+ if plot_dict[stat_id]["percentile"] == False:
300
+ ax.hlines(y=df[df.level == level_id][plot_dict[stat_id]["x_value"]].sum()/df[df.level == level_id][divisor_x].sum(),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[1],linestyle='-.',label=label_1)
301
+
302
+ ax.hlines(y=elly_zone_df[plot_dict[stat_id]["x_value"]].sum()/elly_zone_df[divisor_x].sum(),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[0],linestyle='--',label=label_2)
303
+
304
+ sns.lineplot(x=range(1,len(elly_zone_df)+1),y=elly_zone_df[plot_dict[stat_id]["x_value"]].fillna(0).rolling(window=swing_min).sum()/swing_min,color=colour_palette[0],linewidth=3,ax=ax)
305
+
306
+
307
+
308
+ if plot_dict[stat_id]["percentile"] == True:
309
+
310
+ ax.hlines(y=df[df.level == level_id][plot_dict[stat_id]["x_value"]].quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[1],linestyle='-.',label=label_1)
311
+
312
+ ax.hlines(y=elly_zone_df[plot_dict[stat_id]["x_value"]].fillna(0).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[0],linestyle='--',label=label_2)
313
+
314
+ sns.lineplot(x=range(1,len(elly_zone_df)+1),y=elly_zone_df[plot_dict[stat_id]["x_value"]].fillna(0).rolling(window=swing_min).quantile(0.9),color=colour_palette[0],linewidth=3,ax=ax)
315
+
316
+
317
+ #ax.set_xlim(window_select,exit_velo_df_small.pitch.max())
318
+ #plt.yticks([0,0.2,0.4,0.6,0.8,1])
319
+ #ax.set_ylim(math.floor((min(df_summ.zone_contact)/5)*100)*5/100,1)
320
+ ax.set_xlim(math.floor(swing_min),len(elly_zone_df))
321
+ ax.set_title(f'{batter_dict[int(player_id)]} - {season_title} - {level_id} - {swing_min} {plot_dict[stat_id]["x_axis"]} Rolling {plot_dict[stat_id]["title"]}', fontsize=16,fontname='Century Gothic',)
322
+ #vals = ax.get_yticks()
323
+ ax.set_xlabel(plot_dict[stat_id]['x_axis'], fontsize=16,fontname='Century Gothic')
324
+ ax.set_ylabel(plot_dict[stat_id]['y_axis'], fontsize=16,fontname='Century Gothic')
325
+
326
+ #fig.axes[0].invert_yaxis()
327
+
328
+ #fig.subplots_adjust(wspace=.02, hspace=.02)
329
+ #ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))
330
+ ax.set_yticks(plot_dict[stat_id]["x_range"])
331
+ #fig.colorbar(plot_dist, ax=ax)
332
+ #fig.colorbar(plot_dist)
333
+ #fig.axes[0].invert_yaxis()
334
+ ax.legend(fontsize='16')
335
+ fig.text(x=0.03,y=0.02,s='By: @TJStats',fontname='Century Gothic')
336
+ fig.text(x=1-0.03,y=0.02,s='Data: MLB',ha='right',fontname='Century Gothic')
337
+ fig.tight_layout()
338
  return