CoolFace
Apppublic

TJStatsApps/2025_decision_value

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
rolling_pitcher.py719 linesDownload Raw Back to root
1from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui2import datasets3from datasets import load_dataset4import pandas as pd5import numpy as np6import matplotlib.pyplot as plt7import seaborn as sns8import numpy as np9from scipy.stats import gaussian_kde10import matplotlib11from matplotlib.ticker import MaxNLocator12from matplotlib.gridspec import GridSpec13from scipy.stats import zscore14import math15import matplotlib16from adjustText import adjust_text17import matplotlib.ticker as mtick18from shinywidgets import output_widget, render_widget19import pandas as pd20from configure import base_url21import shinyswatch22import inflect23from matplotlib.pyplot import text24 25def percentile(n):26    def percentile_(x):27        return np.nanpercentile(x, n)28    percentile_.__name__ = 'percentile_%s' % n29    return percentile_30 31colour_palette = ['#FFB000','#648FFF','#785EF0',32                  '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']33 34 35 36print('Starting Everything:')37# 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)38# 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)39# exit_velo_df = pd.read_csv('exit_velo_df_all.csv',index_col=[0])40# player_df_all = pd.read_csv('player_df_all.csv',index_col=[0])41 42# pa_df = pd.read_csv('pa_df_all.csv',index_col=[0])43# pa_df_full_na = pa_df.dropna()44 45### Import Datasets46dataset = load_dataset('nesticot/mlb_data', data_files=['mlb_pitch_data_2023.csv',47                                                         ])48dataset_train = dataset['train']49exit_velo_df_mlb = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)50#print(df_2023)51exit_velo_df_mlb['level'] = 'MLB'52 53### Import Datasets54dataset = load_dataset('nesticot/mlb_data', data_files=['aaa_pitch_data_2023.csv',55                                                         ])56dataset_train = dataset['train']57exit_velo_df_aaa = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)58#print(df_2023)59exit_velo_df_aaa['level'] = 'AAA'60 61### Import Datasets62dataset = load_dataset('nesticot/mlb_data', data_files=['aa_pitch_data_2023.csv',63                                                         ])64dataset_train = dataset['train']65exit_velo_df_aa = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)66#print(df_2023)67exit_velo_df_aa['level'] = 'AA'68 69### Import Datasets70dataset = load_dataset('nesticot/mlb_data', data_files=['high_a_pitch_data_2023.csv',71                                                         ])72dataset_train = dataset['train']73exit_velo_df_ha = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)74#print(df_2023)75exit_velo_df_ha['level'] = 'A+'76 77### Import Datasets78dataset = load_dataset('nesticot/mlb_data', data_files=['a_pitch_data_2023.csv',79                                                         ])80dataset_train = dataset['train']81exit_velo_df_a = dataset_train.to_pandas().set_index(list(dataset_train.features.keys())[0]).reset_index(drop=True)82#print(df_2023)83exit_velo_df_a['level'] = 'A'84 85exit_velo_df = pd.concat([exit_velo_df_mlb,exit_velo_df_aaa,exit_velo_df_aa,exit_velo_df_ha,exit_velo_df_a])86# exit_velo_df_copy = exit_velo_df.copy()87 88# exit_velo_df = exit_velo_df_copy.copy()89 90end_codes = ['strikeout', 'field_out', 'single', 'walk', 'hit_by_pitch',91       'double', 'sac_fly', 'force_out', 'home_run',92       'grounded_into_double_play', 'fielders_choice', 'field_error',93       'triple', 'sac_bunt', 'double_play', 'intent_walk',94       'fielders_choice_out', 'strikeout_double_play',95       'sac_fly_double_play', 'catcher_interf', 'other_out']96 97 98 99exit_velo_df['pa'] = exit_velo_df.event_type.isin(end_codes)100#exit_velo_df['pa'] = 1101exit_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()])))102exit_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()])))103exit_velo_df['k_minus_bb'] = exit_velo_df['k'].astype(np.float32)-exit_velo_df['bb'].astype(np.float32)104 105exit_velo_df = exit_velo_df.drop_duplicates(subset=['play_id'])106 107 108 109swing_codes = ['Swinging Strike', 'In play, no out', 110        'Foul', 'In play, out(s)', 111       'In play, run(s)', 'Swinging Strike (Blocked)',112       'Foul Bunt','Foul Tip', 'Missed Bunt','Foul Pitchout','Swinging Pitchout']113 114swings_in = ['Swinging Strike', 'In play, no out', 115        'Foul', 'In play, out(s)', 116       'In play, run(s)', 'Swinging Strike (Blocked)',117       'Foul Bunt','Foul Tip', 'Missed Bunt','Foul Pitchout','Swinging Pitchout']       118 119swing_strike_codes = ['Swinging Strike',120 'Swinging Strike (Blocked)','Missed Bunt','Foul Tip','Swinging Pitchout']121 122 123contact_codes = ['In play, no out', 124        'Foul', 'In play, out(s)', 125       'In play, run(s)', 126       'Foul Bunt']127 128codes_in = ['In play, out(s)',129'Swinging Strike',130'Ball',131'Foul',132'In play, no out',133'Called Strike',134'Foul Tip',135'In play, run(s)',136'Hit By Pitch',137'Ball In Dirt',138'Pitchout',139'Swinging Strike (Blocked)',140'Foul Bunt',141'Missed Bunt',142'Foul Pitchout',143'Intent Ball',144'Swinging Pitchout']145 146exit_velo_df['in_zone'] = exit_velo_df['zone'] < 10147 148 149exit_velo_df = exit_velo_df.drop_duplicates(subset=['play_id'])150 151exit_velo_df_codes = exit_velo_df[exit_velo_df.play_description.isin(codes_in)].dropna(subset=['in_zone'])152 153exit_velo_df_codes['bip'] = ~exit_velo_df_codes.launch_speed.isna()154conditions = [155    (exit_velo_df_codes['launch_speed'].isna()),156    (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)157]158 159choices = [False,True]160exit_velo_df_codes['barrel'] = np.select(conditions, choices, default=np.nan)161 162conditions_ss = [163    (exit_velo_df_codes['launch_angle'].isna()),164    (exit_velo_df_codes['launch_angle'] >= 8 ) * (exit_velo_df_codes['launch_angle'] <= 32 ) 165]166 167choices_ss = [False,True]168exit_velo_df_codes['sweet_spot'] = np.select(conditions_ss, choices_ss, default=np.nan)169conditions_hh = [170    (exit_velo_df_codes['launch_speed'].isna()),171    (exit_velo_df_codes['launch_speed'] >= 94.5 ) 172]173 174choices_hh = [False,True]175exit_velo_df_codes['hard_hit'] = np.select(conditions_hh, choices_hh, default=np.nan)176 177 178conditions_tb = [179    (exit_velo_df_codes['event_type']=='single'),180    (exit_velo_df_codes['event_type']=='double'),181    (exit_velo_df_codes['event_type']=='triple'),182    (exit_velo_df_codes['event_type']=='home_run'),183]184 185choices_tb = [1,2,3,4]186 187exit_velo_df_codes['tb'] = np.select(conditions_tb, choices_tb, default=np.nan)188 189conditions_woba = [190    (exit_velo_df_codes['event_type']=='walk'),191    (exit_velo_df_codes['event_type']=='hit_by_pitch'),    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 198choices_woba = [0.705,199                0.688,200                0.897,201                1.233,202                1.612,203                2.013]204 205exit_velo_df_codes['woba'] = np.select(conditions_woba, choices_woba, default=np.nan)206 207 208woba_codes = ['strikeout', 'field_out', 'single', 'walk', 'hit_by_pitch',209       'double', 'sac_fly', 'force_out', 'home_run',210       'grounded_into_double_play', 'fielders_choice', 'field_error',211       'triple', 'sac_bunt', 'double_play',212       'fielders_choice_out', 'strikeout_double_play',213       'sac_fly_double_play', 'other_out']214 215 216 217 218 219conditions_woba_code = [220    (exit_velo_df_codes['event_type'].isin(woba_codes))221]222 223choices_woba_code = [1]224 225exit_velo_df_codes['woba_codes'] = np.select(conditions_woba_code, choices_woba_code, default=np.nan)226 227 228#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)229 230 231 232#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)233exit_velo_df_codes['pitches'] = 1234exit_velo_df_codes['whiffs'] = [1 if ((x == 'S')|(x == 'W')|(x =='T')) else 0 for x in exit_velo_df_codes.play_code]235exit_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]236exit_velo_df_codes['swings'] = [1 if x in swings_in else 0 for x in exit_velo_df_codes.play_description]237 238exit_velo_df_codes['out_zone'] = exit_velo_df_codes.in_zone == False239exit_velo_df_codes['zone_swing'] = (exit_velo_df_codes.in_zone == True)&(exit_velo_df_codes.swings == 1)240exit_velo_df_codes['zone_contact'] = (exit_velo_df_codes.in_zone == True)&(exit_velo_df_codes.swings == 1)&(exit_velo_df_codes.whiffs == 0)241exit_velo_df_codes['ozone_swing'] = (exit_velo_df_codes.in_zone==False)&(exit_velo_df_codes.swings == 1)242exit_velo_df_codes['ozone_contact'] = (exit_velo_df_codes.in_zone==False)&(exit_velo_df_codes.swings == 1)&(exit_velo_df_codes.whiffs == 0)243 244exit_velo_df_codes_summ = exit_velo_df_codes.groupby(['pitcher_id','pitcher_name','level']).agg(245    pa = ('pa','sum'), 246    k = ('k','sum'), 247    bb = ('bb','sum'), 248    k_minus_bb = ('k_minus_bb','sum'), 249    csw = ('csw','sum'), 250    bip = ('bip','sum'), 251    tb = ('tb','sum'),252    woba = ('woba','sum'),253    woba_codes = ('woba_codes','sum'),254    hard_hit = ('hard_hit','sum'), 255    barrel = ('barrel','sum'), 256    sweet_spot = ('sweet_spot','sum'), 257    max_launch_speed = ('launch_speed','max'),258    launch_speed_90 =  ('launch_speed',percentile(90)),259    launch_speed = ('launch_speed','mean'),260    launch_angle = ('launch_angle','mean'),261    pitches = ('pitches','sum'),262    swings =  ('swings','sum'),263    in_zone = ('in_zone','sum'),264    out_zone = ('out_zone','sum'),265    whiffs = ('whiffs','sum'),266    zone_swing = ('zone_swing','sum'),267    zone_contact = ('zone_contact','sum'),268    ozone_swing = ('ozone_swing','sum'),269    ozone_contact = ('ozone_contact','sum'),270    ).reset_index()271 272 273 274exit_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))]275exit_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))]276exit_velo_df_codes_summ['k_minus_bb_percent'] =[exit_velo_df_codes_summ.k_minus_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))]277 278 279exit_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))]280 281exit_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))]282 283 284exit_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))]285 286 287 288exit_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))]289 290 291exit_velo_df_codes_summ['barrel_percent'] = exit_velo_df_codes_summ.barrel = [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))]292 293exit_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))]294 295exit_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))]296 297exit_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))]298 299exit_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))]300 301exit_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))]302 303exit_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))]304 305exit_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))]306 307exit_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))]308 309exit_velo_df_codes_summ = exit_velo_df_codes_summ.dropna(subset=['bip'])310 311print('whiffing')312print(exit_velo_df_codes_summ['whiff_rate'])313 314exit_velo_df_codes_summ.head()315 316woba_list = ['woba']317pa_list = ['k','bb','k_minus_bb','bb_minus_k']318balls_in_play_list = ['hard_hit','launch_speed','launch_speed_90','launch_angle','barrel','sweet_spot']319pitches_list = ['zone_percent','swing_percent','sw_str','csw']320swings_list = ['whiff_percent']321in_zone_pitches_list = ['zone_swing']322in_zone_swings_list = ['zone_contact']323out_zone_pitches_list = ['chase_percent']324out_zone_swings_list = ['chase_contact']325 326plot_dict = {327'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':False,'percentile':False},328'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':True,'percentile':False},329'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':False,'percentile':False},330'launch_speed':{'x_axis':'Balls In Play','y_axis':'Exit Velocity','title':'Exit Velocity','x_value':'launch_speed','x_range':[85,90,95,100,105],'percent':True,'percentile_label':'launch_speed','flip_p':True,'percentile':False},331'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':[90,95,100,105,110,115,120],'percent':False,'percentile_label':'launch_speed_90','flip_p':True,'percentile':True},              332'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,0.6],'percent':True,'percentile_label':'sweet_spot_percent','flip_p':True,'percentile':False},333'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':True,'percentile':False},334'barrel':{'x_axis':'Balls In Play','y_axis':'Barrel%','title':'Barrel%','x_value':'barrel','x_range':[0,0.05,0.10,.15,.20,.25,.30],'percent':True,'percentile_label':'barrel_percent','flip_p':False,'percentile':False},335'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':True,'percentile':False},336'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},337'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':False,'percentile':False},338'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':False,'percentile':False},339'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':True,'percentile':False},340'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':True,'percentile':False},341'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':False,'percentile':False},342'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':True,'percentile':False},}343 344test_df = exit_velo_df.sort_values(by='pitcher_name').drop_duplicates(subset='pitcher_id').reset_index(drop=True)[['pitcher_id','pitcher_name']]#['pitcher'].to_dict()345test_df = test_df.set_index('pitcher_id')346 347#test_df =  test_df[test_df.pitcher == 'Chris Bassitt'].append(test_df[test_df.pitcher != 'Chris Bassitt'])348 349batter_dict = test_df['pitcher_name'].to_dict()350 351level_dict = {'MLB':'MLB','AAA':'AAA','AA':'AA','A+':'A+','A':'A'}352 353plot_dict_small = {354'k':'K%',355'bb':'BB%',356'csw':'CSW%',357'launch_speed':'Exit Velocity',358'launch_speed_90':'90th Percentile Exit Velocity',359'sweet_spot':'SweetSpot%',360'launch_angle':'Launch Angle',361'zone_percent':'Zone%',362'barrel':'Barrel%',363'swing_percent':'Swing%',364'whiff_percent':'Whiff%',365'sw_str':'SwStr%',366'zone_swing':'Z-Swing%',367'zone_contact':'Z-Contact%',368'chase_percent':'O-Swing%',369'chase_contact':'O-Contact%',}370 371 372def server(input,output,session):373 374    @output375    @render.plot(alt="A histogram")376    @reactive.event(input.go, ignore_none=False)    377    def plot():378        # np.random.seed(19680801)379        # x = 100 + 15 * np.random.randn(437)380        # fig, ax = plt.subplots()381        # ax.hist(x, input.n(), density=True)382        # return fig383        sns.set_theme(style="whitegrid", palette="pastel")384        if input.id() is "":385            fig = plt.figure(figsize=(12, 12))386            fig.text(s='Please Select a Pitcher',x=0.5,y=0.5)387            return388        389        swing_min = int(input.n())390        fig, ax = plt.subplots(1, 1, figsize=(10, 10))391 392        fig.set_facecolor('white')393        #ax.set_facecolor('white')394        #fig.patch.set_facecolor('lightblue')395 396        print(input.stat_id())397 398        if input.stat_id() in pa_list:399            print('we hAVE MADE IT TO THIS PART OF THE CODE')400 401 402        if input.stat_id() in pa_list:403            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.pa==1)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]404            divisor_x = 'pa'405            print('this is short')406            print(elly_zone_df)407 408 409        if input.stat_id() in balls_in_play_list:410            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.bip)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]411            divisor_x = 'bip'412            #print('this is short')413 414        if input.stat_id() in balls_in_play_list:415            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.bip)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]416            divisor_x = 'bip'417            print('this is short')418 419        if input.stat_id() in pitches_list:420            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.pitches == 1)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]421            divisor_x = 'pitches'422 423        if input.stat_id() in swings_list:424            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.swings == 1)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]425            divisor_x = 'swings'426 427 428        if input.stat_id() in in_zone_pitches_list:429            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.in_zone)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]430            divisor_x = 'in_zone'431 432 433        if input.stat_id() in in_zone_swings_list:434            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.zone_swing)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]435            divisor_x = 'zone_swing'436 437 438        if input.stat_id() in out_zone_pitches_list:439            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.in_zone == False)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]440            divisor_x = 'out_zone'441 442 443        if input.stat_id() in out_zone_swings_list:444            elly_zone_df = exit_velo_df_codes[(exit_velo_df_codes.ozone_swing)&(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())]445            divisor_x = 'ozone_swing'446 447        # penguins = sns.load_dataset("penguins")448        # sns.histplot(data=penguins, x="flipper_length_mm")449        # print('we made it here:')450        # print(int(input.id()))451        # print(input.stat_id())452        # print(input.level_id())453        # print(exit_velo_df_codes[(exit_velo_df_codes.pitcher_id == int(input.id()))&(exit_velo_df_codes.level==input.level_id())])454        # print(exit_velo_df_codes.columns)455        # print(elly_zone_df[plot_dict[input.stat_id()]["x_value"]].sum())456 457        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ.copy()458        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new.set_index('pitcher_id','pitcher','level')459        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new[exit_velo_df_codes_summ_new[divisor_x] >= int(input.n())]460        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new[exit_velo_df_codes_summ_new.level==input.level_id()]461 462        exit_velo_df_codes_summ_rank = exit_velo_df_codes_summ_new.rank(method='max',ascending=False)463        exit_velo_df_codes_summ_rank.columns = exit_velo_df_codes_summ_rank.columns+['_rank']464 465        exit_velo_df_codes_summ_rank_percent =  exit_velo_df_codes_summ_new.rank(pct=True)466        exit_velo_df_codes_summ_rank_percent.columns = exit_velo_df_codes_summ_rank_percent.columns+['_percent']467        468 469        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new.reset_index()470        exit_velo_df_codes_summ_rank = exit_velo_df_codes_summ_rank.reset_index()471        exit_velo_df_codes_summ_rank_percent = exit_velo_df_codes_summ_rank_percent.reset_index()472        print('Table columns:')473        474        exit_velo_df_codes_summ_new.pitcher_id = exit_velo_df_codes_summ_new.pitcher_id.astype(int)475        exit_velo_df_codes_summ_rank.pitcher_id = exit_velo_df_codes_summ_rank.pitcher_id.astype(int)476        exit_velo_df_codes_summ_rank_percent.pitcher_id = exit_velo_df_codes_summ_rank_percent.pitcher_id.astype(int)477 478        print('Table columns2:')479        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new.merge(exit_velo_df_codes_summ_rank,left_on=['pitcher_id'],right_on=['pitcher_id'],how='left',suffixes=['','_rank'])480 481        exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new.merge(exit_velo_df_codes_summ_rank_percent,left_on=['pitcher_id'],right_on=['pitcher_id'],how='left',suffixes=['','_percent'])482 483 484        print(exit_velo_df_codes_summ_new)485        print(exit_velo_df_codes_summ_rank)486        print(exit_velo_df_codes_summ_rank_percent)487        488 489        490 491        #sns.scatterplot(x=data_df.launch_speed_90,y=data_df.zone_contact,color=colour_palette[0],s=75,label=int(input.id()))492 493        exit_velo_df_codes_summ_new_select = exit_velo_df_codes_summ_new[exit_velo_df_codes_summ_new.pitcher_id == int(input.id())].reset_index(drop=True)494        print('whiffing')495        print(exit_velo_df_codes)496        print('Player _df:')497        print(exit_velo_df_codes_summ_new_select)498 499        if len(exit_velo_df_codes_summ_new_select) < 1:500            ax.text(x=0.5,y=0.5,s='Please Select Different Parameters to Produce a plot',fontsize=18,ha='center')501            return 502 503        p = inflect.engine()504 505        exit_velo_df_codes_summ_new_select = exit_velo_df_codes_summ_new_select.loc[:,~exit_velo_df_codes_summ_new_select.columns.duplicated(keep='last')].copy()506        print('Table for the player:')507        print(list(exit_velo_df_codes_summ_new_select.columns))508        print(plot_dict[input.stat_id()]["percentile_label"])509        print(plot_dict[input.stat_id()]["percentile_label"]+'_percent')510        print(exit_velo_df_codes_summ_new_select)511        print(1*plot_dict[input.stat_id()]["flip_p"])512        print(round(exit_velo_df_codes_summ_new_select[plot_dict[input.stat_id()]["percentile_label"]+"_percent"][0],2))513        print((1*plot_dict[input.stat_id()]["flip_p"]-round(exit_velo_df_codes_summ_new_select[plot_dict[input.stat_id()]["percentile_label"]+"_percent"][0],2))*100)514 515        # print(exit_velo_df_codes_summ_new_select[plot_dict[input.stat_id()]["percentile_label"]+'_percent'])516 517        if plot_dict[input.stat_id()]['percent']:518            label_1=f'{input.level_id()} Average {exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][plot_dict[input.stat_id()]["x_value"]].sum()/exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][divisor_x].sum():.1%}'519            label_2=f'{batter_dict[int(input.id())]} Average {elly_zone_df[plot_dict[input.stat_id()]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%} ({p.ordinal(abs(int((1*plot_dict[input.stat_id()]["flip_p"]-round(exit_velo_df_codes_summ_new_select[plot_dict[input.stat_id()]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'520            #label_2=f'{batter_dict[int(input.id())]} Average {elly_zone_df[plot_dict[input.stat_id()]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'521            ax.yaxis.set_major_formatter(mtick.PercentFormatter(1))522 523        else:524            label_1=f'{input.level_id()} Average {exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][plot_dict[input.stat_id()]["x_value"]].sum()/exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][divisor_x].sum():.1f}'525            label_2=f'{batter_dict[int(input.id())]} Average {elly_zone_df[plot_dict[input.stat_id()]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1f} ({p.ordinal(abs(int((1*plot_dict[input.stat_id()]["flip_p"]-round(exit_velo_df_codes_summ_new_select[plot_dict[input.stat_id()]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'526            #label_2=f'{batter_dict[int(input.id())]} Average {elly_zone_df[plot_dict[input.stat_id()]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1f}'527            #ax.yaxis.set_major_formatter(mtick.int)528        529 530        if plot_dict[input.stat_id()]['percentile']:531            label_1=f'{input.level_id()} Average {exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][plot_dict[input.stat_id()]["x_value"]].quantile(0.9):.1f}'532            label_2=f'{batter_dict[int(input.id())]} Average {elly_zone_df[plot_dict[input.stat_id()]["x_value"]].quantile(0.9):.1f} ({p.ordinal(abs(int((1*plot_dict[input.stat_id()]["flip_p"]-round(exit_velo_df_codes_summ_new_select[plot_dict[input.stat_id()]["percentile_label"]+"_percent"][0],2))*100)))} Percentile)'533            #label_2=f'{batter_dict[int(input.id())]} Average {elly_zone_df[plot_dict[input.stat_id()]["x_value"]].sum()/elly_zone_df[divisor_x].sum():.1%}'534            #ax.yaxis.set_major_formatter(mtick.int)535 536 537        print(plot_dict[input.stat_id()]["x_value"])538        print(divisor_x)539 540        # exit_velo_df_codes_summ_new = exit_velo_df_codes_summ.copy()541        # exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new[exit_velo_df_codes_summ_new.balls_in_play >= int(input.n())]542        # exit_velo_df_codes_summ_new = exit_velo_df_codes_summ_new[exit_velo_df_codes_summ_new.level==input.level_id()]543 544        545        print('this is here:')546        print(exit_velo_df_codes_summ_new.head())547        print(exit_velo_df_codes_summ_new.columns)548 549 550        if plot_dict[input.stat_id()]["flip_p"] == False:551            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[2],linestyle='dotted',alpha=0.5)552            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.75),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[3],linestyle='dotted',alpha=0.5)553            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.25),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[4],linestyle='dotted',alpha=0.5)554            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.1),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[5],linestyle='dotted',alpha=0.5)555 556 557            hard_hit_dates = [(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.9),558                              (exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.75),559                              (exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.25),560                              (exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.1)]561            hard_hit_text = ['90th %','75th %','25th %','10th %']562            for i, x in enumerate(hard_hit_dates):563                text(min(input.n()+input.n()/100,+input.n()+1), x ,hard_hit_text[i], rotation=0, ha='left',564                    bbox=dict(facecolor='white',alpha=0.5, edgecolor=colour_palette[2+i], pad=2))565 566 567 568        if plot_dict[input.stat_id()]["flip_p"] == True:569            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.1),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[2],linestyle='dotted',alpha=0.5)570            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.25),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[3],linestyle='dotted',alpha=0.5)571            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.75),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[4],linestyle='dotted',alpha=0.5)572            ax.hlines(y=(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[5],linestyle='dotted',alpha=0.5)573 574            hard_hit_dates = [(exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.9),575                              (exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.75),576                              (exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.25),577                              (exit_velo_df_codes_summ_new[plot_dict[input.stat_id()]["percentile_label"]]).quantile(0.1)]578            hard_hit_text = ['10th %','25th %','75th %','90th %']579            for i, x in enumerate(hard_hit_dates):580                text(min(input.n()+input.n()/100,input.n()+input.n()+3), x ,hard_hit_text[i], rotation=0, ha='left',581                    bbox=dict(facecolor='white',alpha=0.5, edgecolor=colour_palette[2+i], pad=2))582 583 584        585 586 587 588        if plot_dict[input.stat_id()]["percentile"] == False:589            ax.hlines(y=exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][plot_dict[input.stat_id()]["x_value"]].sum()/exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][divisor_x].sum(),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[1],linestyle='-.',label=label_1)590 591            ax.hlines(y=elly_zone_df[plot_dict[input.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)592 593            sns.lineplot(x=range(1,len(elly_zone_df)+1),y=elly_zone_df[plot_dict[input.stat_id()]["x_value"]].fillna(0).rolling(window=swing_min).sum()/swing_min,color=colour_palette[0],linewidth=3,ax=ax)594 595 596 597        if plot_dict[input.stat_id()]["percentile"] == True:598 599            ax.hlines(y=exit_velo_df_codes[exit_velo_df_codes.level == input.level_id()][plot_dict[input.stat_id()]["x_value"]].quantile(0.9),xmin=swing_min,xmax=len(elly_zone_df),color=colour_palette[1],linestyle='-.',label=label_1)600 601            ax.hlines(y=elly_zone_df[plot_dict[input.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)602 603            sns.lineplot(x=range(1,len(elly_zone_df)+1),y=elly_zone_df[plot_dict[input.stat_id()]["x_value"]].fillna(0).rolling(window=swing_min).quantile(0.9),color=colour_palette[0],linewidth=3,ax=ax)604 605 606        #ax.set_xlim(input.n(),exit_velo_df_small.pitch.max())607        #plt.yticks([0,0.2,0.4,0.6,0.8,1])608        #ax.set_ylim(math.floor((min(exit_velo_df_codes_summ.zone_contact)/5)*100)*5/100,1)609        ax.set_xlim(math.floor(swing_min),len(elly_zone_df))610        ax.set_title(f'{batter_dict[int(input.id())]} - {input.level_id()} - {swing_min} {plot_dict[input.stat_id()]["x_axis"]} Rolling {plot_dict[input.stat_id()]["title"]}', fontsize=16,fontname='Century Gothic',)611        #vals = ax.get_yticks()612        ax.set_xlabel(plot_dict[input.stat_id()]['x_axis'], fontsize=16,fontname='Century Gothic')613        ax.set_ylabel(plot_dict[input.stat_id()]['y_axis'], fontsize=16,fontname='Century Gothic')614 615        #fig.axes[0].invert_yaxis()616        617        #fig.subplots_adjust(wspace=.02, hspace=.02)618        #ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))619        ax.set_yticks(plot_dict[input.stat_id()]["x_range"])620        #fig.colorbar(plot_dist, ax=ax)621        #fig.colorbar(plot_dist)622        #fig.axes[0].invert_yaxis()623        ax.legend(fontsize='16')624        fig.text(x=0.03,y=0.02,s='By: @TJStats',fontname='Century Gothic')625        fig.text(x=1-0.03,y=0.02,s='Data: MLB',ha='right',fontname='Century Gothic')626        fig.tight_layout()627 628 629rolling_pitcher = App(ui.page_fluid(630    ui.tags.base(href=base_url), 631    ui.tags.div(632         {"style": "width:90%;margin: 0 auto;max-width: 1600px;"},633        ui.tags.style(634            """635            h4 {636                margin-top: 1em;font-size:35px;637            }638            h2{639                font-size:25px;640            }641            """642         ),643    shinyswatch.theme.simplex(),644    ui.tags.h4("TJStats"),645    ui.tags.i("Baseball Analytics and Visualizations"),646    ui.markdown("""<a href='https://www.patreon.com/tj_stats'>Support me on Patreon for Access to 2024 Apps</a><sup>1</sup>"""),647    ui.navset_tab(648        ui.nav_control(649             ui.a(650                "Home",651                href="home/"652            ),653        ),654        ui.nav_menu(655            "Batter Charts",656            ui.nav_control(657            ui.a(658                "Batting Rolling",659                href="rolling_batter/"660            ),661            ui.a(662                "Spray & Damage",663                href="spray/"664            ),665            ui.a(666                "Decision Value",667                href="decision_value/"668            ),669            # ui.a(670            #     "Damage Model",671            #     href="damage_model/"672            # ),673            ui.a(674                "Batter Scatter",675                href="batter_scatter/"676            ),677            # ui.a(678            #     "EV vs LA Plot",679            #     href="ev_angle/"680            # ),681            ui.a(682                "Statcast Compare",683                href="statcast_compare/"684            )685        ),686        ),687        ui.nav_menu(688            "Pitcher Charts",689            ui.nav_control(690             ui.a(691                "Pitcher Rolling",692                href="rolling_pitcher/"693            ),694             ui.a(695                "Pitcher Summary",696                href="pitching_summary_graphic_new/"697            ),698             ui.a(699                "Pitcher Scatter",700                href="pitcher_scatter/"701            )702        ),703        )),ui.row(704    ui.layout_sidebar(705 706      ui.panel_sidebar(707        ui.input_select("id", "Select Pitcher",batter_dict,selected=675911,width=1,size=1,selectize=True),708        ui.input_select("level_id", "Select Level",level_dict,width=1,size=1),709        ui.input_select("stat_id", "Select Stat",plot_dict_small,width=1,size=1),710        ui.input_numeric("n", "Rolling Window Size", value=50),711        ui.input_action_button("go", "Generate",class_="btn-primary"),712 713        ui.output_table("result")714      ),715 716      ui.panel_main(717        ui.output_plot("plot",height = "1000px",width="1000px")718      ),719    )),)),server)