nesticot commited on
Commit
ebf2faa
1 Parent(s): 043aa15

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +287 -436
app.py CHANGED
@@ -1,501 +1,352 @@
 
1
  import pandas as pd
2
- import seaborn as sns
3
- import matplotlib.pyplot as plt
4
- from matplotlib.pyplot import figure
5
- from matplotlib.offsetbox import OffsetImage, AnnotationBbox
6
- from scipy import stats
7
- import pickle
8
- import json
9
- from datetime import timedelta
10
- from urllib.request import urlopen
11
- from datetime import date
12
  from datetime import datetime
13
- import pytz
14
- import json
15
- from matplotlib.ticker import MaxNLocator
16
- import matplotlib.font_manager as font_manager
17
  import numpy as np
18
-
19
- # team_games_df = pd.read_csv('data/team_games_all.csv',index_col=[0])
20
- # player_games_df = pd.read_csv('data/player_games_cards.csv',index_col=[0]).sort_values(by='date').reset_index(drop=True)
21
- team_abv_nst = pd.read_csv('data/team_abv_nst.csv')
22
- #player_games_df = player_games_df.loc[:, ~player_games_df.columns.str.contains('^Unnamed')]
23
- #team_abv = pd.read_csv('team_abv.csv')
24
- #team_games_df = team_games_df.merge(right=team_abv,left_on='team',right_on='team_name',how='left').drop(columns='team_name')
25
- team_abv = pd.read_csv('data/team_abv.csv')
26
-
27
- import pickle
28
  from datetime import timedelta
 
 
 
 
 
 
29
 
30
- # # Loop over the counter and format the API call
31
- # r = requests.get('https://statsapi.web.nhl.com/api/v1/schedule?startDate=2022-10-01&endDate=2023-06-01')
32
- # schedule = r.json()
33
-
34
- schedule = json.loads(urlopen('https://statsapi.web.nhl.com/api/v1/schedule?startDate=2023-10-07&endDate=2024-04-19').read())
35
-
36
- def flatten(t):
37
- return [item for sublist in t for item in sublist]
38
-
39
- game_id = flatten([[x['gamePk'] for x in schedule['dates'][y]['games']] for y in range(0,len(schedule['dates']))])
40
- game_type = flatten([[x['gameType'] for x in schedule['dates'][y]['games']] for y in range(0,len(schedule['dates']))])
41
- game_date = flatten([[(pd.to_datetime(x['gameDate']) - timedelta(hours=8)) for x in schedule['dates'][y]['games']] for y in range(0,len(schedule['dates']))])
42
- game_final = flatten([[x['status']['detailedState'] for x in schedule['dates'][y]['games']] for y in range(0,len(schedule['dates']))])
43
- game_home = flatten([[x['teams']['home']['team']['name'] for x in schedule['dates'][y]['games']] for y in range(0,len(schedule['dates']))])
44
- game_away = flatten([[x['teams']['away']['team']['name'] for x in schedule['dates'][y]['games']] for y in range(0,len(schedule['dates']))])
45
-
46
- schedule_df = pd.DataFrame(data={'game_id': game_id, 'game_type':game_type,'game_date' : game_date, 'game_home' : game_home, 'game_away' : game_away,'status' : game_final})
47
- schedule_df = schedule_df[schedule_df.game_type == 'R'].reset_index(drop=True)
48
- schedule_df = schedule_df[schedule_df.status != 'Postponed']
49
- schedule_df = schedule_df.replace('Montréal Canadiens','Montreal Canadiens')
50
-
51
-
52
-
53
- schedule_df_merge = schedule_df.merge(right=team_abv,left_on='game_home',right_on='team_name',how='left')
54
- schedule_df_merge = schedule_df_merge.merge(right=team_abv,left_on='game_away',right_on='team_name',how='left')
55
- schedule_df_merge = schedule_df_merge.drop(columns={'team_name_x','team_name_y'})
56
- schedule_df_merge = schedule_df_merge.rename(columns={'team_abv_x' : 'team_abv_home','team_abv_y' : 'team_abv_away'})
57
-
58
-
59
-
60
-
61
- #schedule_df_merge.game_date = pd.to_datetime(schedule_df_merge['game_date']).dt.tz_convert(tz='US/Eastern').dt.date
62
- # schedule_df_merge = schedule_df_merge.set_index(pd.DatetimeIndex(schedule_df_merge.game_date).strftime('%Y-%m-%d'))
63
- schedule_df_merge.index = pd.to_datetime(schedule_df_merge.game_date)
64
- schedule_df_merge = schedule_df_merge.drop(columns='game_date')
65
- #schedule_df_merge.index = schedule_df_merge.index.tz_convert('US/Pacific')
66
- schedule_df_merge.index = schedule_df_merge.index.date
67
- schedule_df_merge = schedule_df_merge.sort_index()
68
- schedule_df_merge = schedule_df_merge[schedule_df_merge.index <= date(2024,5,1)]
69
-
70
- schedule_df_merge_final = schedule_df_merge[schedule_df_merge['status']=='Final']
71
- schedule_ccount_df = pd.DataFrame(data={'date':list(schedule_df_merge_final.index)*2,'team':list(schedule_df_merge_final.team_abv_away)+list(schedule_df_merge_final.team_abv_home)}).sort_values(by='date').reset_index(drop=True)
72
- schedule_ccount_df['team_game'] = schedule_ccount_df.groupby('team').cumcount()+1
73
- schedule_ccount_df.date = pd.to_datetime(schedule_ccount_df.date)
74
-
75
- today = pd.to_datetime(datetime.now(pytz.timezone('US/Pacific')).strftime('%Y-%m-%d'))
76
- team_schdule = schedule_df_merge[(schedule_df_merge['team_abv_home']=='EDM')|(schedule_df_merge['team_abv_away']=='EDM')]
77
- team_schdule_live = team_schdule[team_schdule.index <= today]
78
- team_schdule_live.head()
79
-
80
- team_games_df = pd.read_csv('data/team_games_all.csv',index_col=[0])
81
- player_games_df = pd.read_csv('data/player_games_cards.csv',index_col=[0]).sort_values(by='date').reset_index(drop=True)
82
- team_abv_df = pd.read_csv('data/team_abv.csv')
83
- player_games_df = player_games_df.loc[:, ~player_games_df.columns.str.contains('^Unnamed')]
84
-
85
- team_games_df = team_games_df.merge(right=team_abv_df,left_on='team',right_on='team_name',how='left').drop(columns='team_name')
86
-
87
- player_games_df = player_games_df.drop_duplicates(subset=['player_id','date'],keep='last').reset_index(drop=True)
88
- player_games_df.date = pd.to_datetime(player_games_df.date)
89
- team_games_df = team_games_df[team_games_df['date']=='Final']
90
- schedule_df_merge_final = schedule_df_merge[schedule_df_merge['status']=='Final']
91
- schedule_ccount_df = pd.DataFrame(data={'date':list(schedule_df_merge_final.index)*2,'team':list(schedule_df_merge_final.team_abv_away)+list(schedule_df_merge_final.team_abv_home)}).sort_values(by='date').reset_index(drop=True)
92
- schedule_ccount_df['team_game'] = schedule_ccount_df.groupby('team').cumcount()+1
93
- schedule_ccount_df.date = pd.to_datetime(schedule_ccount_df.date)
94
- team_games_df['team_game'] = team_games_df.groupby('team').cumcount()+1
95
- player_games_df = player_games_df.merge(right=schedule_ccount_df,left_on=['Team','date'],right_on=['team','date'],how='left')
96
- player_games_df['player_game'] = player_games_df.groupby('player_id').cumcount()+1
97
-
98
- date_range_list = pd.date_range(start=player_games_df.date.min()+timedelta(days=6),end=player_games_df.date.max())
99
-
100
-
101
- team_abv_nst_dict = {'All':''} | team_abv_nst.set_index('team_abv')['team_name'].to_dict()
102
-
103
- position_dict = {'All':'','F':'Forwards','D':'Defense'}
104
-
105
- player_games_df = player_games_df.rename(columns={'Total Points_pp':'PP Points'})
106
-
107
- stat_input_list = ['TOI', 'Goals', 'Total Assists',
108
- 'First Assists', 'Total Points', 'PP Points','Shots', 'Hits',
109
- 'Shots Blocked']
110
-
111
-
112
- df_cum_stat_total = player_games_df.groupby(['player_id','Player','Position']).agg(
113
- GP = ('GP','count'),
114
- Total_Points = ('Total Points','sum')
115
- ).reset_index()
116
-
117
- df_all_sort = df_cum_stat_total.copy()
118
- stat_pick = 'Total_Points'
119
- count=11
120
- not_position = ''
121
- team = ''
122
- df_all_sort = df_all_sort[(df_all_sort['Position']!=not_position)]
123
- df_all_sort[stat_pick+' per game'] = df_all_sort[stat_pick]/df_all_sort['GP']
124
- df_all_sort[stat_pick+' Rank'] = df_all_sort[stat_pick].rank(ascending=False,method='min')
125
- df_all_sort = df_all_sort[df_all_sort[stat_pick+' Rank']<=count]
126
- df_all_sort[stat_pick+' per game Rank'] = df_all_sort[stat_pick+' per game'].rank(ascending=False,method='min')
127
- # #df_all_sort.sort_values(by=[stat_pick,stat_pick+' per game','Total Points'],ascending = (False, False,False))
128
- df_all_sort_list = df_all_sort[df_all_sort[stat_pick+' Rank']<max(df_all_sort[stat_pick+' Rank'])].sort_values(by=[stat_pick,stat_pick+' per game','Total_Points'],ascending = (False, False,False))
129
- # # df_all_sort = df_all_sort.sort_values(by=[stat_pick,stat_pick+' per game','Total Points'],ascending = (False, False,False))[(df_all_sort['Position']!=not_position)&(df_all_sort['Team']!=team)].head(count)['Player']
130
- temp_df = df_all_sort[df_all_sort[stat_pick+' Rank']==max(df_all_sort[stat_pick+' Rank'])]#[stat_pick+' per game Rank'].rank().sort_values(ascending=True).reset_index(drop=True)[count-len(df_all_sort_list)-1]
131
- temp_df['temp'] = temp_df[stat_pick+' per game Rank'].rank()#.sort_values(ascending=True)#.reset_index(drop=True)
132
- temp_df = temp_df.sort_values(by='temp',ascending=True)#.reset_index(drop=True)
133
- temp = temp_df[temp_df['temp']<=(count-len(df_all_sort_list))]
134
-
135
- players_list = list(pd.concat([df_all_sort_list,temp]).reset_index(drop=True)['player_id'])
136
-
137
-
138
- rookie_df = pd.read_csv('data/player_rookies.csv',index_col=[0])
139
- rookie_list = rookie_df.player_id.values
140
-
141
 
