CoolFace
Apppublic

TJStatsApps/2025_decision_value

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