Spaces:
Running
Running
Upload app.py
Browse files
app.py
ADDED
@@ -0,0 +1,706 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui
|
2 |
+
import datasets
|
3 |
+
from datasets import load_dataset
|
4 |
+
import pandas as pd
|
5 |
+
import numpy as np
|
6 |
+
import matplotlib.pyplot as plt
|
7 |
+
import seaborn as sns
|
8 |
+
import numpy as np
|
9 |
+
from scipy.stats import gaussian_kde
|
10 |
+
import matplotlib
|
11 |
+
from matplotlib.ticker import MaxNLocator
|
12 |
+
from matplotlib.gridspec import GridSpec
|
13 |
+
from scipy.stats import zscore
|
14 |
+
import math
|
15 |
+
import matplotlib
|
16 |
+
from adjustText import adjust_text
|
17 |
+
import matplotlib.ticker as mtick
|
18 |
+
from shinywidgets import output_widget, render_widget
|
19 |
+
import pandas as pd
|
20 |
+
from configure import base_url
|
21 |
+
import shinyswatch
|
22 |
+
import inflect
|
23 |
+
from matplotlib.pyplot import text
|
24 |
+
|
25 |
+
def percentile(n):
|
26 |
+
def percentile_(x):
|
27 |
+
return np.nanpercentile(x, n)
|
28 |
+
percentile_.__name__ = 'percentile_%s' % n
|
29 |
+
return percentile_
|
30 |
+
|
31 |
+
from matplotlib.colors import Normalize
|
32 |
+
|
33 |
+
print('Running')
|
34 |
+
|
35 |
+
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["#4285F4","white","#FBBC04"])
|
36 |
+
df = pd.read_csv('statcast_20152023.csv')
|
37 |
+
df['last_name'] = df['last_name, first_name'].str.split(',').str[0]
|
38 |
+
df['first_name'] = df['last_name, first_name'].str.split(',').str[1].str.strip(' ')
|
39 |
+
df['name'] = df['first_name'] +' ' +df['last_name']
|
40 |
+
|
41 |
+
df[[x for x in df if x[-7:] == 'percent']] = df[[x for x in df if x[-7:] == 'percent']]/100
|
42 |
+
df['barrel_batted_rate'] = df['barrel_batted_rate']/100
|
43 |
+
|
44 |
+
player_dict = df[['player_id','name']].drop_duplicates().sort_values('name').set_index('player_id').to_dict()['name']
|
45 |
+
|
46 |
+
df_median = df[df.pa>=400]
|
47 |
+
|
48 |
+
format_dict = {
|
49 |
+
'k_percent':{'format':':.1%','average':df.strikeout.sum()/df.pa.sum(),'a_d_good':False,'tab_name':'K%'},
|
50 |
+
'bb_percent':{'format':':.1%','average':df.walk.sum()/df.pa.sum(),'a_d_good':True,'tab_name':'BB%'},
|
51 |
+
'batting_avg':{'format':':.3f','average':df.hit.sum()/df.ab.sum(),'a_d_good':True,'tab_name':'AVG'},
|
52 |
+
'on_base_plus_slg':{'format':':.3f','average':df.on_base_plus_slg.mean()/df.pa.mean(),'a_d_good':True,'tab_name':'OPS'},
|
53 |
+
'isolated_power':{'format':':.3f','average':(df.single.sum() + df.double.sum()*2 + df.triple.sum()*3 + df.home_run.sum()*4)/df.ab.sum() - df.hit.sum()/df.ab.sum(),'a_d_good':True,'tab_name':'ISO'},
|
54 |
+
'xba':{'format':':.3f','average':df_median.xba.median(),'a_d_good':True,'tab_name':'xBA'},
|
55 |
+
'xslg':{'format':':.3f','average':df_median.xslg.median(),'a_d_good':True,'tab_name':'xSLG'},
|
56 |
+
'woba':{'format':':.3f','average':df_median.woba.median(),'a_d_good':True,'tab_name':'wOBA'},
|
57 |
+
'xwoba':{'format':':.3f','average':df_median.xwoba.median(),'a_d_good':True,'tab_name':'xwOBA'},
|
58 |
+
'xobp':{'format':':.3f','average':df_median.xobp.median(),'a_d_good':True,'tab_name':'xOBP'},
|
59 |
+
'xiso':{'format':':.3f','average':df_median.xiso.median(),'a_d_good':True,'tab_name':'xISO'},
|
60 |
+
'wobacon':{'format':':.3f','average':df_median.wobacon.median(),'a_d_good':True,'tab_name':'wOBACON'},
|
61 |
+
'xwobacon':{'format':':.3f','average':df_median.xwobacon.median(),'a_d_good':True,'tab_name':'xwOBACON'},
|
62 |
+
'bacon':{'format':':.1f','average':df_median.bacon.median(),'a_d_good':True,'tab_name':'BACON'},
|
63 |
+
'xbacon':{'format':':.1f','average':df_median.xbacon.median(),'a_d_good':True,'tab_name':'xBACON'},
|
64 |
+
'xbadiff':{'format':':.3f','average':df_median.xbadiff.median(),'a_d_good':True,'tab_name':'BA-xBA'},
|
65 |
+
'xslgdiff':{'format':':.3f','average':df_median.xslgdiff.median(),'a_d_good':True,'tab_name':'SLG-xSLG'},
|
66 |
+
'wobadiff':{'format':':.3f','average':df_median.wobadiff.median(),'a_d_good':True,'tab_name':'wOBA-xwOBA'},
|
67 |
+
'exit_velocity_avg':{'format':':.1f','average':(df.exit_velocity_avg * df.batted_ball).sum() / (df.batted_ball).sum(),'a_d_good':True,'tab_name':'EV'},
|
68 |
+
'launch_angle_avg':{'format':':.1f','average':(df.launch_angle_avg * df.batted_ball).sum() / (df.batted_ball).sum(),'a_d_good':True,'tab_name':'LA'},
|
69 |
+
'barrel':{'format':':.0f','average':df_median.barrel.median(),'a_d_good':True,'tab_name':'Barrel'},
|
70 |
+
'barrel_batted_rate':{'format':':.1%','average':(df.barrel).sum() / (df.batted_ball).sum(),'a_d_good':True,'tab_name':'Barrel%'},
|
71 |
+
'avg_best_speed':{'format':':.1f','average':(df.avg_best_speed * df.batted_ball).sum() / (df.batted_ball).sum(),'a_d_good':True,'tab_name':'Best Speed'},
|
72 |
+
'avg_hyper_speed':{'format':':.1f','average':(df.avg_hyper_speed * df.batted_ball).sum() / (df.batted_ball).sum(),'a_d_good':True,'tab_name':'Hyper Speed'},
|
73 |
+
'out_zone_swing_miss':{'format':':.0f','average':df_median.out_zone_swing_miss.mean(),'a_d_good':True,'tab_name':'O-Whiff%'},
|
74 |
+
'out_zone_swing':{'format':':.0f','average':df_median.out_zone_swing.mean(),'a_d_good':True,'tab_name':'O-Swing'},
|
75 |
+
'out_zone':{'format':':.0f','average':df_median.out_zone.mean(),'a_d_good':True,'tab_name':'O-Zone'},
|
76 |
+
'pitch_count_offspeed':{'format':':.0f','average':df_median.pitch_count_offspeed.mean(),'a_d_good':True,'tab_name':'Pitch Off-Speed'},
|
77 |
+
'pitch_count_fastball':{'format':':.0f','average':df_median.pitch_count_fastball.mean(),'a_d_good':True,'tab_name':'Pitch Fastball'},
|
78 |
+
'pitch_count_breaking':{'format':':.0f','average':df_median.pitch_count_breaking.mean(),'a_d_good':True,'tab_name':'Pitch Breaking'},
|
79 |
+
'pitch_count':{'format':':.0f','average':df_median.pitch_count.mean(),'a_d_good':True,'tab_name':'Pitches'},
|
80 |
+
'in_zone_swing_miss':{'format':':.0f','average':df_median.in_zone_swing_miss.mean(),'a_d_good':False,'tab_name':'Z-Whiff'},
|
81 |
+
'in_zone_swing':{'format':':.0f','average':df_median.in_zone_swing.mean(),'a_d_good':True,'tab_name':'Z-Swing'},
|
82 |
+
'in_zone':{'format':':.0f','average':df_median.in_zone.mean(),'a_d_good':True,'tab_name':'Zone'},
|
83 |
+
'edge':{'format':':.0f','average':df_median.edge.mean(),'a_d_good':True,'tab_name':'Edge'},
|
84 |
+
'batted_ball':{'format':':.0f','average':df_median.batted_ball.mean(),'a_d_good':True,'tab_name':'Batted Balls'},
|
85 |
+
'groundballs':{'format':':.0f','average':df_median.groundballs.mean(),'a_d_good':True,'tab_name':'Groundballs'},
|
86 |
+
'flyballs':{'format':':.0f','average':df_median.flyballs.mean(),'a_d_good':True,'tab_name':'Flyballs'},
|
87 |
+
'linedrives':{'format':':.0f','average':df_median.linedrives.mean(),'a_d_good':True,'tab_name':'Linedrives'},
|
88 |
+
'popups':{'format':':.0f','average':df_median.popups.mean(),'a_d_good':True,'tab_name':'Popups'},
|
89 |
+
'n_bolts':{'format':':.0f','average':df_median.n_bolts.mean(),'a_d_good':True,'tab_name':'Bolts'},
|
90 |
+
'hp_to_1b':{'format':':.2f','average':df_median.hp_to_1b.mean(),'a_d_good':True,'tab_name':'Home Plate to 1st'},
|
91 |
+
'sprint_speed':{'format':':.1f','average':df_median.sprint_speed.mean(),'a_d_good':True,'tab_name':'Sprint Speed'},
|
92 |
+
|
93 |
+
'slg_percent':{'format':':.1%','average':(df.single.sum() + df.double.sum()*2 + df.triple.sum()*3 + df.home_run.sum()*4)/df.ab.sum(),'a_d_good':True,'tab_name':'SLG'},
|
94 |
+
'on_base_percent':{'format':':.1%','average':df_median.on_base_percent.median(),'a_d_good':True,'tab_name':'OBP'},
|
95 |
+
'sweet_spot_percent':{'format':':.1%','average':df_median.sweet_spot_percent.median(),'a_d_good':True,'tab_name':'SweetSpot%'},
|
96 |
+
'solidcontact_percent':{'format':':.1%','average':df_median.solidcontact_percent.median(),'a_d_good':True,'tab_name':'Solid%'},
|
97 |
+
'flareburner_percent':{'format':':.1%','average':df_median.flareburner_percent.median(),'a_d_good':False,'tab_name':'Flare/Burner%'},
|
98 |
+
'poorlyunder_percent':{'format':':.1%','average':df_median.poorlyunder_percent.median(),'a_d_good':False,'tab_name':'Under%'},
|
99 |
+
'poorlytopped_percent':{'format':':.1%','average':df_median.poorlytopped_percent.median(),'a_d_good':False,'tab_name':'Topped%'},
|
100 |
+
'poorlyweak_percent':{'format':':.1%','average':df_median.poorlyweak_percent.median(),'a_d_good':False,'tab_name':'Weak%'},
|
101 |
+
'hard_hit_percent':{'format':':.1%','average':df_median.hard_hit_percent.median(),'a_d_good':True,'tab_name':'HardHit%'},
|
102 |
+
'z_swing_percent':{'format':':.1%','average':df.in_zone_swing.sum()/df.in_zone.sum(),'a_d_good':True,'tab_name':'Z-Swing%'},
|
103 |
+
'z_swing_miss_percent':{'format':':.1%','average':df.in_zone_swing_miss.sum()/df.in_zone_swing.sum(),'a_d_good':False,'tab_name':'Z-Whiff%'},
|
104 |
+
|
105 |
+
'out_zone_percent':{'format':':.1%','average':df.out_zone.sum()/df.pitch_count.sum(),'a_d_good':True,'tab_name':'O-Zone%'},
|
106 |
+
'meatball_swing_percent':{'format':':.1%','average':df_median.meatball_swing_percent.median(),'a_d_good':True,'tab_name':'Meatball Swing%'},
|
107 |
+
'meatball_percent':{'format':':.1%','average':df_median.meatball_percent.median(),'a_d_good':True,'tab_name':'Meatball%'},
|
108 |
+
'iz_contact_percent':{'format':':.1%','average':1 - df.in_zone_swing_miss.sum()/df.in_zone_swing.sum(),'a_d_good':True,'tab_name':'Z-Contact%'},
|
109 |
+
'in_zone_percent':{'format':':.1%','average':df.in_zone.mean()/df.pitch_count.sum(),'a_d_good':True,'tab_name':'Zone%'},
|
110 |
+
'oz_swing_percent':{'format':':.1%','average':df.out_zone_swing.sum()/df.out_zone.sum(),'a_d_good':False,'tab_name':'O-Swing%'},
|
111 |
+
'oz_swing_miss_percent':{'format':':.1%','average':df.out_zone_swing_miss.sum()/df.out_zone_swing.sum(),'a_d_good':False,'tab_name':'O-Whiff%'},
|
112 |
+
'oz_contact_percent':{'format':':.1%','average':1 - df.out_zone_swing_miss.sum()/df.out_zone_swing.sum(),'a_d_good':True,'tab_name':'O-Contact%'},
|
113 |
+
'edge_percent':{'format':':.1%','average':df_median.edge_percent.median(),'a_d_good':True,'tab_name':'Edge%'},
|
114 |
+
'whiff_percent':{'format':':.1%','average':(df.in_zone_swing_miss.sum() + df.out_zone_swing_miss.sum()) / (df.in_zone_swing.sum() + df.out_zone_swing.sum()),'a_d_good':False,'tab_name':'Whiff%'},
|
115 |
+
'swstr_percent':{'format':':.1%','average':(df.in_zone_swing_miss.sum() + df.out_zone_swing_miss.sum()) / (df.pitch_count.sum()),'a_d_good':False,'tab_name':'SwStr%'},
|
116 |
+
'swing_percent':{'format':':.1%','average':(df.in_zone_swing.sum() + df.out_zone_swing.sum()) / (df.pitch_count.sum()),'a_d_good':True,'tab_name':'Swing%'},
|
117 |
+
'pull_percent':{'format':':.1%','average':df_median.hit.median(),'a_d_good':True,'tab_name':'Pull%'},
|
118 |
+
'straightaway_percent':{'format':':.1%','average':df_median.hit.median(),'a_d_good':True,'tab_name':'Straightaway%'},
|
119 |
+
'opposite_percent':{'format':':.1%','average':df_median.hit.median(),'a_d_good':True,'tab_name':'Opposite%'},
|
120 |
+
'f_strike_percent':{'format':':.1%','average':df_median.hit.median(),'a_d_good':False,'tab_name':'1st Strike%'},
|
121 |
+
'groundballs_percent':{'format':':.1%','average':df.groundballs.sum()/df.batted_ball.sum(),'a_d_good':False,'tab_name':'GB%'},
|
122 |
+
'flyballs_percent':{'format':':.1%','average':df.flyballs.sum()/df.batted_ball.sum(),'a_d_good':True,'tab_name':'FB%'},
|
123 |
+
'linedrives_percent':{'format':':.1%','average':df.linedrives.sum()/df.batted_ball.sum(),'a_d_good':True,'tab_name':'LD%'},
|
124 |
+
'popups_percent':{'format':':.1%','average':df.popups.sum()/df.batted_ball.sum(),'a_d_good':False,'tab_name':'PU%'},}
|
125 |
+
|
126 |
+
column_dict = pd.DataFrame(format_dict.keys(),[format_dict[x]['tab_name'] for x in format_dict.keys()]).reset_index().set_index(0).to_dict()['index']
|
127 |
+
|
128 |
+
|
129 |
+
def server(input,output,session):
|
130 |
+
|
131 |
+
|
132 |
+
@output
|
133 |
+
@render.text
|
134 |
+
@reactive.event(input.go, ignore_none=False)
|
135 |
+
def txt_title():
|
136 |
+
if input.player_id() == '':
|
137 |
+
return 'Select a Player'
|
138 |
+
|
139 |
+
player_input = int(input.player_id())
|
140 |
+
season_1 = max(2015,int(input.season_1()))
|
141 |
+
season_2 = min(2023,int(input.season_2()))
|
142 |
+
|
143 |
+
if season_1 < season_2:
|
144 |
+
season_pick = [season_1,season_2]
|
145 |
+
|
146 |
+
elif season_1 > season_2:
|
147 |
+
season_pick = [season_2,season_1]
|
148 |
+
|
149 |
+
if len(str(input.player_id())) == 0:
|
150 |
+
return 'Select a Batter'
|
151 |
+
if str(input.season_1()) == str(input.season_2()):
|
152 |
+
return 'Select Different Seasons'
|
153 |
+
if len(df[(df.player_id == player_input)&(df.year == season_pick[0])] )== 0 or len(df[(df.player_id == player_input)&(df.year == season_pick[1])] )== 0:
|
154 |
+
return 'Select Different Seasons'
|
155 |
+
return f'{player_dict[int(input.player_id())]} Statcast Season Comparison'
|
156 |
+
|
157 |
+
@output
|
158 |
+
@render.text
|
159 |
+
@reactive.event(input.go, ignore_none=False)
|
160 |
+
def txt_title_compare():
|
161 |
+
if type(input.player_id()) is int or input.player_id()=='':
|
162 |
+
return
|
163 |
+
|
164 |
+
if type(input.player_id_2()) is int or input.player_id_2()=='':
|
165 |
+
return
|
166 |
+
|
167 |
+
player_input_1 = int(input.player_id())
|
168 |
+
player_input_2 = int(input.player_id_2())
|
169 |
+
|
170 |
+
|
171 |
+
# season_pick = [input.season_1(),input.season_2()]
|
172 |
+
columns_i_want = list(input.row_select())
|
173 |
+
print(columns_i_want)
|
174 |
+
season_1 = max(2015,int(input.season_1()))
|
175 |
+
season_2 = min(2023,int(input.season_2()))
|
176 |
+
|
177 |
+
player_list = [player_input_1,player_input_2]
|
178 |
+
name_list = [player_dict[int(player_input_1)],player_dict[int(player_input_2)]]
|
179 |
+
season_pick_list = [season_1,season_2]
|
180 |
+
|
181 |
+
if len(str(input.player_id())) == 0:
|
182 |
+
return 'Select a Batter'
|
183 |
+
if len(str(input.player_id_2())) == 0:
|
184 |
+
return 'Select a Batter'
|
185 |
+
|
186 |
+
if str(input.player_id()) == str(input.player_id_2()) and str(input.season_1()) == str(input.season_2()):
|
187 |
+
return 'Select Different Seasons'
|
188 |
+
if len(df[(df.player_id == player_list[0])&(df.year == season_pick_list[0])] )== 0 or len(df[(df.player_id == player_list[1])&(df.year == season_pick_list[1])])== 0:
|
189 |
+
return 'No Data for Specified Batter in Given Season'
|
190 |
+
|
191 |
+
return f'Statcast Season Comparison'
|
192 |
+
|
193 |
+
|
194 |
+
|
195 |
+
|
196 |
+
@output
|
197 |
+
@render.text
|
198 |
+
@reactive.event(input.go, ignore_none=False)
|
199 |
+
def text_2022():
|
200 |
+
if input.player_id() == '':
|
201 |
+
return 'Select a Player'
|
202 |
+
return f'{int(input.season_1())} Season Results Compares to MLB Average'
|
203 |
+
|
204 |
+
|
205 |
+
@output
|
206 |
+
@render.text
|
207 |
+
@reactive.event(input.go, ignore_none=False)
|
208 |
+
def text_2022_1():
|
209 |
+
if type(input.player_id()) is int or input.player_id()=='':
|
210 |
+
return
|
211 |
+
|
212 |
+
if type(input.player_id_2()) is int or input.player_id_2()=='':
|
213 |
+
return
|
214 |
+
season_1 = max(2015,int(input.season_1()))
|
215 |
+
season_2 = min(2023,int(input.season_2()))
|
216 |
+
season_pick_list = [season_1,season_2]
|
217 |
+
player_input_1 = int(input.player_id())
|
218 |
+
player_input_2 = int(input.player_id_2())
|
219 |
+
name_list = [player_dict[int(player_input_1)],player_dict[int(player_input_2)]]
|
220 |
+
return f"{name_list[0]} '{str(season_pick_list[0])[2:]} Season Results Compares to MLB Average"
|
221 |
+
|
222 |
+
@output
|
223 |
+
@render.text
|
224 |
+
@reactive.event(input.go, ignore_none=False)
|
225 |
+
def text_2023():
|
226 |
+
if input.player_id() == '':
|
227 |
+
return 'Select a Player'
|
228 |
+
return f'{int(input.season_2())} Season Results Compares to MLB Average'
|
229 |
+
|
230 |
+
@output
|
231 |
+
@render.text
|
232 |
+
@reactive.event(input.go, ignore_none=False)
|
233 |
+
def text_2023_1():
|
234 |
+
if type(input.player_id()) is int or input.player_id()=='':
|
235 |
+
return
|
236 |
+
|
237 |
+
if type(input.player_id_2()) is int or input.player_id_2()=='':
|
238 |
+
return
|
239 |
+
season_1 = max(2015,int(input.season_1()))
|
240 |
+
season_2 = min(2023,int(input.season_2()))
|
241 |
+
season_pick_list = [season_1,season_2]
|
242 |
+
player_input_1 = int(input.player_id())
|
243 |
+
player_input_2 = int(input.player_id_2())
|
244 |
+
name_list = [player_dict[int(player_input_1)],player_dict[int(player_input_2)]]
|
245 |
+
return f"{name_list[1]} '{str(season_pick_list[1])[2:]} Season Results Compares to MLB Average"
|
246 |
+
|
247 |
+
@output
|
248 |
+
@render.text
|
249 |
+
@reactive.event(input.go, ignore_none=False)
|
250 |
+
def text_diff():
|
251 |
+
if input.player_id() == '':
|
252 |
+
return 'Select a Player'
|
253 |
+
return f'Difference Compares {int(input.season_2())} Results to {int(input.season_1())} Results'
|
254 |
+
|
255 |
+
@output
|
256 |
+
@render.text
|
257 |
+
@reactive.event(input.go, ignore_none=False)
|
258 |
+
def text_diff_compare():
|
259 |
+
if type(input.player_id()) is int or input.player_id()=='':
|
260 |
+
return
|
261 |
+
|
262 |
+
if type(input.player_id_2()) is int or input.player_id_2()=='':
|
263 |
+
return
|
264 |
+
player_input_1 = int(input.player_id())
|
265 |
+
player_input_2 = int(input.player_id_2())
|
266 |
+
name_list = [player_dict[int(player_input_1)],player_dict[int(player_input_2)]]
|
267 |
+
return f'Difference Compares {name_list[0]} Results to {name_list[1]} Results'
|
268 |
+
|
269 |
+
|
270 |
+
|
271 |
+
@output
|
272 |
+
@render.table
|
273 |
+
@reactive.event(input.go, ignore_none=False)
|
274 |
+
def statcast_compare():
|
275 |
+
if input.player_id() == '':
|
276 |
+
return
|
277 |
+
|
278 |
+
if len(str(input.player_id())) == 0:
|
279 |
+
return
|
280 |
+
if len(str(input.player_id_2())) == 0:
|
281 |
+
return
|
282 |
+
|
283 |
+
|
284 |
+
player_input = int(input.player_id())
|
285 |
+
|
286 |
+
|
287 |
+
# season_pick = [input.season_1(),input.season_2()]
|
288 |
+
columns_i_want = list(input.row_select())
|
289 |
+
print(columns_i_want)
|
290 |
+
season_1 = max(2015,int(input.season_1()))
|
291 |
+
season_2 = min(2023,int(input.season_2()))
|
292 |
+
|
293 |
+
|
294 |
+
if season_1 < season_2:
|
295 |
+
season_pick = [season_1,season_2]
|
296 |
+
|
297 |
+
elif season_1 > season_2:
|
298 |
+
season_pick = [season_2,season_1]
|
299 |
+
|
300 |
+
else:
|
301 |
+
return
|
302 |
+
|
303 |
+
print(df[(df.player_id == player_input)&(df.year == season_pick[0])])
|
304 |
+
|
305 |
+
|
306 |
+
if len(df[(df.player_id == player_input)&(df.year == season_pick[0])] )== 0 or len(df[(df.player_id == player_input)&(df.year == season_pick[1])] )== 0:
|
307 |
+
return
|
308 |
+
|
309 |
+
df_compare = pd.concat([df[(df.player_id == player_input)&(df.year == season_pick[0])][[ 'player_age', 'pa']+columns_i_want],
|
310 |
+
df[(df.player_id == player_input)&(df.year == season_pick[1])][[ 'player_age', 'pa']+columns_i_want]]).reset_index(drop=True).T
|
311 |
+
|
312 |
+
|
313 |
+
print('test')
|
314 |
+
print(sum(df.player_id == input.player_id()))
|
315 |
+
df_compare.columns = season_pick
|
316 |
+
|
317 |
+
df_compare['Difference'] = df_compare.loc[columns_i_want][season_pick[1]] - df_compare.loc[columns_i_want][season_pick[0]]
|
318 |
+
|
319 |
+
df_compare_style = df_compare.style.format(
|
320 |
+
"{:.0f}")
|
321 |
+
df_compare_style = df_compare_style.set_properties(**{'background-color': 'white',
|
322 |
+
'color': 'white'},subset=(['player_age', 'pa'],df_compare_style.columns[2])).set_properties(
|
323 |
+
**{'min-width':'100px'},overwrite=False).set_table_styles(
|
324 |
+
[{'selector': 'th:first-child', 'text-align': 'center','props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
325 |
+
[{'selector': 'tr:first-child','text-align': 'center', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
326 |
+
[{'selector': 'index','text-align': 'center', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
327 |
+
[{'selector': 'th', 'text-align': 'center','props': [('line-height', '40px'),('min-width', '30px')]}],overwrite=False).set_properties(
|
328 |
+
|
329 |
+
**{'Height': '20px'},**{'text-align': 'center'},overwrite=False).set_table_styles([{
|
330 |
+
'selector': 'caption',
|
331 |
+
'props': [
|
332 |
+
('color', ''),
|
333 |
+
('fontname', 'Century Gothic'),
|
334 |
+
('font-size', '20px'),
|
335 |
+
('font-style', 'italic'),
|
336 |
+
('font-weight', ''),
|
337 |
+
('text-align', 'centre'),
|
338 |
+
]
|
339 |
+
|
340 |
+
},{'selector' :'th', 'props':[('text-align', 'center'),('font-size', '20px'),('Height','20px'),('min-width','200px')]},{'selector' :'td', 'props':[('text-align', 'center'),('font-size', '20px'),('min-width','100px')]}],overwrite=False)
|
341 |
+
|
342 |
+
|
343 |
+
for r in columns_i_want:
|
344 |
+
if format_dict[r]['a_d_good']:
|
345 |
+
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["#4285F4","white","#FBBC04"])
|
346 |
+
else:
|
347 |
+
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["#FBBC04","white","#4285F4"])
|
348 |
+
|
349 |
+
|
350 |
+
colormap = plt.get_cmap(cmap)
|
351 |
+
norm = Normalize(vmin=0.7, vmax=1.3)
|
352 |
+
|
353 |
+
normalized_value = norm(df_compare[df_compare.columns[0]][r]/format_dict[r]['average'])
|
354 |
+
df_compare_style.format(
|
355 |
+
f"{{{format_dict[r]['format']}}}",subset=(r,df_compare_style.columns[0])).set_properties(**{'background-color': '#%02x%02x%02x' % (int(colormap(normalized_value)[0] *255), int(colormap(normalized_value)[1] *255), int(colormap(normalized_value)[2] *255)),
|
356 |
+
'color': 'black'},subset=(r,df_compare_style.columns[0]))
|
357 |
+
|
358 |
+
norm = Normalize(vmin=0.7, vmax=1.3)
|
359 |
+
normalized_value = norm(df_compare[df_compare.columns[1]][r]/format_dict[r]['average'])
|
360 |
+
df_compare_style.format(
|
361 |
+
f"{{{format_dict[r]['format']}}}",subset=(r,df_compare_style.columns[1])).set_properties(**{'background-color': '#%02x%02x%02x' % (int(colormap(normalized_value)[0] *255), int(colormap(normalized_value)[1] *255), int(colormap(normalized_value)[2] *255)),
|
362 |
+
'color': 'black'},subset=(r,df_compare_style.columns[1]))
|
363 |
+
|
364 |
+
norm = Normalize(vmin=0.7, vmax=1.3)
|
365 |
+
normalized_value = norm(df_compare[df_compare.columns[1]][r]/df_compare[df_compare.columns[0]][r])
|
366 |
+
df_compare_style.format(
|
367 |
+
f"{{{format_dict[r]['format']}}}",subset=(r,df_compare_style.columns[2])).set_properties(**{'background-color': '#%02x%02x%02x' % (int(colormap(normalized_value)[0] *255), int(colormap(normalized_value)[1] *255), int(colormap(normalized_value)[2] *255)),
|
368 |
+
'color': 'black'},subset=(r,df_compare_style.columns[2]))
|
369 |
+
|
370 |
+
|
371 |
+
|
372 |
+
|
373 |
+
df_compare_style.relabel_index(['Age', 'PA']+[format_dict[x]['tab_name'] for x in columns_i_want]).set_properties(
|
374 |
+
**{'border': '1px black solid !important'},overwrite=False).set_table_styles(
|
375 |
+
[{"selector": "", "props": [("border", "1px solid")]},
|
376 |
+
{"selector": "tbody td", "props": [("border", "1px solid")]},
|
377 |
+
{"selector": "th", "props": [("border", "1px solid")]}],overwrite=False)
|
378 |
+
|
379 |
+
#df_compare = df_compare.fillna(np.nan)
|
380 |
+
|
381 |
+
return df_compare_style
|
382 |
+
|
383 |
+
|
384 |
+
|
385 |
+
@output
|
386 |
+
@render.table
|
387 |
+
@reactive.event(input.go, ignore_none=False)
|
388 |
+
def statcast_compare_2():
|
389 |
+
|
390 |
+
# if input.player_id() == 0:
|
391 |
+
# return
|
392 |
+
if type(input.player_id()) is int or input.player_id()=='':
|
393 |
+
return
|
394 |
+
|
395 |
+
if type(input.player_id_2()) is int or input.player_id_2()=='':
|
396 |
+
return
|
397 |
+
# if len(str(input.player_id())) == 0:
|
398 |
+
# return
|
399 |
+
|
400 |
+
player_input_1 = int(input.player_id())
|
401 |
+
player_input_2 = int(input.player_id_2())
|
402 |
+
|
403 |
+
|
404 |
+
# season_pick = [input.season_1(),input.season_2()]
|
405 |
+
columns_i_want = list(input.row_select())
|
406 |
+
print(columns_i_want)
|
407 |
+
season_1 = max(2015,int(input.season_1()))
|
408 |
+
season_2 = min(2023,int(input.season_2()))
|
409 |
+
|
410 |
+
|
411 |
+
# if season_1 < season_2:
|
412 |
+
# season_pick = [season_1,season_2]
|
413 |
+
|
414 |
+
# elif season_1 > season_2:
|
415 |
+
# season_pick = [season_2,season_1]
|
416 |
+
|
417 |
+
# else:
|
418 |
+
# return
|
419 |
+
|
420 |
+
#print(df[(df.player_id == player_input)&(df.year == season_pick[0])])
|
421 |
+
#player_list = ['Elly De La Cruz','Aaron Judge']
|
422 |
+
player_list = [player_input_1,player_input_2]
|
423 |
+
name_list = [player_dict[int(player_input_1)],player_dict[int(player_input_2)]]
|
424 |
+
season_pick_list = [season_1,season_2]
|
425 |
+
|
426 |
+
if len(df[(df.player_id == player_list[0])&(df.year == season_pick_list[0])] )== 0 or len(df[(df.player_id == player_list[1])&(df.year == season_pick_list[1])] )== 0:
|
427 |
+
return
|
428 |
+
if str(input.player_id()) == str(input.player_id_2()) and str(input.season_1()) == str(input.season_2()):
|
429 |
+
return
|
430 |
+
|
431 |
+
|
432 |
+
df_compare = pd.concat([df[(df.player_id == player_list[0])&(df.year == season_pick_list[0])][[ 'year','player_age', 'pa']+columns_i_want],
|
433 |
+
df[(df.player_id == player_list[1])&(df.year == season_pick_list[1])][[ 'year','player_age', 'pa']+columns_i_want]]).reset_index(drop=True).T
|
434 |
+
|
435 |
+
df_compare.columns = [f"{name_list[0]} '{str(season_pick_list[0])[2:]}",f"{name_list[1]} '{str(season_pick_list[1])[2:]}"]
|
436 |
+
df_compare['Difference'] = df_compare.loc[columns_i_want][df_compare.columns [0]] - df_compare.loc[columns_i_want][df_compare.columns[1]]
|
437 |
+
#df_compare = df_compare.fillna(np.nan)
|
438 |
+
|
439 |
+
df_compare_style = df_compare.style.format(
|
440 |
+
"{:.0f}")
|
441 |
+
df_compare_style = df_compare_style.set_properties(**{'background-color': 'white',
|
442 |
+
'color': 'white'},subset=(['year','player_age', 'pa'],df_compare_style.columns[2])).set_properties(
|
443 |
+
**{'min-width':'125px'},overwrite=False).set_table_styles(
|
444 |
+
[{'selector': 'th:first-child', 'text-align': 'center','props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
445 |
+
[{'selector': 'tr:first-child','text-align': 'center', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
446 |
+
[{'selector': 'index','text-align': 'center', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
447 |
+
[{'selector': 'th', 'text-align': 'center','props': [('line-height', '40px'),('min-width', '30px')]}],overwrite=False).set_properties(
|
448 |
+
|
449 |
+
**{'Height': '20px'},**{'text-align': 'center'},overwrite=False).set_table_styles([{
|
450 |
+
'selector': 'caption',
|
451 |
+
'props': [
|
452 |
+
('color', ''),
|
453 |
+
('fontname', 'Century Gothic'),
|
454 |
+
('font-size', '20px'),
|
455 |
+
('font-style', 'italic'),
|
456 |
+
('font-weight', ''),
|
457 |
+
('text-align', 'centre'),
|
458 |
+
]
|
459 |
+
|
460 |
+
},{'selector' :'th', 'props':[('text-align', 'center'),('font-size', '20px'),('Height','20px'),('min-width','200px')]},{'selector' :'td', 'props':[('text-align', 'center'),('font-size', '20px'),('min-width','100px')]}],overwrite=False)
|
461 |
+
|
462 |
+
|
463 |
+
for r in columns_i_want:
|
464 |
+
if format_dict[r]['a_d_good']:
|
465 |
+
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["#4285F4","white","#FBBC04"])
|
466 |
+
else:
|
467 |
+
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["#FBBC04","white","#4285F4"])
|
468 |
+
|
469 |
+
|
470 |
+
colormap = plt.get_cmap(cmap)
|
471 |
+
norm = Normalize(vmin=0.5, vmax=1.5)
|
472 |
+
normalized_value = norm(df_compare[df_compare.columns[0]][r]/format_dict[r]['average'])
|
473 |
+
df_compare_style.format(
|
474 |
+
f"{{{format_dict[r]['format']}}}",subset=(r,df_compare_style.columns[0])).set_properties(**{'background-color': '#%02x%02x%02x' % (int(colormap(normalized_value)[0] *255), int(colormap(normalized_value)[1] *255), int(colormap(normalized_value)[2] *255)),
|
475 |
+
'color': 'black'},subset=(r,df_compare_style.columns[0]))
|
476 |
+
|
477 |
+
norm = Normalize(vmin=0.5, vmax=1.5)
|
478 |
+
normalized_value = norm(df_compare[df_compare.columns[1]][r]/format_dict[r]['average'])
|
479 |
+
df_compare_style.format(
|
480 |
+
f"{{{format_dict[r]['format']}}}",subset=(r,df_compare_style.columns[1])).set_properties(**{'background-color': '#%02x%02x%02x' % (int(colormap(normalized_value)[0] *255), int(colormap(normalized_value)[1] *255), int(colormap(normalized_value)[2] *255)),
|
481 |
+
'color': 'black'},subset=(r,df_compare_style.columns[1]))
|
482 |
+
|
483 |
+
norm = Normalize(vmin=0.8, vmax=1.2)
|
484 |
+
normalized_value = norm(df_compare[df_compare.columns[0]][r]/df_compare[df_compare.columns[1]][r])
|
485 |
+
df_compare_style.format(
|
486 |
+
f"{{{format_dict[r]['format']}}}",subset=(r,df_compare_style.columns[2])).set_properties(**{'background-color': '#%02x%02x%02x' % (int(colormap(normalized_value)[0] *255), int(colormap(normalized_value)[1] *255), int(colormap(normalized_value)[2] *255)),
|
487 |
+
'color': 'black'},subset=(r,df_compare_style.columns[2]))
|
488 |
+
|
489 |
+
df_compare_style = df_compare_style
|
490 |
+
|
491 |
+
|
492 |
+
df_compare_style.relabel_index(['Year','Age', 'PA']+[format_dict[x]['tab_name'] for x in columns_i_want]).set_properties(
|
493 |
+
**{'border': '1px black solid !important'},overwrite=False).set_table_styles(
|
494 |
+
[{"selector": "", "props": [("border", "1px solid")]},
|
495 |
+
{"selector": "tbody td", "props": [("border", "1px solid")]},
|
496 |
+
{"selector": "th", "props": [("border", "1px solid")]}],overwrite=False)
|
497 |
+
|
498 |
+
#df_compare = df_compare.fillna(np.nan)
|
499 |
+
|
500 |
+
return df_compare_style
|
501 |
+
|
502 |
+
@output
|
503 |
+
@render.table
|
504 |
+
@reactive.event(input.go, ignore_none=False)
|
505 |
+
def colour_scale():
|
506 |
+
off_b2b_df = pd.DataFrame(data={'one':-0.30,'two':0,'three':0.30},index=[0])
|
507 |
+
off_b2b_df_style = off_b2b_df.style.set_properties(**{'border': '3 px'},overwrite=False).set_table_styles([{
|
508 |
+
'selector': 'caption',
|
509 |
+
'props': [
|
510 |
+
('color', ''),
|
511 |
+
('fontname', 'Century Gothic'),
|
512 |
+
('font-size', '20px'),
|
513 |
+
('font-style', 'italic'),
|
514 |
+
('font-weight', ''),
|
515 |
+
('text-align', 'centre'),
|
516 |
+
]
|
517 |
+
|
518 |
+
},{'selector' :'th', 'props':[('text-align', 'center'),('Height','px'),('color','black'),(
|
519 |
+
'border', '1px black solid !important')]},{'selector' :'td', 'props':[('text-align', 'center'),('font-size', '18px'),('color','black')]}],overwrite=False).set_properties(
|
520 |
+
**{'background-color':'White','index':'White','min-width':'150px'},overwrite=False).set_table_styles(
|
521 |
+
[{'selector': 'th:first-child', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
522 |
+
[{'selector': 'tr:first-child', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
523 |
+
[{'selector': 'tr', 'props': [('line-height', '20px')]}],overwrite=False).set_properties(
|
524 |
+
**{'Height': '8px'},**{'text-align': 'center'},overwrite=False).set_properties(
|
525 |
+
**{'background-color':'#4285F4'},subset=off_b2b_df.columns[0]).set_properties(
|
526 |
+
**{'background-color':'white'},subset=off_b2b_df.columns[1]).set_properties(
|
527 |
+
**{'background-color':'#FBBC04'},subset=off_b2b_df.columns[2]).set_properties(
|
528 |
+
**{'color':'black'},subset=off_b2b_df.columns[:]).hide_index().set_table_styles([
|
529 |
+
{'selector': 'thead', 'props': [('display', 'none')]}
|
530 |
+
]).set_properties(**{'border': '3 px','color':'black'},overwrite=False).set_properties(
|
531 |
+
**{'border': '1px black solid !important'},subset = ((list(off_b2b_df.index[:]),off_b2b_df.columns[:]))).set_properties(
|
532 |
+
**{'min-width':'130'},subset = ((list(off_b2b_df.index[:]),off_b2b_df.columns[:])),overwrite=False).set_properties(**{
|
533 |
+
'color': 'black'},overwrite=False).set_properties(
|
534 |
+
**{'border': '1px black solid !important'},subset = ((list(off_b2b_df.index[:]),off_b2b_df.columns[:]))) .format(
|
535 |
+
"{:+.0%}")
|
536 |
+
return off_b2b_df_style
|
537 |
+
|
538 |
+
@output
|
539 |
+
@render.table
|
540 |
+
@reactive.event(input.go, ignore_none=False)
|
541 |
+
def colour_scale_2():
|
542 |
+
off_b2b_df = pd.DataFrame(data={'one':-0.30,'two':0,'three':0.30},index=[0])
|
543 |
+
off_b2b_df_style = off_b2b_df.style.set_properties(**{'border': '3 px'},overwrite=False).set_table_styles([{
|
544 |
+
'selector': 'caption',
|
545 |
+
'props': [
|
546 |
+
('color', ''),
|
547 |
+
('fontname', 'Century Gothic'),
|
548 |
+
('font-size', '20px'),
|
549 |
+
('font-style', 'italic'),
|
550 |
+
('font-weight', ''),
|
551 |
+
('text-align', 'centre'),
|
552 |
+
]
|
553 |
+
|
554 |
+
},{'selector' :'th', 'props':[('text-align', 'center'),('Height','px'),('color','black'),(
|
555 |
+
'border', '1px black solid !important')]},{'selector' :'td', 'props':[('text-align', 'center'),('font-size', '18px'),('color','black')]}],overwrite=False).set_properties(
|
556 |
+
**{'background-color':'White','index':'White','min-width':'150px'},overwrite=False).set_table_styles(
|
557 |
+
[{'selector': 'th:first-child', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
558 |
+
[{'selector': 'tr:first-child', 'props': [('background-color', 'white')]}],overwrite=False).set_table_styles(
|
559 |
+
[{'selector': 'tr', 'props': [('line-height', '20px')]}],overwrite=False).set_properties(
|
560 |
+
**{'Height': '8px'},**{'text-align': 'center'},overwrite=False).set_properties(
|
561 |
+
**{'background-color':'#4285F4'},subset=off_b2b_df.columns[0]).set_properties(
|
562 |
+
**{'background-color':'white'},subset=off_b2b_df.columns[1]).set_properties(
|
563 |
+
**{'background-color':'#FBBC04'},subset=off_b2b_df.columns[2]).set_properties(
|
564 |
+
**{'color':'black'},subset=off_b2b_df.columns[:]).hide_index().set_table_styles([
|
565 |
+
{'selector': 'thead', 'props': [('display', 'none')]}
|
566 |
+
]).set_properties(**{'border': '3 px','color':'black'},overwrite=False).set_properties(
|
567 |
+
**{'border': '1px black solid !important'},subset = ((list(off_b2b_df.index[:]),off_b2b_df.columns[:]))).set_properties(
|
568 |
+
**{'min-width':'130'},subset = ((list(off_b2b_df.index[:]),off_b2b_df.columns[:])),overwrite=False).set_properties(**{
|
569 |
+
'color': 'black'},overwrite=False).set_properties(
|
570 |
+
**{'border': '1px black solid !important'},subset = ((list(off_b2b_df.index[:]),off_b2b_df.columns[:]))) .format(
|
571 |
+
"{:+.0%}")
|
572 |
+
|
573 |
+
|
574 |
+
return off_b2b_df_style
|
575 |
+
# test = test.fillna(0)
|
576 |
+
#test['PP TOI'] = ["%d:%02d" % (int(x),(x*60)%60) if x>0 else '0:00' for x in test['PP TOI']]
|
577 |
+
|
578 |
+
|
579 |
+
app = App(ui.page_fluid(
|
580 |
+
# ui.tags.base(href=base_url),
|
581 |
+
ui.tags.div(
|
582 |
+
{"style": "width:90%;margin: 0 auto;max-width: 1600px;"},
|
583 |
+
ui.tags.style(
|
584 |
+
"""
|
585 |
+
h4 {
|
586 |
+
margin-top: 1em;font-size:35px;
|
587 |
+
}
|
588 |
+
h2{
|
589 |
+
font-size:25px;
|
590 |
+
}
|
591 |
+
"""
|
592 |
+
),
|
593 |
+
shinyswatch.theme.simplex(),
|
594 |
+
ui.tags.h4("TJStats"),
|
595 |
+
ui.tags.i("Baseball Analytics and Visualizations"),
|
596 |
+
ui.markdown("""<a href='https://www.patreon.com/tj_stats'>Support me on Patreon for Access to 2024 Apps</a><sup>1</sup>"""),
|
597 |
+
|
598 |
+
ui.navset_tab(
|
599 |
+
ui.nav_control(
|
600 |
+
ui.a(
|
601 |
+
"Home",
|
602 |
+
href="https://nesticot-tjstats-site.hf.space/home/"
|
603 |
+
),
|
604 |
+
),
|
605 |
+
ui.nav_menu(
|
606 |
+
"Batter Charts",
|
607 |
+
ui.nav_control(
|
608 |
+
ui.a(
|
609 |
+
"Batting Rolling",
|
610 |
+
href="https://nesticot-tjstats-site-rolling-batter.hf.space/"
|
611 |
+
),
|
612 |
+
ui.a(
|
613 |
+
"Spray",
|
614 |
+
href="https://nesticot-tjstats-site-spray.hf.space/"
|
615 |
+
),
|
616 |
+
ui.a(
|
617 |
+
"Decision Value",
|
618 |
+
href="https://nesticot-tjstats-site-decision-value.hf.space/"
|
619 |
+
),
|
620 |
+
ui.a(
|
621 |
+
"Damage Model",
|
622 |
+
href="https://nesticot-tjstats-site-damage.hf.space/"
|
623 |
+
),
|
624 |
+
ui.a(
|
625 |
+
"Batter Scatter",
|
626 |
+
href="https://nesticot-tjstats-site-batter-scatter.hf.space/"
|
627 |
+
),
|
628 |
+
ui.a(
|
629 |
+
"EV vs LA Plot",
|
630 |
+
href="https://nesticot-tjstats-site-ev-angle.hf.space/"
|
631 |
+
),
|
632 |
+
ui.a(
|
633 |
+
"Statcast Compare",
|
634 |
+
href="https://nesticot-tjstats-site-statcast-compare.hf.space/"
|
635 |
+
),
|
636 |
+
ui.a(
|
637 |
+
"MLB/MiLB Cards",
|
638 |
+
href="https://nesticot-tjstats-site-mlb-cards.hf.space/"
|
639 |
+
)
|
640 |
+
),
|
641 |
+
),
|
642 |
+
ui.nav_menu(
|
643 |
+
"Pitcher Charts",
|
644 |
+
ui.nav_control(
|
645 |
+
ui.a(
|
646 |
+
"Pitcher Rolling",
|
647 |
+
href="https://nesticot-tjstats-site-rolling-pitcher.hf.space/"
|
648 |
+
),
|
649 |
+
ui.a(
|
650 |
+
"Pitcher Summary",
|
651 |
+
href="https://nesticot-tjstats-site-pitching-summary-graphic-new.hf.space/"
|
652 |
+
),
|
653 |
+
ui.a(
|
654 |
+
"Pitcher Scatter",
|
655 |
+
href="https://nesticot-tjstats-site-pitcher-scatter.hf.space"
|
656 |
+
)
|
657 |
+
),
|
658 |
+
)), ui.row(
|
659 |
+
ui.layout_sidebar(
|
660 |
+
|
661 |
+
|
662 |
+
|
663 |
+
ui.panel_sidebar(
|
664 |
+
#ui.input_date_range("date_range_id", "Date range input",start = statcast_df.game_date.min(), end = statcast_df.game_date.max()),
|
665 |
+
ui.input_select("player_id", "Select Player 1",player_dict,width=1,size=1,selectize=True,multiple=False,selected=592450),
|
666 |
+
ui.input_select("player_id_2", "Select Player 2 (For Player Compare Tab)",player_dict,width=1,size=1,selectize=True,multiple=False,selected=592450),
|
667 |
+
ui.input_numeric("season_1", "Season 1", value=2022,min=2015,max=2023),
|
668 |
+
ui.input_numeric("season_2", "Season 2", value=2023,min=2015,max=2023),
|
669 |
+
ui.input_select("row_select", "Select Stats",
|
670 |
+
column_dict,width=1,size=1,selectize=True,
|
671 |
+
multiple=True,
|
672 |
+
selected=['k_percent','bb_percent','woba','xwoba','iz_contact_percent','oz_swing_percent','whiff_percent']),
|
673 |
+
ui.input_action_button("go", "Generate",class_="btn-primary",
|
674 |
+
)),
|
675 |
+
|
676 |
+
ui.panel_main(ui.tags.h3(""),
|
677 |
+
ui.navset_tab(
|
678 |
+
ui.nav("Single Player",
|
679 |
+
ui.div({"style": "font-size:2.1em;"},ui.output_text("txt_title")),
|
680 |
+
#ui.tags.h2("Fantasy Hockey Schedule Summary"),
|
681 |
+
ui.tags.h5("Created By: @TJStats, Data: MLB"),
|
682 |
+
#ui.div({"style": "font-size:1.6em;"},ui.output_text("txt")),
|
683 |
+
ui.output_table("statcast_compare"),
|
684 |
+
#ui.tags.h5('Legend'),
|
685 |
+
ui.tags.h3(""),
|
686 |
+
ui.tags.h5('Colour Scale:'),
|
687 |
+
ui.output_table("colour_scale"),
|
688 |
+
ui.div({"style": "font-size:1em;"},ui.output_text("text_2022")),
|
689 |
+
ui.div({"style": "font-size:1em;"},ui.output_text("text_2023")),
|
690 |
+
ui.div({"style": "font-size:1em;"},ui.output_text("text_diff"))),
|
691 |
+
|
692 |
+
ui.nav("Player Compare",
|
693 |
+
ui.div({"style": "font-size:2.1em;"},ui.output_text("txt_title_compare")),
|
694 |
+
#ui.tags.h2("Fantasy Hockey Schedule Summary"),
|
695 |
+
ui.tags.h5("Created By: @TJStats, Data: MLB"),
|
696 |
+
#ui.div({"style": "font-size:1.6em;"},ui.output_text("txt")),
|
697 |
+
ui.output_table("statcast_compare_2"),
|
698 |
+
ui.tags.h3(""),
|
699 |
+
ui.tags.h5('Colour Scale:'),
|
700 |
+
ui.output_table("colour_scale_2"),
|
701 |
+
ui.div({"style": "font-size:1em;"},ui.output_text("text_2022_1")),
|
702 |
+
ui.div({"style": "font-size:1em;"},ui.output_text("text_2023_1")),
|
703 |
+
ui.div({"style": "font-size:1em;"},ui.output_text("text_diff_compare")))
|
704 |
+
)
|
705 |
+
),
|
706 |
+
)),)),server)
|