nesticot commited on
Commit
e31db8f
·
verified ·
1 Parent(s): fa88613

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +294 -292
app.py CHANGED
@@ -1,293 +1,295 @@
1
- import polars as pl
2
- import numpy as np
3
- import pandas as pd
4
- import api_scraper
5
- scrape = api_scraper.MLB_Scrape()
6
- from functions import df_update
7
- from functions import pitch_summary_functions
8
- update = df_update.df_update()
9
- from stuff_model import feature_engineering as fe
10
- from stuff_model import stuff_apply
11
- import requests
12
- import joblib
13
- from matplotlib.gridspec import GridSpec
14
- from shiny import App, reactive, ui, render
15
- from shiny.ui import h2, tags
16
- import matplotlib.pyplot as plt
17
- import matplotlib.gridspec as gridspec
18
- import seaborn as sns
19
- from functions.pitch_summary_functions import *
20
-
21
- colour_palette = ['#FFB000','#648FFF','#785EF0',
22
- '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
23
-
24
-
25
- year_list = [2017,2018,2019,2020,2021,2022,2023,2024]
26
-
27
-
28
-
29
- level_dict = {'1':'MLB',
30
- '11':'AAA',
31
- '12':'AA',
32
- '13':'A+',
33
- '14':'A',
34
- '17':'AFL',
35
- '22':'College',
36
- '21':'Prospects',
37
- '51':'International' }
38
-
39
- function_dict={
40
- 'velocity_kdes':'Velocity Distributions',
41
- 'break_plot':'Pitch Movement',
42
- 'tj_stuff_roling':'Rolling tjStuff+ by Pitch',
43
- 'tj_stuff_roling_game':'Rolling tjStuff+ by Game',
44
- 'location_plot_lhb':'Locations vs LHB',
45
- 'location_plot_rhb':'Locations vs RHB',
46
- }
47
-
48
-
49
- split_dict = {'all':'All',
50
- 'left':'LHH',
51
- 'right':'RHH'}
52
-
53
- split_dict_hand = {'all':['L','R'],
54
- 'left':['L'],
55
- 'right':['R']}
56
-
57
- from shiny import App, reactive, ui, render
58
- from shiny.ui import h2, tags
59
-
60
- # Define the UI layout for the app
61
- app_ui = ui.page_fluid(
62
- ui.layout_sidebar(
63
- ui.panel_sidebar(
64
- # Row for selecting season and level
65
- ui.row(
66
- ui.column(6, ui.input_select('year_input', 'Select Season', year_list, selected=2024)),
67
- ui.column(6, ui.input_select('level_input', 'Select Level', level_dict))
68
- ),
69
- # Row for the action button to get player list
70
- ui.row(ui.input_action_button("player_button", "Get Player List", class_="btn-primary")),
71
- # Row for selecting the player
72
- ui.row(ui.column(12, ui.output_ui('player_select_ui', 'Select Player'))),
73
- # Row for selecting the date range
74
- ui.row(ui.column(12, ui.output_ui('date_id', 'Select Date'))),
75
-
76
- # Rows for selecting plots and split options
77
- ui.row(
78
- ui.column(4, ui.input_select('plot_id_1', 'Plot Left', function_dict, multiple=False, selected='velocity_kdes')),
79
- ui.column(4, ui.input_select('plot_id_2', 'Plot Middle', function_dict, multiple=False, selected='tj_stuff_roling')),
80
- ui.column(4, ui.input_select('plot_id_3', 'Plot Right', function_dict, multiple=False, selected='break_plot'))
81
- ),
82
- ui.row(
83
- ui.column(6, ui.input_select('split_id', 'Select Split', split_dict, multiple=False)),
84
- ui.column(6, ui.input_numeric('rolling_window', 'Rolling Window (for tjStuff+ Plot)', min=1, value=50))
85
- ),
86
-
87
- # Row for the action button to generate plot
88
- ui.row(ui.input_action_button("generate_plot", "Generate Plot", class_="btn-primary"))
89
- ),
90
-
91
- ui.panel_main(
92
- ui.navset_tab(
93
- # Tab for game summary plot
94
- ui.nav("Pitching Summary",
95
- ui.output_text("status"),
96
- ui.output_plot('plot', width='2100px', height='2100px')
97
- ),
98
- )
99
- )
100
- )
101
- )
102
-
103
-
104
- def server(input, output, session):
105
-
106
- @reactive.calc
107
- @reactive.event(input.pitcher_id, input.date_id,input.split_id)
108
- def cached_data():
109
-
110
- year_input = int(input.year_input())
111
- sport_id = int(input.level_input())
112
- player_input = int(input.pitcher_id())
113
- start_date = str(input.date_id()[0])
114
- end_date = str(input.date_id()[1])
115
- # Simulate an expensive data operation
116
- game_list = scrape.get_player_games_list(sport_id = sport_id,
117
- season = year_input,
118
- player_id = player_input,
119
- start_date = start_date,
120
- end_date = end_date)
121
-
122
- data_list = scrape.get_data(game_list_input = game_list[:])
123
- df = (stuff_apply.stuff_apply(fe.feature_engineering(update.update(scrape.get_data_df(data_list = data_list).filter(
124
- (pl.col("pitcher_id") == player_input)&
125
- (pl.col("is_pitch") == True)&
126
- (pl.col('batter_hand').is_in(split_dict_hand[input.split_id()]))
127
-
128
- )))).with_columns(
129
- pl.col('pitch_type').count().over('pitch_type').alias('pitch_count')
130
- ))
131
- return df
132
-
133
- @render.ui
134
- @reactive.event(input.player_button, ignore_none=False)
135
- def player_select_ui():
136
- # Get the list of pitchers for the selected level and season
137
- df_pitcher_info = scrape.get_players(sport_id=int(input.level_input()), season=int(input.year_input())).filter(
138
- pl.col("position").is_in(['P'])).sort("name")
139
-
140
- # Create a dictionary of pitcher IDs and names
141
- pitcher_dict = dict(zip(df_pitcher_info['player_id'], df_pitcher_info['name']))
142
-
143
- # Return a select input for choosing a pitcher
144
- return ui.input_select("pitcher_id", "Select Pitcher", pitcher_dict, selectize=True)
145
-
146
- @render.ui
147
- @reactive.event(input.player_button, ignore_none=False)
148
- def date_id():
149
- # Create a date range input for selecting the date range within the selected year
150
- return ui.input_date_range("date_id", "Select Date Range",
151
- start=f"{int(input.year_input())}-01-01",
152
- end=f"{int(input.year_input())}-12-31",
153
- min=f"{int(input.year_input())}-01-01",
154
- max=f"{int(input.year_input())}-12-31")
155
- @output
156
- @render.text
157
- def status():
158
- # Only show status when generating
159
- if input.generate == 0:
160
- return ""
161
- return ""
162
-
163
- @output
164
- @render.plot
165
- @reactive.event(input.generate_plot, ignore_none=False)
166
- def plot():
167
- # Show progress/loading notification
168
- with ui.Progress(min=0, max=1) as p:
169
- p.set(message="Generating plot", detail="This may take a while...")
170
-
171
-
172
- p.set(0.3, "Gathering data...")
173
- year_input = int(input.year_input())
174
- sport_id = int(input.level_input())
175
- player_input = int(input.pitcher_id())
176
- start_date = str(input.date_id()[0])
177
- end_date = str(input.date_id()[1])
178
-
179
- print(year_input, sport_id, player_input, start_date, end_date)
180
-
181
-
182
- # game_list = scrape.get_player_games_list(sport_id = sport_id,
183
- # season = year_input,
184
- # player_id = player_input,
185
- # start_date = start_date,
186
- # end_date = end_date)
187
-
188
- # data_list = scrape.get_data(game_list_input = game_list[:])
189
- # df = stuff_apply.stuff_apply(fe.feature_engineering(update.update(scrape.get_data_df(data_list = data_list).filter(
190
- # (pl.col("pitcher_id") == player_input)&
191
- # (pl.col("is_pitch") == True))))).with_columns(
192
- # pl.col('pitch_type').count().over('pitch_type').alias('pitch_count')
193
- # )
194
-
195
- df = cached_data()
196
- df = df.clone()
197
-
198
- p.set(0.6, "Creating plot...")
199
-
200
-
201
- #plt.rcParams["figure.figsize"] = [10,10]
202
- fig = plt.figure(figsize=(26,26))
203
- plt.rcParams.update({'figure.autolayout': True})
204
- fig.set_facecolor('white')
205
- sns.set_theme(style="whitegrid", palette=colour_palette)
206
- print('this is the one plot')
207
-
208
- gs = gridspec.GridSpec(6, 8,
209
- height_ratios=[5,20,12,36,36,7],
210
- width_ratios=[4,18,18,18,18,18,18,4])
211
-
212
-
213
- gs.update(hspace=0.2, wspace=0.5)
214
-
215
- # Define the positions of each subplot in the grid
216
- ax_headshot = fig.add_subplot(gs[1,1:3])
217
- ax_bio = fig.add_subplot(gs[1,3:5])
218
- ax_logo = fig.add_subplot(gs[1,5:7])
219
-
220
- ax_season_table = fig.add_subplot(gs[2,1:7])
221
-
222
- ax_plot_1 = fig.add_subplot(gs[3,1:3])
223
- ax_plot_2 = fig.add_subplot(gs[3,3:5])
224
- ax_plot_3 = fig.add_subplot(gs[3,5:7])
225
-
226
- ax_table = fig.add_subplot(gs[4,1:7])
227
-
228
- ax_footer = fig.add_subplot(gs[-1,1:7])
229
- ax_header = fig.add_subplot(gs[0,1:7])
230
- ax_left = fig.add_subplot(gs[:,0])
231
- ax_right = fig.add_subplot(gs[:,-1])
232
-
233
- # Hide axes for footer, header, left, and right
234
- ax_footer.axis('off')
235
- ax_header.axis('off')
236
- ax_left.axis('off')
237
- ax_right.axis('off')
238
-
239
- sns.set_theme(style="whitegrid", palette=colour_palette)
240
- fig.set_facecolor('white')
241
-
242
- df_teams = scrape.get_teams()
243
-
244
- player_headshot(player_input=player_input, ax=ax_headshot,sport_id=sport_id,season=year_input)
245
- player_bio(pitcher_id=player_input, ax=ax_bio,sport_id=sport_id,year_input=year_input)
246
- plot_logo(pitcher_id=player_input, ax=ax_logo, df_team=df_teams,df_players=scrape.get_players(sport_id,year_input))
247
-
248
- stat_summary_table(df=df,
249
- ax=ax_season_table,
250
- player_input=player_input,
251
- split=split_dict[input.split_id()],
252
- sport_id=sport_id)
253
-
254
- # break_plot(df=df_plot,ax=ax2)
255
- for x,y,z in zip([input.plot_id_1(),input.plot_id_2(),input.plot_id_3()],[ax_plot_1,ax_plot_2,ax_plot_3],[1,3,5]):
256
- if x == 'velocity_kdes':
257
- velocity_kdes(df,
258
- ax=y,
259
- gs=gs,
260
- gs_x=[3,4],
261
- gs_y=[z,z+2],
262
- fig=fig)
263
- if x == 'tj_stuff_roling':
264
- tj_stuff_roling(df=df,
265
- window=int(input.rolling_window()),
266
- ax=y)
267
-
268
- if x == 'tj_stuff_roling_game':
269
- tj_stuff_roling_game(df=df,
270
- window=int(input.rolling_window()),
271
- ax=y)
272
-
273
- if x == 'break_plot':
274
- break_plot(df = df,ax=y)
275
-
276
- if x == 'location_plot_lhb':
277
- location_plot(df = df,ax=y,hand='L')
278
-
279
- if x == 'location_plot_rhb':
280
- location_plot(df = df,ax=y,hand='R')
281
-
282
- summary_table(df=df,
283
- ax=ax_table)
284
-
285
- plot_footer(ax_footer)
286
-
287
- fig.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01)
288
-
289
-
290
-
291
-
292
-
 
 
293
  app = App(app_ui, server)
 