142
- skater_dict = df_cum_stat_total.sort_values(by=['Total_Points','GP'],ascending=[False,True]).drop_duplicates(subset='player_id').set_index('player_id')#.sort_values(by='Player')
143
- #skater_dict['skater_team'] = skater_dict.Player + ' - ' + skater_dict.Team
144
- skater_dict = skater_dict['Player'].to_dict()
145
- # players_list = list(df_all_sort['Player'])
146
- print(players_list)
147
-
148
-
149
- from shiny import ui, render, App
150
- from shiny import App, reactive, ui
151
- from shiny.ui import h2, tags
152
- import matplotlib.image as mpimg
153
-
154
- # app_ui = ui.page_fluid(
155
-
156
- # # ui.output_plot("plot"),
157
- # #ui.h2('MLB Batter Launch Angle vs Exit Velocity'),
158
- # ui.layout_sidebar(
159
- # ui.panel_sidebar(
160
- # ui.input_select("id", "Select Batter",batter_dict),
161
-
162
- # ui.input_select("plot_id", "Select Plot",{'scatter':'Scatter Plot','dist':'Distribution Plot'})))
163
- # ,
164
-
165
- # ui.panel_main(ui.output_plot("plot",height = "750px",width="1250px")),
166
- # #ui.download_button('test','Download'),
167
- # )
168
- #import shinyswatch
169
  app_ui = ui.page_fluid(
170
- #shinyswatch.theme.cosmo(),
171
  ui.layout_sidebar(
172
-
173
- # Available themes:
174
- # cerulean, cosmo, cyborg, darkly, flatly, journal, litera, lumen, lux,
175
- # materia, minty, morph, pulse, quartz, sandstone, simplex, sketchy, slate,
176
- # solar, spacelab, superhero, united, vapor, yeti, zephyr
177
-
178
- ui.panel_sidebar(
179
- ui.input_select("id", "Select Skater (max. 10 Skaters)",skater_dict,width=1,selected=list(players_list[0:10]),selectize=True,multiple=True),
180
- ui.input_select("stat", "Stat Input",stat_input_list,width=1,size=1,selectize=False,selected='Total Points'),
181
- ui.input_select("team_select", "Team",team_abv_nst_dict,width=1,size=1,selectize=False,selected='All'),
182
- ui.input_select("position_select", "Position",position_dict,width=1,size=1,selectize=False,selected='All'),
183
- ui.input_date("date", "Date input",value = datetime.today().date() - timedelta(days=1),min='2023-10-10', max=datetime.today().date() - timedelta(days=1)),
184
- ui.input_switch("rookie_switch", "Rookies Only"),
185
- ui.output_table("result"),
186
- width=3),
187
-
188
-
189
-
190
- ui.panel_main(
191
-
192
- ui.navset_tab(
193
- ui.nav("Chart Races",
194
- ui.panel_main(
195
- ui.output_plot("plot",height = "1200px",width="1200px")),
196
- )
197
-
198
-
199
-
200
- ))))
201
- # ui.row(
202
- # ui.column(
203
- # 3,
204
- # ui.input_date("x", "Date input"),),
205
- # ui.column(
206
- # 1,
207
- # ui.input_select("level_id", "Select Level",level_dict,width=1)),
208
- # ui.column(
209
- # 3,
210
- # ui.input_select("stat_id", "Select Stat",plot_dict_small,width=1)),
211
- # ui.column(
212
- # 2,
213
- # ui.input_numeric("n", "Rolling Window Size", value=50)),
214
- # ),
215
- # ui.output_table("result_batters")),
216
-
217
- # ui.nav(
218
- # "Pitchers",
219
-
220
- # ui.row(
221
- # ui.column(
222
- # 3,
223
- # ui.input_select("id_pitch", "Select Pitcher",pitcher_dict,width=1,selected=675911),
224
- # ),
225
- # ui.column(
226
- # 1,
227
- # ui.input_select("level_id_pitch", "Select Level",level_dict,width=1)),
228
- # ui.column(
229
- # 3,
230
- # ui.input_select("stat_id_pitch", "Select Stat",plot_dict_small_pitch,width=1)),
231
- # ui.column(
232
- # 2,
233
- # ui.input_numeric("n_pitch", "Rolling Window Size", value=50)),
234
- # ),
235
- # ui.output_table("result_pitchers")),
236
- # )
237
- # )
238
- # )
239
-
240
-
241
-
242
-
243
- #from urllib.request import Request, urlopen
244
-
245
- # importing OpenCV(cv2) module
246
-
247
-
248
-
249
-
250
- def server(input, output, session):
251
-
252
-
253
- @reactive.Effect
254
- def _():
255
-
256
-
257
- team_select_list = [input.team_select()]
258
- position_select_list = [input.position_select()]
259
-
260
- if team_select_list[0] == 'All':
261
- team_select_list = team_abv_nst.team_abv.unique()
262
-
263
- if position_select_list[0] == 'All':
264
- position_select_list = player_games_df.Position.unique()
265
-
266
- elif position_select_list[0] == 'F':
267
- position_select_list = player_games_df[player_games_df.Position != 'D'].Position.unique()
268
-
269
- else:
270
- position_select_list = ['D']
271
 
