|
|
from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui |
|
|
import datasets |
|
|
from datasets import load_dataset |
|
|
import pandas as pd |
|
|
import numpy as np |
|
|
import matplotlib.pyplot as plt |
|
|
import seaborn as sns |
|
|
import numpy as np |
|
|
from scipy.stats import gaussian_kde |
|
|
import matplotlib |
|
|
from matplotlib.ticker import MaxNLocator |
|
|
from matplotlib.gridspec import GridSpec |
|
|
from scipy.stats import zscore |
|
|
import math |
|
|
import matplotlib |
|
|
from adjustText import adjust_text |
|
|
import matplotlib.ticker as mtick |
|
|
from shinywidgets import output_widget, render_widget |
|
|
import pandas as pd |
|
|
|
|
|
import shinyswatch |
|
|
import inflect |
|
|
from matplotlib.pyplot import text |
|
|
from functions import rolling_batter_functions as rbf |
|
|
import joblib |
|
|
import polars as pl |
|
|
from functions import df_update |
|
|
update = df_update.df_update() |
|
|
|
|
|
def percentile(n): |
|
|
def percentile_(x): |
|
|
return np.nanpercentile(x, n) |
|
|
percentile_.__name__ = 'percentile_%s' % n |
|
|
return percentile_ |
|
|
|
|
|
colour_palette = ['#FFB000','#648FFF','#785EF0', |
|
|
'#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED'] |
|
|
|
|
|
|
|
|
|
|
|
print('Starting Everything:') |
|
|
|
|
|
|
|
|
exit_velo_df_mlb = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/mlb_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_mlb = exit_velo_df_mlb.with_columns(pl.lit('MLB').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_aaa = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/aaa_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_aaa = exit_velo_df_aaa.with_columns(pl.lit('AAA').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_aa = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/aa_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_aa = exit_velo_df_aa.with_columns(pl.lit('AA').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_ha = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/hi_a_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_ha = exit_velo_df_ha.with_columns(pl.lit('A+').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_a = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/lo_a_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_a = exit_velo_df_a.with_columns(pl.lit('A').alias('level')) |
|
|
|
|
|
|
|
|
|
|
|
exit_velo_df = pl.concat([exit_velo_df_mlb,exit_velo_df_aaa,exit_velo_df_aa,exit_velo_df_ha,exit_velo_df_a]) |
|
|
|
|
|
|
|
|
exit_velo_df_codes = update.update(exit_velo_df).sort('start_time') |
|
|
exit_velo_df_codes_summ = update.update_summary_select(df=exit_velo_df_codes,selection=['batter_id','batter_name','level']).to_pandas() |
|
|
exit_velo_df_codes = exit_velo_df_codes.to_pandas() |
|
|
|
|
|
woba_list = ['woba'] |
|
|
pa_list = ['k','bb','bb_minus_k'] |
|
|
balls_in_play_list = ['hard_hit','launch_speed','launch_speed_90','launch_angle','barrel','sweet_spot'] |
|
|
pitches_list = ['zone_percent','swing_percent','sw_str','csw'] |
|
|
swings_list = ['whiff_percent'] |
|
|
in_zone_pitches_list = ['zone_swing'] |
|
|
in_zone_swings_list = ['zone_contact'] |
|
|
out_zone_pitches_list = ['chase_percent'] |
|
|
out_zone_swings_list = ['chase_contact'] |
|
|
|
|
|
plot_dict = { |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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},} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
batter_dict_mlb = dict(zip(exit_velo_df_mlb.sort(['batter_name'])['batter_id'],exit_velo_df_mlb.sort(['batter_name'])['batter_name'])) |
|
|
|
|
|
batter_dict_aaa = dict(zip(exit_velo_df_aaa.sort(['batter_name'])['batter_id'],exit_velo_df_aaa.sort(['batter_name'])['batter_name'])) |
|
|
batter_dict_aa = dict(zip(exit_velo_df_aa.sort(['batter_name'])['batter_id'],exit_velo_df_aa.sort(['batter_name'])['batter_name'])) |
|
|
batter_dict_ha = dict(zip(exit_velo_df_ha.sort(['batter_name'])['batter_id'],exit_velo_df_ha.sort(['batter_name'])['batter_name'])) |
|
|
batter_dict_a =dict(zip(exit_velo_df_a.sort(['batter_name'])['batter_id'],exit_velo_df_a.sort(['batter_name'])['batter_name'])) |
|
|
|
|
|
level_dict = {'MLB':'MLB','AAA':'AAA','AA':'AA','A+':'A+','A':'A'} |
|
|
|
|
|
plot_dict_small = { |
|
|
'k':'K%', |
|
|
'bb':'BB%', |
|
|
'bb_minus_k':'BB-K%', |
|
|
'csw':'CSW%', |
|
|
'woba':'wOBA', |
|
|
'launch_speed':'Exit Velocity', |
|
|
'launch_speed_90':'90th Percentile Exit Velocity', |
|
|
'hard_hit':'HardHit%', |
|
|
'sweet_spot':'SweetSpot%', |
|
|
'launch_angle':'Launch Angle', |
|
|
'zone_percent':'Zone%', |
|
|
'barrel':'Barrel%', |
|
|
'swing_percent':'Swing%', |
|
|
'whiff_percent':'Whiff%', |
|
|
'sw_str':'SwStr%', |
|
|
'zone_swing':'Z-Swing%', |
|
|
'zone_contact':'Z-Contact%', |
|
|
'chase_percent':'O-Swing%', |
|
|
'chase_contact':'O-Contact%',} |
|
|
|
|
|
|
|
|
def server(input,output,session): |
|
|
|
|
|
@render.ui |
|
|
def test(): |
|
|
|
|
|
|
|
|
if input.my_tabs() == 'MLB': |
|
|
|
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_mlb,selectize=True) |
|
|
|
|
|
|
|
|
if input.my_tabs() == 'AAA': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_aaa,selectize=True) |
|
|
|
|
|
if input.my_tabs() == 'AA': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_aa,selectize=True) |
|
|
|
|
|
if input.my_tabs() == 'A+': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_ha,selectize=True) |
|
|
|
|
|
if input.my_tabs() == 'A': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_a,selectize=True) |
|
|
|
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_mlb(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_mlb, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_aaa(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_aaa, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_aa(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_aa, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_ha(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_ha, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_a(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_a, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui |
|
|
import datasets |
|
|
from datasets import load_dataset |
|
|
import pandas as pd |
|
|
import numpy as np |
|
|
import matplotlib.pyplot as plt |
|
|
import seaborn as sns |
|
|
import numpy as np |
|
|
from scipy.stats import gaussian_kde |
|
|
import matplotlib |
|
|
from matplotlib.ticker import MaxNLocator |
|
|
from matplotlib.gridspec import GridSpec |
|
|
from scipy.stats import zscore |
|
|
import math |
|
|
import matplotlib |
|
|
from adjustText import adjust_text |
|
|
import matplotlib.ticker as mtick |
|
|
from shinywidgets import output_widget, render_widget |
|
|
import pandas as pd |
|
|
|
|
|
import shinyswatch |
|
|
import inflect |
|
|
from matplotlib.pyplot import text |
|
|
from functions import rolling_batter_functions as rbf |
|
|
import joblib |
|
|
import polars as pl |
|
|
from functions import df_update |
|
|
update = df_update.df_update() |
|
|
|
|
|
def percentile(n): |
|
|
def percentile_(x): |
|
|
return np.nanpercentile(x, n) |
|
|
percentile_.__name__ = 'percentile_%s' % n |
|
|
return percentile_ |
|
|
|
|
|
colour_palette = ['#FFB000','#648FFF','#785EF0', |
|
|
'#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED'] |
|
|
|
|
|
|
|
|
|
|
|
print('Starting Everything:') |
|
|
|
|
|
|
|
|
exit_velo_df_mlb = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/mlb_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_mlb = exit_velo_df_mlb.with_columns(pl.lit('MLB').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_aaa = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/aaa_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_aaa = exit_velo_df_aaa.with_columns(pl.lit('AAA').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_aa = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/aa_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_aa = exit_velo_df_aa.with_columns(pl.lit('AA').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_ha = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/hi_a_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_ha = exit_velo_df_ha.with_columns(pl.lit('A+').alias('level')) |
|
|
|
|
|
|
|
|
exit_velo_df_a = pl.read_parquet(f"hf://datasets/TJStatsApps/mlb_data/data/lo_a_pitch_data_2025.parquet") |
|
|
|
|
|
exit_velo_df_a = exit_velo_df_a.with_columns(pl.lit('A').alias('level')) |
|
|
|
|
|
|
|
|
|
|
|
exit_velo_df = pl.concat([exit_velo_df_mlb,exit_velo_df_aaa,exit_velo_df_aa,exit_velo_df_ha,exit_velo_df_a]) |
|
|
|
|
|
|
|
|
exit_velo_df_codes = update.update(exit_velo_df) |
|
|
exit_velo_df_codes_summ = update.update_summary_select(df=exit_velo_df_codes,selection=['batter_id','batter_name','level']).to_pandas() |
|
|
exit_velo_df_codes = exit_velo_df_codes.to_pandas() |
|
|
|
|
|
woba_list = ['woba'] |
|
|
pa_list = ['k','bb','bb_minus_k'] |
|
|
balls_in_play_list = ['hard_hit','launch_speed','launch_speed_90','launch_angle','barrel','sweet_spot'] |
|
|
pitches_list = ['zone_percent','swing_percent','sw_str','csw'] |
|
|
swings_list = ['whiff_percent'] |
|
|
in_zone_pitches_list = ['zone_swing'] |
|
|
in_zone_swings_list = ['zone_contact'] |
|
|
out_zone_pitches_list = ['chase_percent'] |
|
|
out_zone_swings_list = ['chase_contact'] |
|
|
|
|
|
plot_dict = { |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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}, |
|
|
'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},} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
batter_dict_mlb = dict(zip(exit_velo_df_mlb.sort(['batter_name'])['batter_id'],exit_velo_df_mlb.sort(['batter_name'])['batter_name'])) |
|
|
|
|
|
batter_dict_aaa = dict(zip(exit_velo_df_aaa.sort(['batter_name'])['batter_id'],exit_velo_df_aaa.sort(['batter_name'])['batter_name'])) |
|
|
batter_dict_aa = dict(zip(exit_velo_df_aa.sort(['batter_name'])['batter_id'],exit_velo_df_aa.sort(['batter_name'])['batter_name'])) |
|
|
batter_dict_ha = dict(zip(exit_velo_df_ha.sort(['batter_name'])['batter_id'],exit_velo_df_ha.sort(['batter_name'])['batter_name'])) |
|
|
batter_dict_a =dict(zip(exit_velo_df_a.sort(['batter_name'])['batter_id'],exit_velo_df_a.sort(['batter_name'])['batter_name'])) |
|
|
|
|
|
level_dict = {'MLB':'MLB','AAA':'AAA','AA':'AA','A+':'A+','A':'A'} |
|
|
|
|
|
plot_dict_small = { |
|
|
'k':'K%', |
|
|
'bb':'BB%', |
|
|
'bb_minus_k':'BB-K%', |
|
|
'csw':'CSW%', |
|
|
'woba':'wOBA', |
|
|
'launch_speed':'Exit Velocity', |
|
|
'launch_speed_90':'90th Percentile Exit Velocity', |
|
|
'hard_hit':'HardHit%', |
|
|
'sweet_spot':'SweetSpot%', |
|
|
'launch_angle':'Launch Angle', |
|
|
'zone_percent':'Zone%', |
|
|
'barrel':'Barrel%', |
|
|
'swing_percent':'Swing%', |
|
|
'whiff_percent':'Whiff%', |
|
|
'sw_str':'SwStr%', |
|
|
'zone_swing':'Z-Swing%', |
|
|
'zone_contact':'Z-Contact%', |
|
|
'chase_percent':'O-Swing%', |
|
|
'chase_contact':'O-Contact%',} |
|
|
|
|
|
|
|
|
def server(input,output,session): |
|
|
|
|
|
@render.ui |
|
|
def test(): |
|
|
|
|
|
|
|
|
if input.my_tabs() == 'MLB': |
|
|
|
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_mlb,selectize=True) |
|
|
|
|
|
|
|
|
if input.my_tabs() == 'AAA': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_aaa,selectize=True) |
|
|
|
|
|
if input.my_tabs() == 'AA': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_aa,selectize=True) |
|
|
|
|
|
if input.my_tabs() == 'A+': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_ha,selectize=True) |
|
|
|
|
|
if input.my_tabs() == 'A': |
|
|
|
|
|
|
|
|
return ui.input_select("id", "Select Player",batter_dict_a,selectize=True) |
|
|
|
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_mlb(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_mlb, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_aaa(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_aaa, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_aa(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_aa, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_ha(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_ha, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
@output |
|
|
@render.plot(alt="A histogram") |
|
|
@reactive.event(input.go, ignore_none=False) |
|
|
def plot_a(): |
|
|
|
|
|
|
|
|
rbf.rolling_plot(df = exit_velo_df_codes[exit_velo_df_codes['level']==input.my_tabs()], |
|
|
df_summ = exit_velo_df_codes_summ[exit_velo_df_codes_summ['level']==input.my_tabs()], |
|
|
player_id = input.id(), |
|
|
stat_id = input.stat_id(), |
|
|
batter_dict = batter_dict_a, |
|
|
window_select = input.n(), |
|
|
level_id = input.my_tabs()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app = App( |
|
|
ui.page_fluid( |
|
|
ui.page_sidebar( |
|
|
ui.sidebar( |
|
|
ui.tags.h5("MLB & MiLB Rolling Batter Plot"), |
|
|
ui.tags.i("Baseball Analytics and Visualizations"), |
|
|
ui.div( |
|
|
"By: ", |
|
|
ui.tags.a( |
|
|
"@TJStats", |
|
|
href="https://x.com/TJStats", |
|
|
target="_blank" |
|
|
) |
|
|
), |
|
|
ui.tags.p( |
|
|
ui.tags.a( |
|
|
"Support me on Patreon for more baseball content", |
|
|
href="https://www.patreon.com/TJ_Stats", |
|
|
target="_blank" |
|
|
) |
|
|
), |
|
|
ui.row( |
|
|
ui.output_ui('test', 'Select Player'), |
|
|
ui.input_select("stat_id", "Select Stat", plot_dict_small, width=1, size=1), |
|
|
ui.input_numeric("n", "Rolling Window Size", value=50), |
|
|
ui.input_action_button("go", "Generate", class_="btn-primary"), |
|
|
ui.output_table("result") |
|
|
) |
|
|
,width='500px'), |
|
|
|
|
|
|
|
|
ui.navset_tab( |
|
|
ui.nav("MLB", ui.output_plot("plot_mlb", height="1000px", width="1000px")), |
|
|
ui.nav("AAA", ui.output_plot("plot_aaa", height="1000px", width="1000px")), |
|
|
ui.nav("AA", ui.output_plot("plot_aa", height="1000px", width="1000px")), |
|
|
ui.nav("A+", ui.output_plot("plot_ha", height="1000px", width="1000px")), |
|
|
ui.nav("A", ui.output_plot("plot_a", height="1000px", width="1000px")), |
|
|
id="my_tabs" |
|
|
) |
|
|
) |
|
|
), |
|
|
server |
|
|
) |