1
+ import polars as pl
2
+ import numpy as np
3
+ import pandas as pd
4
+ import api_scraper
5
+ scrape = api_scraper.MLB_Scrape()
6
+ from functions import df_update
7
+ from functions import pitch_summary_functions
8
+ update = df_update.df_update()
9
+ from stuff_model import feature_engineering as fe
10
+ from stuff_model import stuff_apply
11
+ import requests
12
+ import joblib
13
+ from matplotlib.gridspec import GridSpec
14
+ from shiny import App, reactive, ui, render
15
+ from shiny.ui import h2, tags
16
+ import matplotlib.pyplot as plt
17
+ import matplotlib.gridspec as gridspec
18
+ import seaborn as sns
19
+ from functions.pitch_summary_functions import *
20
+ from shiny import App, reactive, ui, render
21
+ from shiny.ui import h2, tags
22
+
23
+ colour_palette = ['#FFB000','#648FFF','#785EF0',
24
+ '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
25
+
26
+
27
+ year_list = [2017,2018,2019,2020,2021,2022,2023,2024]
28
+
29
+
30
+
31
+ level_dict = {'1':'MLB',
32
+ '11':'AAA',
33
+ '12':'AA',
34
+ '13':'A+',
35
+ '14':'A',
36
+ '17':'AFL',
37
+ '22':'College',
38
+ '21':'Prospects',
39
+ '51':'International' }
40
+
41
+ function_dict={
42
+ 'velocity_kdes':'Velocity Distributions',
43
+ 'break_plot':'Pitch Movement',
44
+ 'tj_stuff_roling':'Rolling tjStuff+ by Pitch',
45
+ 'tj_stuff_roling_game':'Rolling tjStuff+ by Game',
46
+ 'location_plot_lhb':'Locations vs LHB',
47
+ 'location_plot_rhb':'Locations vs RHB',
48
+ }
49
+
50
+
51
+ split_dict = {'all':'All',
52
+ 'left':'LHH',
53
+ 'right':'RHH'}
54
+
55
+ split_dict_hand = {'all':['L','R'],
56
+ 'left':['L'],
57
+ 'right':['R']}
58
+
59
+ from shiny import App, reactive, ui, render
60
+ from shiny.ui import h2, tags
61
+
62
+ # Define the UI layout for the app
63
+ app_ui = ui.page_fluid(
64
+ ui.layout_sidebar(
65
+ ui.panel_sidebar(
66
+ # Row for selecting season and level
67
+ ui.row(
68
+ ui.column(6, ui.input_select('year_input', 'Select Season', year_list, selected=2024)),
69
+ ui.column(6, ui.input_select('level_input', 'Select Level', level_dict))
70
+ ),
71
+ # Row for the action button to get player list
72
+ ui.row(ui.input_action_button("player_button", "Get Player List", class_="btn-primary")),
73
+ # Row for selecting the player
74
+ ui.row(ui.column(12, ui.output_ui('player_select_ui', 'Select Player'))),
75
+ # Row for selecting the date range
76
+ ui.row(ui.column(12, ui.output_ui('date_id', 'Select Date'))),
77
+
78
+ # Rows for selecting plots and split options
79
+ ui.row(
80
+ ui.column(4, ui.input_select('plot_id_1', 'Plot Left', function_dict, multiple=False, selected='velocity_kdes')),
81
+ ui.column(4, ui.input_select('plot_id_2', 'Plot Middle', function_dict, multiple=False, selected='tj_stuff_roling')),
82
+ ui.column(4, ui.input_select('plot_id_3', 'Plot Right', function_dict, multiple=False, selected='break_plot'))
83
+ ),
84
+ ui.row(
85
+ ui.column(6, ui.input_select('split_id', 'Select Split', split_dict, multiple=False)),
86
+ ui.column(6, ui.input_numeric('rolling_window', 'Rolling Window (for tjStuff+ Plot)', min=1, value=50))
87
+ ),
88
+
89
+ # Row for the action button to generate plot
90
+ ui.row(ui.input_action_button("generate_plot", "Generate Plot", class_="btn-primary"))
91
+ ),
92
+
93
+ ui.panel_main(
94
+ ui.navset_tab(
95
+ # Tab for game summary plot
96
+ ui.nav("Pitching Summary",
97
+ ui.output_text("status"),
98
+ ui.output_plot('plot', width='2100px', height='2100px')
99
+ ),
100
+ )
101
+ )
102
+ )
103
+ )
104
+
105
+
106
+ def server(input, output, session):
107
+
108
+ @reactive.calc
109
+ @reactive.event(input.pitcher_id, input.date_id,input.split_id)
110
+ def cached_data():
111
+
112
+ year_input = int(input.year_input())
113
+ sport_id = int(input.level_input())
114
+ player_input = int(input.pitcher_id())
115
+ start_date = str(input.date_id()[0])
116
+ end_date = str(input.date_id()[1])
117
+ # Simulate an expensive data operation
118
+ game_list = scrape.get_player_games_list(sport_id = sport_id,
119
+ season = year_input,
120
+ player_id = player_input,
121
+ start_date = start_date,
122
+ end_date = end_date)
123
+
124
+ data_list = scrape.get_data(game_list_input = game_list[:])
125
+ df = (stuff_apply.stuff_apply(fe.feature_engineering(update.update(scrape.get_data_df(data_list = data_list).filter(
126
+ (pl.col("pitcher_id") == player_input)&
127
+ (pl.col("is_pitch") == True)&
128
+ (pl.col('batter_hand').is_in(split_dict_hand[input.split_id()]))
129
+
130
+ )))).with_columns(
131
+ pl.col('pitch_type').count().over('pitch_type').alias('pitch_count')
132
+ ))
133
+ return df
134
+
135
+ @render.ui
136
+ @reactive.event(input.player_button, ignore_none=False)
137
+ def player_select_ui():
138
+ # Get the list of pitchers for the selected level and season
139
+ df_pitcher_info = scrape.get_players(sport_id=int(input.level_input()), season=int(input.year_input())).filter(
140
+ pl.col("position").is_in(['P'])).sort("name")
141
+
142
+ # Create a dictionary of pitcher IDs and names
143
+ pitcher_dict = dict(zip(df_pitcher_info['player_id'], df_pitcher_info['name']))
144
+
145
+ # Return a select input for choosing a pitcher
146
+ return ui.input_select("pitcher_id", "Select Pitcher", pitcher_dict, selectize=True)
147
+
148
+ @render.ui
149
+ @reactive.event(input.player_button, ignore_none=False)
150
+ def date_id():
151
+ # Create a date range input for selecting the date range within the selected year
152
+ return ui.input_date_range("date_id", "Select Date Range",
153
+ start=f"{int(input.year_input())}-01-01",
154
+ end=f"{int(input.year_input())}-12-31",
155
+ min=f"{int(input.year_input())}-01-01",
156
+ max=f"{int(input.year_input())}-12-31")
157
+ @output
158
+ @render.text
159
+ def status():
160
+ # Only show status when generating
161
+ if input.generate == 0:
162
+ return ""
163
+ return ""
164
+
165
+ @output
166
+ @render.plot
167
+ @reactive.event(input.generate_plot, ignore_none=False)
168
+ def plot():
169
+ # Show progress/loading notification
170
+ with ui.Progress(min=0, max=1) as p:
171
+ p.set(message="Generating plot", detail="This may take a while...")
172
+
173
+
174
+ p.set(0.3, "Gathering data...")
175
+ year_input = int(input.year_input())
176
+ sport_id = int(input.level_input())
177
+ player_input = int(input.pitcher_id())
178
+ start_date = str(input.date_id()[0])
179
+ end_date = str(input.date_id()[1])
180
+
181
+ print(year_input, sport_id, player_input, start_date, end_date)
182
+
183
+
184
+ # game_list = scrape.get_player_games_list(sport_id = sport_id,
185
+ # season = year_input,
186
+ # player_id = player_input,
187
+ # start_date = start_date,
188
+ # end_date = end_date)
189
+
190
+ # data_list = scrape.get_data(game_list_input = game_list[:])
191
+ # df = stuff_apply.stuff_apply(fe.feature_engineering(update.update(scrape.get_data_df(data_list = data_list).filter(
192
+ # (pl.col("pitcher_id") == player_input)&
193
+ # (pl.col("is_pitch") == True))))).with_columns(
194
+ # pl.col('pitch_type').count().over('pitch_type').alias('pitch_count')
195
+ # )
196
+
197
+ df = cached_data()
198
+ df = df.clone()
199
+
200
+ p.set(0.6, "Creating plot...")
201
+
202
+
203
+ #plt.rcParams["figure.figsize"] = [10,10]
204
+ fig = plt.figure(figsize=(26,26))
205
+ plt.rcParams.update({'figure.autolayout': True})
206
+ fig.set_facecolor('white')
207
+ sns.set_theme(style="whitegrid", palette=colour_palette)
208
+ print('this is the one plot')
209
+
210
+ gs = gridspec.GridSpec(6, 8,
211
+ height_ratios=[5,20,12,36,36,7],
212
+ width_ratios=[4,18,18,18,18,18,18,4])
213
+
214
+
215
+ gs.update(hspace=0.2, wspace=0.5)
216
+
217
+ # Define the positions of each subplot in the grid
218
+ ax_headshot = fig.add_subplot(gs[1,1:3])
219
+ ax_bio = fig.add_subplot(gs[1,3:5])
220
+ ax_logo = fig.add_subplot(gs[1,5:7])
221
+
222
+ ax_season_table = fig.add_subplot(gs[2,1:7])
223
+
224
+ ax_plot_1 = fig.add_subplot(gs[3,1:3])
225
+ ax_plot_2 = fig.add_subplot(gs[3,3:5])
226
+ ax_plot_3 = fig.add_subplot(gs[3,5:7])
227
+
228
+ ax_table = fig.add_subplot(gs[4,1:7])
229
+
230
+ ax_footer = fig.add_subplot(gs[-1,1:7])
231
+ ax_header = fig.add_subplot(gs[0,1:7])
232
+ ax_left = fig.add_subplot(gs[:,0])
233
+ ax_right = fig.add_subplot(gs[:,-1])
234
+
235
+ # Hide axes for footer, header, left, and right
236
+ ax_footer.axis('off')
237
+ ax_header.axis('off')
238
+ ax_left.axis('off')
239
+ ax_right.axis('off')
240
+
241
+ sns.set_theme(style="whitegrid", palette=colour_palette)
242
+ fig.set_facecolor('white')
243
+
244
+ df_teams = scrape.get_teams()
245
+
246
+ player_headshot(player_input=player_input, ax=ax_headshot,sport_id=sport_id,season=year_input)
247
+ player_bio(pitcher_id=player_input, ax=ax_bio,sport_id=sport_id,year_input=year_input)
248
+ plot_logo(pitcher_id=player_input, ax=ax_logo, df_team=df_teams,df_players=scrape.get_players(sport_id,year_input))
249
+
250
+ stat_summary_table(df=df,
251
+ ax=ax_season_table,
252
+ player_input=player_input,
253
+ split=input.split_id(),
254
+ sport_id=sport_id)
255
+
256
+ # break_plot(df=df_plot,ax=ax2)
257
+ for x,y,z in zip([input.plot_id_1(),input.plot_id_2(),input.plot_id_3()],[ax_plot_1,ax_plot_2,ax_plot_3],[1,3,5]):
258
+ if x == 'velocity_kdes':
259
+ velocity_kdes(df,
260
+ ax=y,
261
+ gs=gs,
262
+ gs_x=[3,4],
263
+ gs_y=[z,z+2],
264
+ fig=fig)
265
+ if x == 'tj_stuff_roling':
266
+ tj_stuff_roling(df=df,
267
+ window=int(input.rolling_window()),
268
+ ax=y)
269
+
270
+ if x == 'tj_stuff_roling_game':
271
+ tj_stuff_roling_game(df=df,
272
+ window=int(input.rolling_window()),
273
+ ax=y)
274
+
275
+ if x == 'break_plot':
276
+ break_plot(df = df,ax=y)
277
+
278
+ if x == 'location_plot_lhb':
279
+ location_plot(df = df,ax=y,hand='L')
280
+
281
+ if x == 'location_plot_rhb':
282
+ location_plot(df = df,ax=y,hand='R')
283
+
284
+ summary_table(df=df,
285
+ ax=ax_table)
286
+
287
+ plot_footer(ax_footer)
288
+
289
+ fig.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01)
290
+
291
+
292
+
293
+
294
+
295
  app = App(app_ui, server)