272
- print(team_select_list)
273
-
 
 
 
 
274
 
275
- if input.rookie_switch():
276
 
277
- df_cum_stat_total = player_games_df[(player_games_df.date <= pd.to_datetime(input.date()))
278
- &(player_games_df.player_id.isin(rookie_list))
279
- &(player_games_df.Team.isin(team_select_list))
280
- &(player_games_df.Position.isin(position_select_list))].groupby(['player_id','Player','Position']).agg(
281
- GP = ('GP','count'),
282
- Total_Points = (f'{input.stat()}','sum')
283
- ).reset_index()
284
-
285
- else:
286
- df_cum_stat_total = player_games_df[(player_games_df.date <= pd.to_datetime(input.date()))
287
- &(player_games_df.Team.isin(team_select_list))
288
- &(player_games_df.Position.isin(position_select_list))].groupby(['player_id','Player','Position']).agg(
289
- GP = ('GP','count'),
290
- Total_Points = (f'{input.stat()}','sum')
291
- ).reset_index()
292
-
293
- df_all_sort = df_cum_stat_total.copy()
294
- stat_pick = 'Total_Points'
295
- count=6
296
- not_position = ''
297
- team = ''
298
- df_all_sort = df_all_sort[(df_all_sort['Position']!=not_position)]
299
- df_all_sort[stat_pick+' per game'] = df_all_sort[stat_pick]/df_all_sort['GP']
300
- df_all_sort[stat_pick+' Rank'] = df_all_sort[stat_pick].rank(ascending=False,method='min')
301
- df_all_sort = df_all_sort[df_all_sort[stat_pick+' Rank']<=count]
302
- df_all_sort[stat_pick+' per game Rank'] = df_all_sort[stat_pick+' per game'].rank(ascending=False,method='min')
303
- # #df_all_sort.sort_values(by=[stat_pick,stat_pick+' per game','Total Points'],ascending = (False, False,False))
304
- df_all_sort_list = df_all_sort[df_all_sort[stat_pick+' Rank']<max(df_all_sort[stat_pick+' Rank'])].sort_values(by=[stat_pick,stat_pick+' per game','Total_Points'],ascending = (False, False,False))
305
- # # df_all_sort = df_all_sort.sort_values(by=[stat_pick,stat_pick+' per game','Total Points'],ascending = (False, False,False))[(df_all_sort['Position']!=not_position)&(df_all_sort['Team']!=team)].head(count)['Player']
306
- temp_df = df_all_sort[df_all_sort[stat_pick+' Rank']==max(df_all_sort[stat_pick+' Rank'])]#[stat_pick+' per game Rank'].rank().sort_values(ascending=True).reset_index(drop=True)[count-len(df_all_sort_list)-1]
307
- temp_df['temp'] = temp_df[stat_pick+' per game Rank'].rank()#.sort_values(ascending=True)#.reset_index(drop=True)
308
- temp_df = temp_df.sort_values(by='temp',ascending=True)#.reset_index(drop=True)
309
- temp = temp_df[temp_df['temp']<=(count-len(df_all_sort_list))]
310
-
311
- players_list_new = list(pd.concat([df_all_sort_list,temp]).reset_index(drop=True)['player_id'])
312
-
313
-
314
- skater_dict = df_cum_stat_total.sort_values(by=['Total_Points','GP'],ascending=[False,True]).drop_duplicates(subset='player_id').set_index('player_id')#.sort_values(by='Player')
315
- #skater_dict['skater_team'] = skater_dict.Player + ' - ' + skater_dict.Team
316
- skater_dict = skater_dict['Player'].to_dict()
317
- # players_list = list(df_all_sort['Player'])
318
-
319
- ui.update_select(
320
- "id",
321
- label="Select Skater (max. 10 Skaters)",
322
- choices=skater_dict,
323
- selected=list(players_list_new[0:10]))
324
-
325
 
