nesticot commited on
Commit
0fb0e06
·
verified ·
1 Parent(s): fec355e

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +554 -0
  2. rolling_batter_functions.py +338 -0
app.py CHANGED
@@ -0,0 +1,554 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui
2
+ import datasets
3
+ from datasets import load_dataset
4
+ import pandas as pd
5
+ import numpy as np
6
+ import matplotlib.pyplot as plt
7
+ import seaborn as sns
8
+ import numpy as np
9
+ from scipy.stats import gaussian_kde
10
+ import matplotlib
11
+ from matplotlib.ticker import MaxNLocator
12
+ from matplotlib.gridspec import GridSpec
13
+ from scipy.stats import zscore
14
+ import math
15
+ import matplotlib
16
+ from adjustText import adjust_text
17
+ import matplotlib.ticker as mtick
18
+ from shinywidgets import output_widget, render_widget
19
+ import pandas as pd
20
+ #from configure import base_url
21
+ import shinyswatch
22
+ import inflect
23
+ from matplotlib.pyplot import text
24
+ import rolling_batter_functions as rbf
25
+
26
+ def percentile(n):
27
+ def percentile_(x):
28
+ return np.nanpercentile(x, n)
29
+ percentile_.__name__ = 'percentile_%s' % n
30
+ return percentile_
31
+
32
+ colour_palette = ['#FFB000','#648FFF','#785EF0',
33
+ '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
34
+
35
+
36
+
37
+ print('Starting Everything:')
38
+ # exit_velo_df = milb_a_ev_df.append([triple_a_ev_df,double_a_ev_df,a_high_a_ev_df,single_a_ev_df]).reset_index(drop=True)
39
+ # player_df_all = mlb_a_player_df.append([triple_a_player_df,double_a_player_df,a_high_a_player_df,single_a_player_df]).reset_index(drop=True)
40
+ # exit_velo_df = pd.read_csv('exit_velo_df_all.csv',index_col=[0])
41
+ # player_df_all = pd.read_csv('player_df_all.csv',index_col=[0])
42
+
43
+ # pa_df = pd.read_csv('pa_df_all.csv',index_col=[0])
44
+ # pa_df_full_na = pa_df.dropna()
45
+
46
+ ### Import Datasets
47
+ dataset = load_dataset('nesticot/mlb_data', data_files=['mlb_pitch_data_2024.csv',
48
+ ])
49
+
50
+
51
+
52
+ dataset_train = dataset['train']
53
+ exit_velo_df_mlb = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)
54
+ #print(df_2023)
55
+ exit_velo_df_mlb['level'] = 'MLB'
56
+
57
+
58
+
59
+ ### Import Datasets
60
+ dataset = load_dataset('nesticot/mlb_data', data_files=['aaa_pitch_data_2024.csv',
61
+ ])
62
+ dataset_train = dataset['train']
63
+ exit_velo_df_aaa = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)
64
+ #print(df_2023)
65
+ exit_velo_df_aaa['level'] = 'AAA'
66
+
67
+ # ### Import Datasets
68
+ # dataset = load_dataset('nesticot/mlb_data', data_files=['aa_pitch_data_2023.csv',
69
+ # ])
70
+ # dataset_train = dataset['train']
71
+ # exit_velo_df_aa = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)
72
+ # #print(df_2023)
73
+ # exit_velo_df_aa['level'] = 'AA'
74
+
75
+ # ### Import Datasets
76
+ # dataset = load_dataset('nesticot/mlb_data', data_files=['high_a_pitch_data_2023.csv',
77
+ # ])
78
+ # dataset_train = dataset['train']
79
+ # exit_velo_df_ha = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)
80
+ # #print(df_2023)
81
+ # exit_velo_df_ha['level'] = 'A+'
82
+
83
+ # ### Import Datasets
84
+ # dataset = load_dataset('nesticot/mlb_data', data_files=['a_pitch_data_2023.csv',
85
+ # ])
86
+ # dataset_train = dataset['train']
87
+ # exit_velo_df_a = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)
88
+ # #print(df_2023)
89
+ # exit_velo_df_a['level'] = 'A'
90
+
91
+ # exit_velo_df = pd.concat([exit_velo_df_mlb,exit_velo_df_aaa,exit_velo_df_aa,exit_velo_df_ha,exit_velo_df_a])
92
+ exit_velo_df = pd.concat([exit_velo_df_mlb,exit_velo_df_aaa])
93
+ # exit_velo_df_copy = exit_velo_df.copy()
94
+
95
+ # exit_velo_df = exit_velo_df_copy.copy()
96
+
97
+ end_codes = ['strikeout', 'field_out', 'single', 'walk', 'hit_by_pitch',
98
+ 'double', 'sac_fly', 'force_out', 'home_run',
99
+ 'grounded_into_double_play', 'fielders_choice', 'field_error',
100
+ 'triple', 'sac_bunt', 'double_play', 'intent_walk',
101
+ 'fielders_choice_out', 'strikeout_double_play',
102
+ 'sac_fly_double_play', 'catcher_interf', 'other_out']
103
+
104
+
105
+
106
+ exit_velo_df['pa'] = exit_velo_df.event_type.isin(end_codes)
107
+ #exit_velo_df['pa'] = 1
108
+ exit_velo_df['k'] = exit_velo_df.event_type.isin(list(filter(None, [x if 'strikeout' in x else '' for x in exit_velo_df.event_type.fillna('None').unique()])))
109
+ exit_velo_df['bb'] = exit_velo_df.event_type.isin(list(filter(None, [x if 'walk' in x else '' for x in exit_velo_df.event_type.fillna('None').unique()])))
110
+
111
+ #exit_velo_df['k_minus_bb'] = exit_velo_df['k'].astype(np.float32)-exit_velo_df['bb'].astype(np.float32)
112
+ exit_velo_df['bb_minus_k'] = exit_velo_df['bb'].astype(np.float32)-exit_velo_df['k'].astype(np.float32)
113
+
114
+
115
+
116
+ exit_velo_df = exit_velo_df.drop_duplicates(subset=['play_id'])
117
+
118
+
119
+
120
+ swing_codes = ['Swinging Strike', 'In play, no out',
121
+ 'Foul', 'In play, out(s)',
122
+ 'In play, run(s)', 'Swinging Strike (Blocked)',
123
+ 'Foul Bunt','Foul Tip', 'Missed Bunt','Foul Pitchout','Swinging Pitchout']
124
+
125
+ swings_in = ['Swinging Strike', 'In play, no out',
126
+ 'Foul', 'In play, out(s)',
127
+ 'In play, run(s)', 'Swinging Strike (Blocked)',
128
+ 'Foul Bunt','Foul Tip', 'Missed Bunt','Foul Pitchout','Swinging Pitchout']
129
+
130
+ swing_strike_codes = ['Swinging Strike',
131
+ 'Swinging Strike (Blocked)','Missed Bunt','Foul Tip','Swinging Pitchout']
132
+
133
+
134
+ contact_codes = ['In play, no out',
135
+ 'Foul', 'In play, out(s)',
136
+ 'In play, run(s)',
137
+ 'Foul Bunt']
138
+
139
+ codes_in = ['In play, out(s)',
140
+ 'Swinging Strike',
141
+ 'Ball',
142
+ 'Foul',
143
+ 'In play, no out',
144
+ 'Called Strike',
145
+ 'Foul Tip',
146
+ 'In play, run(s)',
147
+ 'Hit By Pitch',
148
+ 'Ball In Dirt',
149
+ 'Pitchout',
150
+ 'Swinging Strike (Blocked)',
151
+ 'Foul Bunt',
152
+ 'Missed Bunt',
153
+ 'Foul Pitchout',
154
+ 'Intent Ball',
155
+ 'Swinging Pitchout']
156
+
157
+ exit_velo_df['in_zone'] = exit_velo_df['zone'] < 10
158
+
159
+
160
+ exit_velo_df = exit_velo_df.drop_duplicates(subset=['play_id'])
161
+
162
+ exit_velo_df_codes = exit_velo_df[exit_velo_df.play_description.isin(codes_in)].dropna(subset=['in_zone'])
163
+
164
+ exit_velo_df_codes['bip'] = ~exit_velo_df_codes.launch_speed.isna()
165
+ conditions = [
166
+ (exit_velo_df_codes['launch_speed'].isna()),
167
+ (exit_velo_df_codes['launch_speed']*1.5 - exit_velo_df_codes['launch_angle'] >= 117 ) & (exit_velo_df_codes['launch_speed'] + exit_velo_df_codes['launch_angle'] >= 124) & (exit_velo_df_codes['launch_speed'] > 98) & (exit_velo_df_codes['launch_angle'] >= 8) & (exit_velo_df_codes['launch_angle'] <= 50)
168
+ ]
169
+
170
+ choices = [False,True]
171
+ exit_velo_df_codes['barrel'] = np.select(conditions, choices, default=np.nan)
172
+
173
+ conditions_ss = [
174
+ (exit_velo_df_codes['launch_angle'].isna()),
175
+ (exit_velo_df_codes['launch_angle'] >= 8 ) * (exit_velo_df_codes['launch_angle'] <= 32 )
176
+ ]
177
+
178
+ choices_ss = [False,True]
179
+ exit_velo_df_codes['sweet_spot'] = np.select(conditions_ss, choices_ss, default=np.nan)
180
+
181
+
182
+ conditions_hh = [
183
+ (exit_velo_df_codes['launch_speed'].isna()),
184
+ (exit_velo_df_codes['launch_speed'] >= 94.5 )
185
+ ]
186
+
187
+ choices_hh = [False,True]
188
+ exit_velo_df_codes['hard_hit'] = np.select(conditions_hh, choices_hh, default=np.nan)
189
+
190
+
191
+ conditions_tb = [
192
+ (exit_velo_df_codes['event_type']=='single'),
193
+ (exit_velo_df_codes['event_type']=='double'),
194
+ (exit_velo_df_codes['event_type']=='triple'),
195
+ (exit_velo_df_codes['event_type']=='home_run'),
196
+ ]
197
+
198
+ choices_tb = [1,2,3,4]
199
+
200
+ exit_velo_df_codes['tb'] = np.select(conditions_tb, choices_tb, default=np.nan)
201
+
202
+ conditions_woba = [
203
+ (exit_velo_df_codes['event_type']=='walk'),
204
+ (exit_velo_df_codes['event_type']=='hit_by_pitch'),
205
+ (exit_velo_df_codes['event_type']=='single'),
206
+ (exit_velo_df_codes['event_type']=='double'),
207
+ (exit_velo_df_codes['event_type']=='triple'),
208
+ (exit_velo_df_codes['event_type']=='home_run'),
209
+ ]
210
+
211
+ choices_woba = [0.705,
212
+ 0.688,
213
+ 0.897,
214
+ 1.233,
215
+ 1.612,
216
+ 2.013]
217
+
218
+ exit_velo_df_codes['woba'] = np.select(conditions_woba, choices_woba, default=np.nan)
219
+
220
+
221
+ woba_codes = ['strikeout', 'field_out', 'single', 'walk', 'hit_by_pitch',
222
+ 'double', 'sac_fly', 'force_out', 'home_run',
223
+ 'grounded_into_double_play', 'fielders_choice', 'field_error',
224
+ 'triple', 'sac_bunt', 'double_play',
225
+ 'fielders_choice_out', 'strikeout_double_play',
226
+ 'sac_fly_double_play', 'other_out']
227
+
228
+
229
+
230
+
231
+
232
+ conditions_woba_code = [
233
+ (exit_velo_df_codes['event_type'].isin(woba_codes))
234
+ ]
235
+
236
+ choices_woba_code = [1]
237
+
238
+ exit_velo_df_codes['woba_codes'] = np.select(conditions_woba_code, choices_woba_code, default=np.nan)
239
+
240
+
241
+ #exit_velo_df_codes['barrel'] = (exit_velo_df_codes.launch_speed >= 98) & (exit_velo_df_codes.launch_angle >= (26 - (-98 + exit_velo_df_codes.launch_speed))) & (exit_velo_df_codes.launch_angle <= 30 + (-98 + exit_velo_df_codes.launch_speed)) & (exit_velo_df_codes.launch_angle >= 8) & (exit_velo_df_codes.launch_angle <= 50)
242
+
243
+
244
+
245
+
246
+
247
+ #exit_velo_df_codes['barrel'] = (exit_velo_df_codes.launch_speed >= 98) & (exit_velo_df_codes.launch_angle >= (26 - (-98 + exit_velo_df_codes.launch_speed))) & (exit_velo_df_codes.launch_angle <= 30 + (-98 + exit_velo_df_codes.launch_speed)) & (exit_velo_df_codes.launch_angle >= 8) & (exit_velo_df_codes.launch_angle <= 50)
248
+ exit_velo_df_codes['pitches'] = 1
249
+ exit_velo_df_codes['whiffs'] = [1 if ((x == 'S')|(x == 'W')|(x =='T')) else 0 for x in exit_velo_df_codes.play_code]
250
+ exit_velo_df_codes['csw'] = [1 if ((x == 'S')|(x == 'W')|(x =='T')|(x == 'C')) else 0 for x in exit_velo_df_codes.play_code]
251
+ exit_velo_df_codes['swings'] = [1 if x in swings_in else 0 for x in exit_velo_df_codes.play_description]
252
+
253
+ exit_velo_df_codes['out_zone'] = exit_velo_df_codes.in_zone == False
254
+ exit_velo_df_codes['zone_swing'] = (exit_velo_df_codes.in_zone == True)&(exit_velo_df_codes.swings == 1)
255
+ exit_velo_df_codes['zone_contact'] = (exit_velo_df_codes.in_zone == True)&(exit_velo_df_codes.swings == 1)&(exit_velo_df_codes.whiffs == 0)
256
+ exit_velo_df_codes['ozone_swing'] = (exit_velo_df_codes.in_zone==False)&(exit_velo_df_codes.swings == 1)
257
+ exit_velo_df_codes['ozone_contact'] = (exit_velo_df_codes.in_zone==False)&(exit_velo_df_codes.swings == 1)&(exit_velo_df_codes.whiffs == 0)
258
+
259
+
260
+
261
+ exit_velo_df_codes_summ = exit_velo_df_codes.groupby(['batter_id','batter_name','level']).agg(
262
+ pa = ('pa','sum'),
263
+ k = ('k','sum'),
264
+ bb = ('bb','sum'),
265
+ bb_minus_k = ('bb_minus_k','sum'),
266
+ csw = ('csw','sum'),
267
+ bip = ('bip','sum'),
268
+ tb = ('tb','sum'),
269
+ woba = ('woba','sum'),
270
+ woba_codes = ('woba_codes','sum'),
271
+ hard_hit = ('hard_hit','sum'),
272
+ barrel = ('barrel','sum'),
273
+ sweet_spot = ('sweet_spot','sum'),
274
+ max_launch_speed = ('launch_speed','max'),
275
+ launch_speed_90 = ('launch_speed',percentile(90)),
276
+ launch_speed = ('launch_speed','mean'),
277
+ launch_angle = ('launch_angle','mean'),
278
+ pitches = ('pitches','sum'),
279
+ swings = ('swings','sum'),
280
+ in_zone = ('in_zone','sum'),
281
+ out_zone = ('out_zone','sum'),
282
+ whiffs = ('whiffs','sum'),
283
+ zone_swing = ('zone_swing','sum'),
284
+ zone_contact = ('zone_contact','sum'),
285
+ ozone_swing = ('ozone_swing','sum'),
286
+ ozone_contact = ('ozone_contact','sum'),
287
+ ).reset_index()
288
+
289
+ #exit_velo_df_codes_summ['out_zone'] = ~exit_velo_df_codes_summ.in_zone
290
+ #bip_min_input = int(input())
291
+ #bip_min = min(bip_min_input,50)
292
+ #exit_velo_df_codes_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ.balls_in_play>=bip_min]
293
+
294
+
295
+ exit_velo_df_codes_summ['k_percent'] = [exit_velo_df_codes_summ.k[x]/exit_velo_df_codes_summ.pa[x] if exit_velo_df_codes_summ.pa[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
296
+ exit_velo_df_codes_summ['bb_percent'] =[exit_velo_df_codes_summ.bb[x]/exit_velo_df_codes_summ.pa[x] if exit_velo_df_codes_summ.pa[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
297
+ exit_velo_df_codes_summ['bb_minus_k_percent'] =[exit_velo_df_codes_summ.bb_minus_k[x]/exit_velo_df_codes_summ.pa[x] if exit_velo_df_codes_summ.pa[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
298
+
299
+ exit_velo_df_codes_summ['csw_percent'] =[exit_velo_df_codes_summ.csw[x]/exit_velo_df_codes_summ.pitches[x] if exit_velo_df_codes_summ.pitches[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
300
+
301
+
302
+ exit_velo_df_codes_summ['sweet_spot_percent'] = [exit_velo_df_codes_summ.sweet_spot[x]/exit_velo_df_codes_summ.bip[x] if exit_velo_df_codes_summ.bip[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
303
+
304
+ exit_velo_df_codes_summ['woba_percent'] = [exit_velo_df_codes_summ.woba[x]/exit_velo_df_codes_summ.woba_codes[x] if exit_velo_df_codes_summ.woba_codes[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
305
+ #exit_velo_df_codes_summ['hard_hit_percent'] = [exit_velo_df_codes_summ.sweet_spot[x]/exit_velo_df_codes_summ.bip[x] if exit_velo_df_codes_summ.bip[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
306
+ exit_velo_df_codes_summ['hard_hit_percent'] = [exit_velo_df_codes_summ.hard_hit[x]/exit_velo_df_codes_summ.bip[x] if exit_velo_df_codes_summ.bip[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
307
+
308
+
309
+ exit_velo_df_codes_summ['barrel_percent'] = [exit_velo_df_codes_summ.barrel[x]/exit_velo_df_codes_summ.bip[x] if exit_velo_df_codes_summ.bip[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
310
+
311
+ exit_velo_df_codes_summ['zone_contact_percent'] = [exit_velo_df_codes_summ.zone_contact[x]/exit_velo_df_codes_summ.zone_swing[x] if exit_velo_df_codes_summ.zone_swing[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
312
+
313
+ exit_velo_df_codes_summ['zone_swing_percent'] = [exit_velo_df_codes_summ.zone_swing[x]/exit_velo_df_codes_summ.in_zone[x] if exit_velo_df_codes_summ.pitches[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
314
+
315
+ exit_velo_df_codes_summ['zone_percent'] = [exit_velo_df_codes_summ.in_zone[x]/exit_velo_df_codes_summ.pitches[x] if exit_velo_df_codes_summ.pitches[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
316
+
317
+ exit_velo_df_codes_summ['chase_percent'] = [exit_velo_df_codes_summ.ozone_swing[x]/(exit_velo_df_codes_summ.pitches[x] - exit_velo_df_codes_summ.in_zone[x]) if (exit_velo_df_codes_summ.pitches[x]- exit_velo_df_codes_summ.in_zone[x]) != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
318
+
319
+ exit_velo_df_codes_summ['chase_contact'] = [exit_velo_df_codes_summ.ozone_contact[x]/exit_velo_df_codes_summ.ozone_swing[x] if exit_velo_df_codes_summ.ozone_swing[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
320
+
321
+ exit_velo_df_codes_summ['swing_percent'] = [exit_velo_df_codes_summ.swings[x]/exit_velo_df_codes_summ.pitches[x] if exit_velo_df_codes_summ.pitches[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
322
+
323
+ exit_velo_df_codes_summ['whiff_rate'] = [exit_velo_df_codes_summ.whiffs[x]/exit_velo_df_codes_summ.swings[x] if exit_velo_df_codes_summ.swings[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
324
+
325
+ exit_velo_df_codes_summ['swstr_rate'] = [exit_velo_df_codes_summ.whiffs[x]/exit_velo_df_codes_summ.pitches[x] if exit_velo_df_codes_summ.pitches[x] != 0 else np.nan for x in range(len(exit_velo_df_codes_summ))]
326
+
327
+ exit_velo_df_codes_summ = exit_velo_df_codes_summ.dropna(subset=['bip'])
328
+
329
+ woba_list = ['woba']
330
+ pa_list = ['k','bb','bb_minus_k']
331
+ balls_in_play_list = ['hard_hit','launch_speed','launch_speed_90','launch_angle','barrel','sweet_spot']
332
+ pitches_list = ['zone_percent','swing_percent','sw_str','csw']
333
+ swings_list = ['whiff_percent']
334
+ in_zone_pitches_list = ['zone_swing']
335
+ in_zone_swings_list = ['zone_contact']
336
+ out_zone_pitches_list = ['chase_percent']
337
+ out_zone_swings_list = ['chase_contact']
338
+
339
+ plot_dict = {
340
+ '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},
341
+ '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},
342
+ '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},
343
+ '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},
344
+ '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},
345
+ '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},
346
+ '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},
347
+ '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},
348
+ '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},
349
+ '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},
350
+ '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},
351
+ '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},
352
+ '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},
353
+ '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},
354
+ '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},
355
+ '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},
356
+ '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},
357
+ '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},
358
+ '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},}
359
+
360
+
361
+
362
+
363
+ # test_df = exit_velo_df.sort_values(by='batter_name').drop_duplicates(subset='batter_id').reset_index(drop=True)[['batter_id','batter_name']]#['pitcher'].to_dict()
364
+ # test_df = test_df.dropna()
365
+ # test_df['batter_id'] = test_df['batter_id'].astype(int)
366
+ # test_df = test_df.set_index('batter_id')
367
+ # #test_df = test_df[test_df.pitcher == 'Chris Bassitt'].append(test_df[test_df.pitcher != 'Chris Bassitt'])
368
+
369
+ batter_dict_mlb = exit_velo_df_mlb.set_index('batter_id')['batter_name'].to_dict()
370
+ batter_dict_aaa = exit_velo_df_aaa.set_index('batter_id')['batter_name'].to_dict()
371
+
372
+ level_dict = {'MLB':'MLB','AAA':'AAA','AA':'AA','A+':'A+','A':'A'}
373
+
374
+ plot_dict_small = {
375
+ 'k':'K%',
376
+ 'bb':'BB%',
377
+ 'bb_minus_k':'BB-K%',
378
+ 'csw':'CSW%',
379
+ 'woba':'wOBA',
380
+ 'launch_speed':'Exit Velocity',
381
+ 'launch_speed_90':'90th Percentile Exit Velocity',
382
+ 'hard_hit':'HardHit%',
383
+ 'sweet_spot':'SweetSpot%',
384
+ 'launch_angle':'Launch Angle',
385
+ 'zone_percent':'Zone%',
386
+ 'barrel':'Barrel%',
387
+ 'swing_percent':'Swing%',
388
+ 'whiff_percent':'Whiff%',
389
+ 'sw_str':'SwStr%',
390
+ 'zone_swing':'Z-Swing%',
391
+ 'zone_contact':'Z-Contact%',
392
+ 'chase_percent':'O-Swing%',
393
+ 'chase_contact':'O-Contact%',}
394
+
395
+
396
+ def server(input,output,session):
397
+
398
+ @render.ui
399
+ def test():
400
+
401
+ # @reactive.Effect
402
+ if input.my_tabs() == 'MLB':
403
+
404
+ #test_df = test_df[test_df.pitcher == 'Chris Bassitt'].append(test_df[test_df.pitcher != 'Chris Bassitt'])
405
+ batter_dict = exit_velo_df_mlb.set_index('batter_id')['batter_name'].to_dict()
406
+ return ui.input_select("id", "Select Player",batter_dict,selectize=True)
407
+
408
+
409
+ if input.my_tabs() == 'AAA':
410
+ #test_df = test_df[test_df.pitcher == 'Chris Bassitt'].append(test_df[test_df.pitcher != 'Chris Bassitt'])
411
+ batter_dict = exit_velo_df_aaa.set_index('batter_id')['batter_name'].to_dict()
412
+ return ui.input_select("id", "Select Player",batter_dict,selectize=True)
413
+
414
+
415
+ @output
416
+ @render.plot(alt="A histogram")
417
+ @reactive.event(input.go, ignore_none=False)
418
+ def plot_mlb():
419
+
420
+
421
+ rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()],
422
+ df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()],
423
+ player_id = input.id(),
424
+ stat_id = input.stat_id(),
425
+ batter_dict = batter_dict_mlb,
426
+ window_select = input.n(),
427
+ level_id = input.my_tabs())
428
+
429
+
430
+ @output
431
+ @render.plot(alt="A histogram")
432
+ @reactive.event(input.go, ignore_none=False)
433
+ def plot_aaa():
434
+
435
+
436
+ rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()],
437
+ df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()],
438
+ player_id = input.id(),
439
+ stat_id = input.stat_id(),
440
+ batter_dict = batter_dict_aaa,
441
+ window_select = input.n(),
442
+ level_id = input.my_tabs())
443
+
444
+
445
+
446
+ app = App(ui.page_fluid(
447
+ # ui.tags.base(href=base_url),
448
+ ui.tags.div(
449
+ {"style": "width:90%;margin: 0 auto;max-width: 1600px;"},
450
+ ui.tags.style(
451
+ """
452
+ h4 {
453
+ margin-top: 1em;font-size:35px;
454
+ }
455
+ h2{
456
+ font-size:25px;
457
+ }
458
+ """
459
+ ),
460
+ shinyswatch.theme.simplex(),
461
+ ui.tags.h4("TJStats"),
462
+ ui.tags.i("Baseball Analytics and Visualizations"),
463
+ # ui.markdown("""<a href='https://www.patreon.com/tj_stats'>Support me on Patreon for Access to 2024 Apps</a><sup>1</sup>"""),
464
+
465
+ # ui.navset_tab(
466
+ # ui.nav_control(
467
+ # ui.a(
468
+ # "Home",
469
+ # href="https://nesticot-tjstats-site.hf.space/home/"
470
+ # ),
471
+ # ),
472
+ # ui.nav_menu(
473
+ # "Batter Charts",
474
+ # ui.nav_control(
475
+ # ui.a(
476
+ # "Batting Rolling",
477
+ # href="https://nesticot-tjstats-site-rolling-batter.hf.space/"
478
+ # ),
479
+ # ui.a(
480
+ # "Spray",
481
+ # href="https://nesticot-tjstats-site-spray.hf.space/"
482
+ # ),
483
+ # ui.a(
484
+ # "Decision Value",
485
+ # href="https://nesticot-tjstats-site-decision-value.hf.space/"
486
+ # ),
487
+ # ui.a(
488
+ # "Damage Model",
489
+ # href="https://nesticot-tjstats-site-damage.hf.space/"
490
+ # ),
491
+ # ui.a(
492
+ # "Batter Scatter",
493
+ # href="https://nesticot-tjstats-site-batter-scatter.hf.space/"
494
+ # ),
495
+ # ui.a(
496
+ # "EV vs LA Plot",
497
+ # href="https://nesticot-tjstats-site-ev-angle.hf.space/"
498
+ # ),
499
+ # ui.a(
500
+ # "Statcast Compare",
501
+ # href="https://nesticot-tjstats-site-statcast-compare.hf.space/"
502
+ # ),
503
+ # ui.a(
504
+ # "MLB/MiLB Cards",
505
+ # href="https://nesticot-tjstats-site-mlb-cards.hf.space/"
506
+ # )
507
+ # ),
508
+ # ),
509
+ # ui.nav_menu(
510
+ # "Pitcher Charts",
511
+ # ui.nav_control(
512
+ # ui.a(
513
+ # "Pitcher Rolling",
514
+ # href="https://nesticot-tjstats-site-rolling-pitcher.hf.space/"
515
+ # ),
516
+ # ui.a(
517
+ # "Pitcher Summary",
518
+ # href="https://nesticot-tjstats-site-pitching-summary-graphic-new.hf.space/"
519
+ # ),
520
+ # ui.a(
521
+ # "Pitcher Scatter",
522
+ # href="https://nesticot-tjstats-site-pitcher-scatter.hf.space"
523
+ # )
524
+ # ),
525
+ # )),
526
+ ui.row(
527
+ ui.layout_sidebar(
528
+
529
+ ui.panel_sidebar(
530
+ ui.output_ui('test','Select Player'),
531
+ #ui.input_select("id", "Select Pitcher",batter_dict,selected=675911,width=1,size=1,selectize=True),
532
+ #ui.input_select("level_id", "Select Level",level_dict,width=1,size=1),
533
+ ui.input_select("stat_id", "Select Stat",plot_dict_small,width=1,size=1),
534
+ ui.input_numeric("n", "Rolling Window Size", value=50),
535
+ ui.input_action_button("go", "Generate",class_="btn-primary"),
536
+ ui.output_table("result")
537
+ ),
538
+
539
+ ui.panel_main(
540
+ ui.navset_tab(
541
+ # ui.nav("Raw Data",
542
+ # ui.output_data_frame("raw_table")),
543
+ # ui.nav("Season Summary",
544
+ # ui.output_plot('plot',
545
+ # width='2000px',
546
+ # height='2000px')),
547
+ ui.nav("MLB",
548
+ ui.output_plot("plot_mlb",height = "1000px",width="1000px")),
549
+ ui.nav("AAA",
550
+ ui.output_plot("plot_aaa",height = "1000px",width="1000px"))
551
+
552
+
553
+
554
+ ,id="my_tabs")))))),server)
rolling_batter_functions.py ADDED
@@ -0,0 +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