326
  @output
327
- @render.table
328
- def result():
329
- if input.rookie_switch():
330
-
331
- return player_games_df[(player_games_df.date <= pd.to_datetime(input.date()))&(player_games_df.player_id.isin(rookie_list))].groupby(['player_id','Player','Position']).agg(
332
- GP = ('GP','count'),
333
- Stat = (f'{input.stat()}','sum')
334
- ).reset_index().sort_values(by=['Stat','GP'],ascending=[False,True]).reset_index(drop=True)
335
-
336
- else:
337
- return player_games_df[player_games_df.date <= pd.to_datetime(input.date())].groupby(['player_id','Player','Position']).agg(
338
- GP = ('GP','count'),
339
- Stat = (f'{input.stat()}','sum')
340
- ).reset_index().sort_values(by=['Stat','GP'],ascending=[False,True]).reset_index(drop=True)
341
 
 
 
 
 
 
 
342
 
343
  @output
344
- @render.plot(alt="A histogram")
345
- def plot():
 
 
 
 
 
 
 
 
 
 
 
 
346
 
 
 
 
 
 
 
347
 
348
- team_select_list = [input.team_select()]
349
- position_select_list = [input.position_select()]
350
 
 
 
 
 
 
351
 
 
 
352
 
353
- if team_select_list[0] == 'All':
354
- team_select_title = 'NHL '
355
- else:
356
- team_select_title = f'{team_abv_nst_dict[team_select_list[0]]} '
357
-
358
 
359
- if position_select_list[0] == 'All':
360
- position_select_title = ''
361
 
362
- elif position_select_list[0] == 'F':
363
- position_select_title = 'Forwards '
364
 
365
- else:
366
- position_select_title = 'Defense '
367
 
368
- rookie = ''
369
- if input.rookie_switch():
370
- rookie = 'Rookie '
371
-
372
- i = 0
373
- #rookie = ''
374
- current_season = '2023'
375
- start_season = '2024'
376
 
377
- # player_lookup_list = ['Connor McDavid','David Pastrnak','Nathan MacKinnon']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
 
379
 
380
- type(input.id())
381
- print(input.id())
382
- player_lookup_list = list(input.id())[0:10]
 
 
383
 
384
- stat = input.stat()
385
- sns.set_theme(style="whitegrid", palette="pastel")
386
- #print(type([input.date()))
387
- date_range_list = [pd.to_datetime(input.date())]
388
- for k in range(len(date_range_list)):
389
- print(date_range_list[k])
390
- stat = input.stat()
391
- team_schedule_url_merge = []
392
- max_games_player = []
393
- max_games_team = []
394
- max_stat = []
395
- per_game = False
396
- for i in range(0,len(player_lookup_list)):
397
- team_schedule_url_merge.append(player_games_df[(player_games_df.player_id == int(player_lookup_list[i]))&(date_range_list[k] >= player_games_df.date)].reset_index(drop=True))
398
- #print('touble',i, player_lookup_list[i],len(player_games_df[(player_games_df.player_id == player_lookup_list[i])]))
399
- team_schedule_url_merge[i].index = team_schedule_url_merge[i].team_game
400
- team_schedule_url_merge[i] = team_schedule_url_merge[i].reindex(np.arange(team_schedule_url_merge[i].team_game.min(), team_schedule_url_merge[i].team_game.max() + 1)).reset_index(drop=True)
401
- #team_schedule_url_merge[0]['team_game'] = team_schedule_url_merge[0]['index']
402
- #team_schedule_url_merge[0]['player_game'] =
403
- #schedule_ccount_df[schedule_ccount_df['team'].isin(team_schedule_url_merge[0].Team.unique())].merge(right=team_schedule_url_merge[0],left_on=['date','team'],right_on=['date','Team'],how='left')
404
 
405
- team_schedule_url_merge[i]['stat'] = team_schedule_url_merge[i][stat].cumsum()
406
 
 
 
 
407
 
408
- #team_schedule_url_merge[i]['stat'] = team_schedule_url_merge[i][stat_pick]
409
- team_schedule_url_merge[i] = team_schedule_url_merge[i].append(team_schedule_url_merge[i]).sort_index()
410
- team_schedule_url_merge[i] = team_schedule_url_merge[i].append(team_schedule_url_merge[i].iloc[0]).sort_index().reset_index(drop=True)
411
 
412
- team_schedule_url_merge[i]['team_game'][0] = 0
413
- team_schedule_url_merge[i]['player_game'][0] = 0
414
- team_schedule_url_merge[i]['stat'][0] = 0
415
 
416
- for j in range(1,len(team_schedule_url_merge[i]),2):
417
- team_schedule_url_merge[i]['player_game'][j] = team_schedule_url_merge[i]['player_game'][j]-1
418
- team_schedule_url_merge[i]['team_game'][j] = team_schedule_url_merge[i]['team_game'][j]-1
419
- team_schedule_url_merge[i]['stat'][j] = team_schedule_url_merge[i]['stat'][j] - team_schedule_url_merge[i][stat][j]
420
 
421
- if len(team_schedule_url_merge[i]) >3:
422
- if pd.isna(team_schedule_url_merge[i].iloc[3]['player_game']) and pd.isna(team_schedule_url_merge[i].iloc[1]['player_game']) == True:
423
- team_schedule_url_merge[i]['player_game'][2] = np.nan
424
- team_schedule_url_merge[i]['stat'][2] = np.nan
425
 
426
- if len(team_schedule_url_merge[i]) >3:
427
- if pd.isna(team_schedule_url_merge[i].iloc[len(team_schedule_url_merge[i])-1]['player_game']) == True:
428
- team_schedule_url_merge[i]['stat'][len(team_schedule_url_merge[i])-1] = np.nanmax(team_schedule_url_merge[i]['stat'])
429
 
430
- if not (team_schedule_url_merge[i]['team_game'].values[1] == team_schedule_url_merge[i]['player_game'].values[0]):
431
- team_schedule_url_merge[i].loc[0,'team_game'] = np.nan
432
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
 
434
- max_games_player.append(np.around(np.nanmax(team_schedule_url_merge[i]['player_game'])))
435
- max_games_team.append(np.around(np.nanmax(team_schedule_url_merge[i]['team_game'])))
436
- max_stat.append((np.around(np.nanmax(team_schedule_url_merge[i]['stat']))))
437
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
 
 
 
 
 
 
439
 
 
 
 
440
 
441
 
 
 
442
 
443
- fig, ax = plt.subplots(figsize=(15,15))
444
- cgfont = {'fontname':'Century Gothic'}
445
- font = font_manager.FontProperties(family='Century Gothic',
446
- style='normal', size=14)
447
 
448
 
449
- ax.axhline(0,color='black',linestyle ="--",linewidth=2,alpha=1.0,label='Missed Games')
450
- ax.axhline(0,color='black',linestyle ="-",linewidth=2,alpha=1.0)
451
 
452
 
453
- if 'Total' in stat:
454
- stat = stat.replace('Total ',"")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
 
456
 
457
- colour_scheme = ['#648FFF','#785EF0','#DC267F','#FE6100','#FFB000','#FAEF3B','#861318','#2ED3BC','#341BBF','#B37E2C']
458
 
459
- for i in range(len(team_schedule_url_merge)):
460
- sns.lineplot(team_schedule_url_merge[i].reset_index()['team_game'],team_schedule_url_merge[i].reset_index()['stat'],linewidth=3-i*.2,color=colour_scheme[i])
461
- plt.plot(team_schedule_url_merge[i]['team_game'],team_schedule_url_merge[i]['stat'],color=ax.lines[i*2+2].get_color(),label=str(i+1)+'. '+team_schedule_url_merge[i]['Player'][0]+', '+str(int(max_stat[i]))+' '+stat+' in '+str(int(max(team_schedule_url_merge[i]['player_game'])))+' Games',linewidth=6)
462
- ax.lines[i*2+2].set_linestyle("--")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
 
464
 
 
465
 
466
- fig.set_facecolor('#ffffff')
467
- ax.set(xlim=(0,max([team_schedule_url_merge[x].team_game.max() for x in range(len(team_schedule_url_merge))])))
468
- ax.set(ylim=(0,max([team_schedule_url_merge[x].stat.max() for x in range(len(team_schedule_url_merge))])))
469
 
470
- ax.legend_.remove()
471
 
 
 
472
 
473
 
474
- if per_game == False:
475
- fig.suptitle(f'{rookie}{team_select_title}{position_select_title}{stat} Race',y=.98,fontsize=32,color='black',**cgfont)
476
- ax.set_ylabel(stat,fontsize=20,color='black',**cgfont)
477
- # else:
478
- # fig.suptitle(stat+' Per Game, All Situations',y=.99,fontsize=48,color='black',**cgfont)
479
- # ax.set_ylabel(stat+"/GP",fontsize=20,color='black',**cgfont)
480
 
481
 
482
 
483
- ax.set_title(str(current_season)[0:4]+'-'+str(start_season)[-4:]+' Season',y=1.01,fontsize=18,color='black',**cgfont,x=0,ha='left')
484
- ax.set_xlabel('Team Game',fontsize=20,color='black',**cgfont)
485
- ax.tick_params(axis="x", labelsize=24,colors='black')
486
- ax.set_facecolor('#ffffff')
487
- ax.xaxis.set_major_locator(MaxNLocator(integer=True))
488
- ax.tick_params(axis="y", labelsize=24,colors='black')
489
- ax.yaxis.set_major_locator(MaxNLocator(integer=True))
 
 
 
 
 
 
 
 
 
490
 
491
- fig.text(x=0.025,y=0.01,s="Created By: @TJStats",color='black', fontsize=20, horizontalalignment='left',**cgfont)
492
- fig.text(x=0.975,y=0.01,s="Data: Natural Stat Trick",color='black', fontsize=20, horizontalalignment='right',**cgfont)
493
- fig.text(x=.975,y=0.92,s='Date: '+input.date().strftime('%B %d, %Y'),color='black', fontsize=18, horizontalalignment='right',**cgfont)
494
 
495
- ax.legend(prop=font,bbox_to_anchor=(0.01, 0.99),loc='upper left',framealpha=1,frameon=True)
496
- plt.tight_layout()
497
- #fig.savefig('gif_race/'+stat+rookie+str(date_range_list[k].date())+'.png', facecolor=fig.get_facecolor(), edgecolor='none',bbox_inches='tight',dpi=100)
498
- #plt.close()
499
- #fig.legend(prop=font,loc='best',framealpha=1,frameon=True)
500
 
501
- app = App(app_ui, server)
 
1
+ import palmerpenguins
2
  import pandas as pd
 
 
 
 
 
 
 
 
 
 
3
  from datetime import datetime
4
+ from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui
 
 
 
5
  import numpy as np
6
+ import math
 
 
 
 
 
 
 
 
 
7
  from datetime import timedelta
8
+ #df = pd.read_csv('summary_2024.csv',index_col=[0])
9
+ df_game_logs = pd.read_csv('player_games_cards.csv',index_col=[0])
10
+ df_game_logs.date = pd.to_datetime(df_game_logs.date)
11
+ team_pp = pd.read_csv('team_games.csv',index_col=[0])
12
+ team_pp.date = pd.to_datetime(team_pp.date)
13
+ team_abv = pd.read_csv('team_abb.csv')
14
 
15
+ df_game_logs_2 = df_game_logs.copy()
16
+ team_pp_2 = team_pp.copy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  app_ui = ui.page_fluid(
 
19
  ui.layout_sidebar(
20
+
21
+ ui.panel_sidebar(
22
+ ui.input_select(
23
+ "selection_mode",
24
+ "Selection mode",
25
+ {"none": "(None)", "single": "Single", "multiple": "Multiple"},
26
+ selected="multiple",
27
+ ),
28
+
29
+ ui.input_switch("gridstyle", "Grid", True),
30
+ ui.input_switch("fullwidth", "Take full width", True),
31
+ ui.input_switch("fixedheight", "Fixed height", True),
32
+ ui.input_switch("filters", "Filters", True),
33
+ ui.input_date_range("date_range_id", "Date range input",start = df_game_logs.date.min(),
34
+ end = datetime.today().date()- timedelta(days=1),width=2,min='2023-10-10',
35
+ max=datetime.today().date() - timedelta(days=1)),width=2),
36
+
37
+ ui.panel_main(
38
+ ui.navset_tab(
39
+ ui.nav("Total",
40
+ ui.tags.h1("NHL Leaderboards — 2023-24 Season"),
41
+ ui.div({"style": "font-size:1.6em;"},ui.output_text("txt")),
42
+ ui.tags.h5("Created By: @TJStats, Data: Natural Stat Trick"),
43
+ ui.output_data_frame("grid"),
44
+ ),
45
+ ui.nav("Per Game",
46
+ ui.tags.h1("NHL Leaderboards — 2023-24 Season — Per Game"),
47
+ ui.div({"style": "font-size:1.6em;"},ui.output_text("txt_per_game")),
48
+ ui.tags.h5("Created By: @TJStats, Data: Natural Stat Trick"),
49
+ ui.output_data_frame("grid_per_game"),
50
+ ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ ui.nav("Per 60",
53
+ ui.tags.h1("NHL Leaderboards — 2023-24 Season — Per 60"),
54
+ ui.div({"style": "font-size:1.6em;"},ui.output_text("txt_60")),
55
+ ui.tags.h5("Created By: @TJStats, Data: Natural Stat Trick"),
56
+ ui.output_data_frame("grid_60"),
57
+ ),))))
58
 
 
59
 
60
+ def server(input: Inputs, output: Outputs, session: Session):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  @output
63
+ @render.text
64
+ def txt():
65
+ if input.date_range_id()[0].year != input.date_range_id()[1].year:
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ return f'{input.date_range_id()[0].strftime("%B %d, %Y")} to {input.date_range_id()[1].strftime("%B %d, %Y")}'
68
+ else:
69
+ if input.date_range_id()[0].month != input.date_range_id()[1].month:
70
+ return f'{input.date_range_id()[0].strftime("%B %d")} to {input.date_range_id()[1].strftime("%B %d, %Y")}'
71
+ else:
72
+ return f'{input.date_range_id()[0].strftime("%B %d")} to {input.date_range_id()[1].strftime("%d, %Y")}'
73
 
74
  @output
75
+ @render.text
76
+ def txt_per_game():
77
+ if input.date_range_id()[0].year != input.date_range_id()[1].year:
78
+
79
+ return f'{input.date_range_id()[0].strftime("%B %d, %Y")} to {input.date_range_id()[1].strftime("%B %d, %Y")}'
80
+ else:
81
+ if input.date_range_id()[0].month != input.date_range_id()[1].month:
82
+ return f'{input.date_range_id()[0].strftime("%B %d")} to {input.date_range_id()[1].strftime("%B %d, %Y")}'
83
+ else:
84
+ return f'{input.date_range_id()[0].strftime("%B %d")} to {input.date_range_id()[1].strftime("%d, %Y")}'
85
+ @output
86
+ @render.text
87
+ def txt_60():
88
+ if input.date_range_id()[0].year != input.date_range_id()[1].year:
89
 
90
+ return f'{input.date_range_id()[0].strftime("%B %d, %Y")} to {input.date_range_id()[1].strftime("%B %d, %Y")}'
91
+ else:
92
+ if input.date_range_id()[0].month != input.date_range_id()[1].month:
93
+ return f'{input.date_range_id()[0].strftime("%B %d")} to {input.date_range_id()[1].strftime("%B %d, %Y")}'
94
+ else:
95
+ return f'{input.date_range_id()[0].strftime("%B %d")} to {input.date_range_id()[1].strftime("%d, %Y")}'
96
 
 
 
97
 
98
+ @output
99
+ @render.data_frame
100
+ def grid():
101
+ height = 750 if input.fixedheight() else None
102
+ width = "100%" if input.fullwidth() else "fit-content"
103
 
104
+ df_game_logs = df_game_logs_2.copy()
105
+ team_pp = team_pp_2.copy()
106
 
107
+ df_game_logs = df_game_logs[(df_game_logs.date.dt.date >= input.date_range_id()[0])&(df_game_logs.date.dt.date <= input.date_range_id()[1])]
 
 
 
 
108
 
 
 
109
 
110
+ player_id_team = df_game_logs.sort_values(by='date').groupby('player_id').tail(1)[['player_id','Team']].set_index(['player_id'])
111
+ team_pp = team_pp.merge(team_abv)
112
 
113
+ df_game_logs = df_game_logs.merge(right=team_pp, left_on = ['date','Team'], right_on = ['date','abb'])
114
+ df_game_logs['Team'] = df_game_logs.player_id.map(player_id_team.to_dict()['Team'])
115
 
 
 
 
 
 
 
 
 
116
 
117
+ players_games_og_all_summary = df_game_logs.groupby(['player_id','Player','pos','Team']).agg(
118
+ GP = ('GP','sum'),
119
+ TOI = ('TOI','sum'),
120
+ Goals = ('Goals','sum'),
121
+ Assists = ('Total Assists','sum'),
122
+ First_Assists = ('First Assists','sum'),
123
+ Total_Points = ('Total Points','sum'),
124
+ ixG = ('ixG','sum'),
125
+ #GSAx = ('Goals'-'ixG','sum'),
126
+ Shots = ('Shots','sum'),
127
+ iCF = ('iCF','sum'),
128
+ iSCF = ('iSCF','sum'),
129
+ iHDCF = ('iHDCF','sum'),
130
+ Hits = ('Hits','sum'),
131
+ Shots_Blocked = ('Shots Blocked','sum'),
132
+ TOI_pp = ('TOI_pp','sum'),
133
+ Total_Points_pp = ('Total Points_pp','sum'),
134
+ TOI_pp_team = ('pp_toi','sum'))#.reset_index()
135
 
136
 
137
+ players_games_og_all_summary['1A_percent'] = (players_games_og_all_summary.First_Assists / players_games_og_all_summary.Assists).round(3)
138
+ players_games_og_all_summary['PP%'] = (players_games_og_all_summary.TOI_pp / players_games_og_all_summary.TOI_pp_team).round(3)
139
+ players_games_og_all_summary['G-ixG'] = players_games_og_all_summary.Goals - players_games_og_all_summary.ixG
140
+ players_games_og_all_summary['S+H+B'] = players_games_og_all_summary.Shots + players_games_og_all_summary.Hits + players_games_og_all_summary.Shots_Blocked
141
+ players_games_og_all_summary.TOI = players_games_og_all_summary.TOI.round(2)
142
 
143
+ players_games_og_all_summary['1A_percent'] = [f'{str(round(x*100,1))}%' if not math.isnan(x) else '' for x in players_games_og_all_summary['1A_percent']]
144
+ players_games_og_all_summary['PP%'] = [f'{str(round(x*100,1))}%' if not math.isnan(x) else '' for x in players_games_og_all_summary['PP%']]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+
147
 
148
+ output_df = players_games_og_all_summary.reset_index(drop=False)[['Player', 'Team', 'pos', 'GP', 'TOI', 'Goals',
149
+ 'Assists', 'Total_Points','Total_Points_pp', 'Shots','Hits', 'Shots_Blocked', 'S+H+B',
150
+ '1A_percent', 'PP%']]
151
 
 
 
 
152
 
153
+ output_df.columns = ['Player', 'Team', 'Pos', 'GP', 'TOI', 'Goals','Assists', 'Points','PPP', 'Shots','Hits', 'Blocks', 'S+H+B',
154
+ '1A%', 'PP%']
 
155
 
 
 
 
 
156
 
 
 
 
 
157
 
 
 
 
158
 
 
 
159
 
160
+ if input.gridstyle():
161
+ return render.DataGrid(
162
+ output_df,
163
+ row_selection_mode=input.selection_mode(),
164
+ height=height,
165
+ width='fit-content',
166
+ filters=input.filters(),
167
+ )
168
+ else:
169
+ return render.DataTable(
170
+ output_df,
171
+ row_selection_mode=input.selection_mode(),
172
+ height=height,
173
+ width='fit-content',
174
+ filters=input.filters(),
175
+ )
176
+
177
 
 
 
 
178
 
179
+ @output
180
+ @render.data_frame
181
+ def grid_per_game():
182
+ height = 750 if input.fixedheight() else None
183
+ width = "100%" if input.fullwidth() else "fit-content"
184
+
185
+ df_game_logs = df_game_logs_2.copy()
186
+ team_pp = team_pp_2.copy()
187
+
188
+ df_game_logs = df_game_logs[(df_game_logs.date.dt.date >= input.date_range_id()[0])&(df_game_logs.date.dt.date <= input.date_range_id()[1])]
189
+
190
+
191
+ player_id_team = df_game_logs.sort_values(by='date').groupby('player_id').tail(1)[['player_id','Team']].set_index(['player_id'])
192
+ team_pp = team_pp.merge(team_abv)
193
+
194
+ df_game_logs = df_game_logs.merge(right=team_pp, left_on = ['date','Team'], right_on = ['date','abb'])
195
+ df_game_logs['Team'] = df_game_logs.player_id.map(player_id_team.to_dict()['Team'])
196
+
197
+
198
+ players_games_og_all_summary = df_game_logs.groupby(['player_id','Player','pos','Team']).agg(
199
+ GP = ('GP','sum'),
200
+ TOI = ('TOI','sum'),
201
+ Goals = ('Goals','sum'),
202
+ Assists = ('Total Assists','sum'),
203
+ First_Assists = ('First Assists','sum'),
204
+ Total_Points = ('Total Points','sum'),
205
+ ixG = ('ixG','sum'),
206
+ #GSAx = ('Goals'-'ixG','sum'),
207
+ Shots = ('Shots','sum'),
208
+ iCF = ('iCF','sum'),
209
+ iSCF = ('iSCF','sum'),
210
+ iHDCF = ('iHDCF','sum'),
211
+ Hits = ('Hits','sum'),
212
+ Shots_Blocked = ('Shots Blocked','sum'),
213
+ TOI_pp = ('TOI_pp','sum'),
214
+ Total_Points_pp = ('Total Points_pp','sum'),
215
+ TOI_pp_team = ('pp_toi','sum'))#.reset_index()
216
+
217
+
218
+ players_games_og_all_summary['1A_percent'] = (players_games_og_all_summary.First_Assists / players_games_og_all_summary.Assists).round(3)
219
+ players_games_og_all_summary['PP%'] = (players_games_og_all_summary.TOI_pp / players_games_og_all_summary.TOI_pp_team).round(3)
220
+ players_games_og_all_summary['G-ixG'] = players_games_og_all_summary.Goals - players_games_og_all_summary.ixG
221
+ players_games_og_all_summary['S+H+B'] = players_games_og_all_summary.Shots + players_games_og_all_summary.Hits + players_games_og_all_summary.Shots_Blocked
222
+ players_games_og_all_summary.TOI = players_games_og_all_summary.TOI.round(2)
223
+
224
+ players_games_og_all_summary['1A_percent'] = [f'{str(round(x*100,1))}%' if not math.isnan(x) else '' for x in players_games_og_all_summary['1A_percent']]
225
+ players_games_og_all_summary['PP%'] = [f'{str(round(x*100,1))}%' if not math.isnan(x) else '' for x in players_games_og_all_summary['PP%']]
226
 
227
+ players_games_og_all_summary[['TOI', 'Goals', 'ixG', 'G-ixG','Assists',
228
+ 'First_Assists', 'Total_Points','Total_Points_pp',
229
+ 'Shots','Hits', 'Shots_Blocked', 'S+H+B', ]] = players_games_og_all_summary[['TOI', 'Goals', 'ixG', 'G-ixG','Assists',
230
+ 'First_Assists', 'Total_Points','Total_Points_pp',
231
+ 'Shots','Hits', 'Shots_Blocked', 'S+H+B', ]].divide(players_games_og_all_summary.GP,axis=0).round(2)
232
 
233
+ output_df = players_games_og_all_summary.reset_index(drop=False)[['Player', 'Team', 'pos', 'GP', 'TOI', 'Goals',
234
+ 'Assists', 'Total_Points','Total_Points_pp', 'Shots','Hits', 'Shots_Blocked', 'S+H+B',
235
+ '1A_percent', 'PP%']]
236
 
237
 
238
+ output_df.columns = ['Player', 'Team', 'Pos', 'GP', 'TOI/GP', 'Goals/GP','Assists/GP', 'Points/GP','PPP/GP', 'Shots/GP','Hits/GP', 'Blocks/GP', 'S+H+B/GP',
239
+ '1A%', 'PP%']
240
 
 
 
 
 
241
 
242
 
 
 
243
 
244
 
245
+ if input.gridstyle():
246
+ return render.DataGrid(
247
+ output_df,
248
+ row_selection_mode=input.selection_mode(),
249
+ height=height,
250
+ width='fit-content',
251
+ filters=input.filters(),
252
+ )
253
+ else:
254
+ return render.DataTable(
255
+ output_df,
256
+ row_selection_mode=input.selection_mode(),
257
+ height=height,
258
+ width='fit-content',
259
+ filters=input.filters(),
260
+ )
261
 
262
 
 
263
 
264
+ @output
265
+ @render.data_frame
266
+ def grid_60():
267
+ height = 750 if input.fixedheight() else None
268
+ width = "100%" if input.fullwidth() else "fit-content"
269
+
270
+ df_game_logs = df_game_logs_2.copy()
271
+ team_pp = team_pp_2.copy()
272
+
273
+ df_game_logs = df_game_logs[(df_game_logs.date.dt.date >= input.date_range_id()[0])&(df_game_logs.date.dt.date <= input.date_range_id()[1])]
274
+
275
+
276
+ player_id_team = df_game_logs.sort_values(by='date').groupby('player_id').tail(1)[['player_id','Team']].set_index(['player_id'])
277
+ team_pp = team_pp.merge(team_abv)
278
+
279
+ df_game_logs = df_game_logs.merge(right=team_pp, left_on = ['date','Team'], right_on = ['date','abb'])
280
+ df_game_logs['Team'] = df_game_logs.player_id.map(player_id_team.to_dict()['Team'])
281
+
282
+
283
+ players_games_og_all_summary = df_game_logs.groupby(['player_id','Player','pos','Team']).agg(
284
+ GP = ('GP','sum'),
285
+ TOI = ('TOI','sum'),
286
+ Goals = ('Goals','sum'),
287
+ Assists = ('Total Assists','sum'),
288
+ First_Assists = ('First Assists','sum'),
289
+ Total_Points = ('Total Points','sum'),
290
+ ixG = ('ixG','sum'),
291
+ #GSAx = ('Goals'-'ixG','sum'),
292
+ Shots = ('Shots','sum'),
293
+ iCF = ('iCF','sum'),
294
+ iSCF = ('iSCF','sum'),
295
+ iHDCF = ('iHDCF','sum'),
296
+ Hits = ('Hits','sum'),
297
+ Shots_Blocked = ('Shots Blocked','sum'),
298
+ TOI_pp = ('TOI_pp','sum'),
299
+ Total_Points_pp = ('Total Points_pp','sum'),
300
+ TOI_pp_team = ('pp_toi','sum'))#.reset_index()
301
+
302
+
303
+ players_games_og_all_summary['1A_percent'] = (players_games_og_all_summary.First_Assists / players_games_og_all_summary.Assists).round(3)
304
+ players_games_og_all_summary['PP%'] = (players_games_og_all_summary.TOI_pp / players_games_og_all_summary.TOI_pp_team).round(3)
305
+ players_games_og_all_summary['G-ixG'] = players_games_og_all_summary.Goals - players_games_og_all_summary.ixG
306
+ players_games_og_all_summary['S+H+B'] = players_games_og_all_summary.Shots + players_games_og_all_summary.Hits + players_games_og_all_summary.Shots_Blocked
307
+ players_games_og_all_summary.TOI = players_games_og_all_summary.TOI.round(2)
308
+
309
+ players_games_og_all_summary['1A_percent'] = [f'{str(round(x*100,1))}%' if not math.isnan(x) else '' for x in players_games_og_all_summary['1A_percent']]
310
+ players_games_og_all_summary['PP%'] = [f'{str(round(x*100,1))}%' if not math.isnan(x) else '' for x in players_games_og_all_summary['PP%']]
311
+
312
+ players_games_og_all_summary[['Goals', 'ixG', 'G-ixG','Assists',
313
+ 'First_Assists', 'Total_Points','Total_Points_pp','iCF','iSCF',
314
+ 'Shots','Hits', 'Shots_Blocked', 'S+H+B', ]] = players_games_og_all_summary[['Goals', 'ixG', 'G-ixG','Assists',
315
+ 'First_Assists', 'Total_Points','Total_Points_pp','iCF','iSCF',
316
+ 'Shots','Hits', 'Shots_Blocked', 'S+H+B']].divide(players_games_og_all_summary.TOI/60,axis=0).round(2)
317
 
318
 
319
+ players_games_og_all_summary['TOI/GP'] = players_games_og_all_summary.TOI / players_games_og_all_summary.GP
320
 
321
+ output_df = players_games_og_all_summary.reset_index(drop=False)[['Player', 'Team', 'pos', 'GP', 'TOI', 'TOI/GP','Goals',
322
+ 'Assists', 'Total_Points','Total_Points_pp','iCF','iSCF', 'Shots','Hits', 'Shots_Blocked', 'S+H+B',
323
+ '1A_percent', 'PP%']]
324
 
 
325
 
326
+ output_df.columns = ['Player', 'Team', 'Pos', 'GP', 'TOI','TOI/GP', 'Goals/60','Assists/60', 'Points/60','PPP/60','iCF/60','iSCF/60', 'Shots/60','Hits/60', 'Blocks/60', 'S+H+B/60',
327
+ '1A%', 'PP%']
328
 
329
 
 
 
 
 
 
 
330
 
331
 
332
 
333
+ if input.gridstyle():
334
+ return render.DataGrid(
335
+ output_df,
336
+ row_selection_mode=input.selection_mode(),
337
+ height=height,
338
+ width='fit-content',
339
+ filters=input.filters(),
340
+ )
341
+ else:
342
+ return render.DataTable(
343
+ output_df,
344
+ row_selection_mode=input.selection_mode(),
345
+ height=height,
346
+ width='fit-content',
347
+ filters=input.filters(),
348
+ )
349
 
 
 
 
350
 
 
 
 
 
 
351
 
352
+ app = App(app_ui, server)