nesticot commited on
Commit
919aa2c
·
verified ·
1 Parent(s): 1c19008

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +854 -830
app.py CHANGED
@@ -1,830 +1,854 @@
1
- #import packages
2
- import pandas as pd
3
- import json
4
- import numpy as np
5
- import requests
6
- pd.options.mode.chained_assignment = None
7
- from datetime import datetime
8
- import time
9
- import difflib
10
- from datetime import datetime, timedelta
11
- import api_scraper
12
- import polars as pl
13
- import matplotlib.colors
14
- import matplotlib.colors as mcolors
15
- from shiny import App, ui, render, reactive
16
-
17
- def add_empty_rows(df, n_empty, period):
18
- """ adds 'n_empty' empty rows every 'period' rows to 'df'.
19
- Returns a new DataFrame. """
20
-
21
- # to make sure that the DataFrame index is a RangeIndex(start=0, stop=len(df))
22
- # and that the original df object is not mutated.
23
- df = df.reset_index(drop=True)
24
-
25
- # length of the new DataFrame containing the NaN rows
26
- len_new_index = len(df) + n_empty*(len(df) // period)
27
- # index of the new DataFrame
28
- new_index = pd.RangeIndex(len_new_index)
29
-
30
- # add an offset (= number of NaN rows up to that row)
31
- # to the current df.index to align with new_index.
32
- df.index += n_empty * (df.index
33
- .to_series()
34
- .groupby(df.index // period)
35
- .ngroup())
36
-
37
- # reindex by aligning df.index with new_index.
38
- # Values of new_index not present in df.index are filled with NaN.
39
- new_df = df.reindex(new_index)
40
-
41
- return new_df
42
-
43
- unique_team_list = [120,
44
- 141,
45
- 140,
46
- 139,
47
- 138,
48
- 137,
49
- 136,
50
- 135,
51
- 134,
52
- 143,
53
- 133,
54
- 147,
55
- 121,
56
- 142,
57
- 158,
58
- 146,
59
- 119,
60
- 108,
61
- 118,
62
- 117,
63
- 116,
64
- 145,
65
- 115,
66
- 114,
67
- 113,
68
- 112,
69
- 111,
70
- 110,
71
- 109,
72
- 144]
73
-
74
- ## Create a dataframe of teams to assist with selecting a player to search
75
- #specifically for the case where multiple players share the same name
76
- #Make an api call to get a dictionary of all teams
77
- teams = requests.get(url='https://statsapi.mlb.com/api/v1/teams/').json()
78
- #Select only teams that are at the MLB level
79
- mlb_teams_city = [x['franchiseName'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
80
- mlb_teams_name = [x['teamName'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
81
- mlb_teams_franchise = [x['name'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
82
- mlb_teams_id = [x['id'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
83
- mlb_teams_abb = [x['abbreviation'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
84
-
85
- #Create a dataframe of all the teams
86
- mlb_teams_df = pd.DataFrame(data={'team_id':mlb_teams_id,'city':mlb_teams_franchise,'name':mlb_teams_name,'franchise':mlb_teams_franchise,'abbreviation':mlb_teams_abb})
87
- ##Create a dataframe of all players in the database
88
- #Make an api call to get a dictionary of all players
89
- player_data = requests.get(url='https://statsapi.mlb.com/api/v1/sports/11/players').json()
90
-
91
- #Select relevant data that will help distinguish players from one another
92
- fullName_list = [x['fullName'] for x in player_data['people']]
93
- id_list = [x['id'] for x in player_data['people']]
94
- position_list = [x['primaryPosition']['abbreviation'] for x in player_data['people']]
95
- team_list = [x['currentTeam']['id']for x in player_data['people']]
96
-
97
- #Create a dataframe of players and their current team ids
98
- player_df_all = pd.DataFrame(data={'id':id_list,'name':fullName_list,'position':position_list,'team_id':team_list})
99
- #Use the teams dataframe to merge the team name to the players dataframe
100
- player_df_all = player_df_all.merge(right=mlb_teams_df[['team_id','franchise']],left_on='team_id',right_on='team_id',how='left',suffixes=['','_y'])
101
- #drop the duplicated id column
102
- player_df_all = player_df_all.drop(columns=['team_id'])
103
- #make a column of the names all uppercase to make lookups easier
104
- player_df_all['upper_name'] = player_df_all['name'].str.upper()
105
- #rename to make the data clearer
106
- player_df_all = player_df_all.rename(columns={'franchise':'currentTeam'})
107
-
108
-
109
-
110
- import matplotlib.pyplot as plt
111
- colour_palette = ['#FFB000','#648FFF','#785EF0',
112
- '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
113
-
114
- cmap_up = mcolors.LinearSegmentedColormap.from_list("", ['#FFFFFF', '#FFB000'])
115
-
116
-
117
- # Function to alternate row colors
118
- def highlight_alternate_rows(x):
119
- return ['background-color: #ebebeb' if i % 2 == 0 else '' for i in range(len(x))]
120
- # Function to apply thick border to data cells
121
- # Columns after which we want a thick vertical line
122
-
123
- scraper = api_scraper.MLB_Scrape()
124
- df_teams = scraper.get_teams()
125
-
126
- teams_mlb = df_teams.filter(pl.col("league_id").is_in([103,104])).sort("abbreviation")
127
- teams_dict = dict(zip(teams_mlb['team_id'],teams_mlb['abbreviation']))
128
-
129
- teams_name_dict = dict(zip(teams_mlb['team_id'],teams_mlb['franchise']))
130
-
131
- {109: 'Arizona Diamondbacks',
132
- 144: 'Atlanta Braves',
133
- 110: 'Baltimore Orioles',
134
- 111: 'Boston Red Sox',
135
- 112: 'Chicago Cubs',
136
- 145: 'Chicago White Sox',
137
- 113: 'Cincinnati Reds',
138
- 114: 'Cleveland Guardians',
139
- 115: 'Colorado Rockies',
140
- 116: 'Detroit Tigers',
141
- 117: 'Houston Astros',
142
- 118: 'Kansas City Royals',
143
- 108: 'Los Angeles Angels',
144
- 119: 'Los Angeles Dodgers',
145
- 146: 'Miami Marlins',
146
- 158: 'Milwaukee Brewers',
147
- 142: 'Minnesota Twins',
148
- 121: 'New York Mets',
149
- 147: 'New York Yankees',
150
- #133: 'Athletics',
151
- 133: 'Oakland Athletics',
152
- 143: 'Philadelphia Phillies',
153
- 134: 'Pittsburgh Pirates',
154
- 135: 'San Diego Padres',
155
- 137: 'San Francisco Giants',
156
- 136: 'Seattle Mariners',
157
- 138: 'St. Louis Cardinals',
158
- 139: 'Tampa Bay Rays',
159
- 140: 'Texas Rangers',
160
- 141: 'Toronto Blue Jays',
161
- 120: 'Washington Nationals'}
162
-
163
-
164
- data_r_1 = requests.get("https://pub-api-ro.fantasysports.yahoo.com/fantasy/v2/league/458.l.1423;out=settings/players;position=ALL;start=0;count=5000;sort=rank_season;search=;out=percent_owned;out=auction_values,ranks;ranks=season;ranks_by_position=season;out=expert_ranks;expert_ranks.rank_type=projected_season_remaining/draft_analysis;cut_types=diamond;slices=last7days?format=json_f").json()
165
- #data_r_2 = requests.get("https://pub-api-ro.fantasysports.yahoo.com/fantasy/v2/league/422.l.1416;out=settings/players;position=ALL;start=758;count=5000;sort=rank_season;search=;out=auction_values,ranks;ranks=season;ranks_by_position=season;out=expert_ranks;expert_ranks.rank_type=projected_season_remaining/draft_analysis;cut_types=diamond;slices=last7days?format=json_f").json()
166
- # 757 is bad
167
- #https://pub-api-ro.fantasysports.yahoo.com/fantasy/v2/league/422.l.1416;out=settings/players;position=ALL;start=0;count=756;sort=rank_season;search=;out=auction_values,ranks;ranks=season;ranks_by_position=season;out=expert_ranks;expert_ranks.rank_type=projected_season_remaining/draft_analysis;cut_types=diamond;slices=last7days?format=json_f
168
-
169
- total_list = []
170
-
171
- for x in data_r_1['fantasy_content']['league']['players']:
172
- single_list = []
173
-
174
- single_list.append((x['player']['player_id']))
175
- single_list.append(x['player']['name']['full'])
176
- single_list.append(x['player']['name']['first'])
177
- single_list.append(x['player']['name']['last'])
178
- single_list.append(x['player']['draft_analysis']['average_pick'])
179
- single_list.append(x['player']['average_auction_cost'])
180
- single_list.append(x['player']['display_position'])
181
- single_list.append(x['player']['editorial_team_abbr'])
182
- total_list.append(single_list)
183
-
184
- df_2023 = pd.DataFrame(data=total_list, columns=['player_id','full','first','last','average_pick', 'average_cost','display_position','editorial_team_abbr'])
185
-
186
-
187
- team_abb_list = ['ATL', 'AZ', 'BAL', 'BOS', 'CHC', 'CIN', 'CLE', 'COL', 'CWS',
188
- 'DET', 'HOU', 'KC', 'LAA', 'LAD', 'MIA', 'MIL', 'MIN', 'NYM',
189
- 'NYY', 'ATH', 'PHI', 'PIT', 'SD', 'SEA', 'SF', 'STL', 'TB', 'TEX',
190
- 'TOR', 'WSH']
191
-
192
- team_abb_list_yahoo = ['ATL', 'ARI', 'BAL', 'BOS', 'CHC', 'CIN', 'CLE', 'COL', 'CWS',
193
- 'DET', 'HOU', 'KC', 'LAA', 'LAD', 'MIA', 'MIL', 'MIN', 'NYM',
194
- 'NYY', 'ATH', 'PHI', 'PIT', 'SD', 'SEA', 'SF', 'STL', 'TB', 'TEX',
195
- 'TOR', 'WSH']
196
- team_abb_df = pd.DataFrame({'mlb_team':team_abb_list,'yahoo_team':team_abb_list_yahoo})
197
-
198
-
199
-
200
- from shiny import App, ui, render
201
- import pandas as pd
202
-
203
- # Create sample data for the tables
204
- data1 = pd.DataFrame({
205
- 'Name': ['Alice', 'Bob', 'Charlie'],
206
- 'Age': [25, 30, 35],
207
- 'City': ['New York', 'London', 'Paris']
208
- })
209
-
210
- data2 = pd.DataFrame({
211
- 'Product': ['Laptop', 'Phone', 'Tablet'],
212
- 'Price': [1200, 800, 500],
213
- 'Stock': [50, 100, 75]
214
- })
215
-
216
- data3 = pd.DataFrame({
217
- 'Country': ['USA', 'UK', 'France'],
218
- 'Population': ['331M', '67M', '67M'],
219
- 'Language': ['English', 'English', 'French']
220
- })
221
-
222
- app_ui = ui.page_sidebar(
223
- ui.sidebar(
224
- ui.input_select(
225
- "team_id",
226
- "Select Team",
227
- choices=teams_dict
228
- ),
229
- # ui.h3("Sidebar"),
230
- # ui.p("This is a demonstration of a card with tabs containing tables.")
231
- ),
232
- ui.card(
233
- ui.output_text("selected_team_info"),
234
- ui.navset_card_tab(
235
- ui.nav_panel(
236
- "Lineups",
237
- ui.div({"style": "font-size:1.7em;"}, ui.output_text("lineup_title")),
238
- ui.output_table("table1")
239
- ),
240
- ui.nav_panel(
241
- "Summary",
242
- ui.div({"style": "font-size:1.7em;"}, ui.output_text("summary_title")),
243
- ui.output_table("table2")
244
- ),
245
- ui.nav_panel(
246
- "Fantasy Eligibility",
247
- ui.div({"style": "font-size:1.7em;"}, ui.output_text("fantasy_title")),
248
- ui.output_table("table3")
249
- )
250
- )
251
- )
252
- )
253
-
254
- def server(input, output, session):
255
-
256
- @render.text
257
- def lineup_title():
258
-
259
- return f"{teams_name_dict[int(input.team_id())]} Spring Training Lineups"
260
-
261
- @render.text
262
- def summary_title():
263
-
264
- return f"{teams_name_dict[int(input.team_id())]} Spring Training Lineup Summary"
265
-
266
- @render.text
267
- def fantasy_title():
268
-
269
- return f"{teams_name_dict[int(input.team_id())]} Spring Training Position Eligibility Tracker - Yahoo"
270
-
271
-
272
- @reactive.calc
273
- def cached_data():
274
- team_id_select = int(input.team_id())
275
-
276
- df_schedule = scraper.get_schedule(year_input=[2025],sport_id=[1],game_type=['S','E'])
277
-
278
- # df_schedule_p = scraper.get_schedule(year_input=[2024],sport_id=[21],game_type=['E'])
279
-
280
- # df_schedule_all = pl.concat([df_schedule,df_schedule_p])
281
-
282
- df_schedule_all = pl.concat([df_schedule])
283
-
284
-
285
- df_schedule_team = df_schedule_all.filter((pl.col('date') <= datetime.today().date())&((pl.col('home_id') == team_id_select)|(pl.col('away_id') == team_id_select)))
286
- if df_schedule_team.is_empty():
287
- return None, None, None
288
- statcast_dict = dict(zip(df_schedule_team['game_id'],df_schedule_team['gameday_type']))
289
- game_list = df_schedule_team['game_id'][:]
290
- game_data = scraper.get_data(game_list)
291
-
292
- print('Importing New Games.')
293
- lineup_data = []
294
- game_id = []
295
- date = []
296
- player_id = []
297
- player_name = []
298
- position = []
299
- team_id = []
300
- batting_order = []
301
- handedness_batter = []
302
- away_home = []
303
- handedness_pitcher = []
304
- pitcher_name = []
305
- for y in range(0,len(game_data)):
306
- game_id.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])*[game_data[y]['gameData']['game']['pk']])
307
- date.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])*[game_data[y]['gameData']['datetime']['officialDate']])
308
- player_id.append([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
309
- player_name.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['person']['fullName'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
310
- position.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['allPositions'][0]['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
311
- team_id.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['parentTeamId'] if 'parentTeamId' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
312
- batting_order.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['battingOrder'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
313
- away_home.append(['away' if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
314
- handedness_batter.append([game_data[y]['gameData']['players'][x]['batSide']['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
315
- handedness_pitcher.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['home']['id'])]['pitchHand']['code']+'HP' if 'home' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
316
- pitcher_name.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['home']['id'])]['fullName'] if 'home' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
317
-
318
- game_id.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])*[game_data[y]['gameData']['game']['pk']])
319
- date.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])*[game_data[y]['gameData']['datetime']['officialDate']])
320
- player_id.append([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
321
- player_name.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['person']['fullName'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
322
- position.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['allPositions'][0]['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
323
- team_id.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['parentTeamId'] if 'parentTeamId' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
324
- batting_order.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['battingOrder'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
325
- away_home.append(['home' if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
326
- handedness_batter.append([game_data[y]['gameData']['players'][x]['batSide']['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
327
- handedness_pitcher.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['away']['id'])]['pitchHand']['code']+'HP' if 'away' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
328
- pitcher_name.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['away']['id'])]['fullName'] if 'away' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
329
-
330
-
331
-
332
- game_id_final = [item for sublist in game_id for item in sublist]
333
- date_final = [item for sublist in date for item in sublist]
334
- player_id_final = [item for sublist in player_id for item in sublist]
335
- player_name_final = [item for sublist in player_name for item in sublist]
336
- position_final = [item for sublist in position for item in sublist]
337
- team_id_final = [item for sublist in team_id for item in sublist]
338
- batting_order_final = [item for sublist in batting_order for item in sublist]
339
- away_home_final = [item for sublist in away_home for item in sublist]
340
- handedness_batter_final = [item for sublist in handedness_batter for item in sublist]
341
- handedness_pitcher_final = [item for sublist in handedness_pitcher for item in sublist]
342
- pitcher_name_final = [item for sublist in pitcher_name for item in sublist]
343
-
344
- position_df = pl.DataFrame(data={'position':[1,2,3,4,5,6,7,8,9,10],'position_name':['P','C','1B','2B','3B','SS','LF','CF','RF','DH']})
345
- batting_order_full = pl.DataFrame(data={'game_id':game_id_final ,
346
- 'date':date_final,
347
- 'player_id':player_id_final,
348
- 'player_name':player_name_final,
349
- 'position':position_final,
350
- 'team_id':team_id_final,
351
- 'batting_order':batting_order_final,
352
- 'away_home':away_home_final,
353
- 'handedness_batter':handedness_batter_final,
354
- 'handedness_pitcher':handedness_pitcher_final,
355
- 'pitcher_name':pitcher_name_final})
356
-
357
- # batting_order_full = batting_order_full
358
-
359
-
360
-
361
- batting_order_full = batting_order_full.with_columns(pl.col('position').cast(pl.Int32))
362
- batting_order_full = batting_order_full.join(df_teams[['team_id', 'franchise', 'abbreviation']], on='team_id', how='left')
363
- position_df = position_df.with_columns(pl.col('position').cast(pl.Int32))
364
- batting_order_full = batting_order_full.join(position_df, on='position', how='left')
365
- batting_order_full_opp = batting_order_full.filter(pl.col('team_id') != team_id_select)
366
-
367
- batting_order_full = batting_order_full.filter(pl.col('team_id') == team_id_select)
368
- batting_order_full_filter = batting_order_full.filter(pl.col('batting_order').cast(pl.Int32) % 100 == 0)
369
-
370
- batting_order_full_filter = batting_order_full_filter.sort(by=['abbreviation', 'franchise', 'date', 'game_id', 'batting_order'], descending=[False, False, False, False, False]).with_row_count().drop('row_nr')
371
- batting_order_full_filter = batting_order_full_filter.unique(subset=['batting_order','game_id','away_home'])
372
-
373
- batting_order_full_filter = batting_order_full_filter.with_columns(pl.col('batting_order').cast(pl.Int32))
374
-
375
-
376
- df_test_merge = batting_order_full_filter.clone()
377
- df_test_merge = df_test_merge.with_columns(pl.col('*').fill_null(np.nan))
378
-
379
- df_test_merge = df_test_merge.sort(['player_id', 'date']).fill_null(strategy='forward')
380
- df_test_merge_small = df_test_merge.select([
381
- 'game_id', 'date', 'abbreviation', 'batting_order', 'player_id', 'player_name',
382
- 'position_name', 'handedness_batter', 'handedness_pitcher', 'pitcher_name'
383
- ]).sort(['date', 'game_id', 'abbreviation', 'batting_order'])
384
-
385
- df_test_merge_small = df_test_merge_small.select(['game_id',
386
- 'date', 'abbreviation', 'batting_order', 'player_id', 'player_name',
387
- 'position_name', 'handedness_batter', 'handedness_pitcher', 'pitcher_name'
388
- ]).fill_null('')
389
-
390
- df_test_merge_small = df_test_merge_small.with_columns([
391
- (pl.col('batting_order').cast(pl.Int32) / 100).cast(pl.Int32).alias('batting_order'),
392
- pl.lit(1).alias('count'),
393
- ])
394
-
395
- df_test_merge_small = df_test_merge_small.rename({'game_id': 'Game ID',
396
- 'date': 'Date', 'abbreviation': 'Team', 'batting_order': 'Batting',
397
- 'player_id': 'Player ID', 'player_name': 'Player', 'position_name': 'Position',
398
- 'handedness_batter': 'Bats', 'handedness_pitcher': 'Pitcher Hand',
399
- 'pitcher_name': 'Pitcher Name'
400
- })
401
-
402
- return df_test_merge_small,batting_order_full_opp,statcast_dict
403
-
404
-
405
-
406
- @output
407
- @render.table
408
- def table1():
409
- df,batting_order_full_opp,statcast_dict = cached_data()
410
- if df is None:
411
- return pd.DataFrame({"Message": ["No Games as of this time"]})
412
- team_opp = dict(zip(batting_order_full_opp['game_id'],batting_order_full_opp['abbreviation']))
413
-
414
- df_test_merge_small_pd = df.to_pandas()
415
-
416
- df_test_merge_small_pd['Opponent'] = df_test_merge_small_pd['Game ID'].map(team_opp)
417
-
418
- # Create a new column with the date and opponent for the first occurrence of each game ID
419
- df_test_merge_small_pd['Game'] = np.where(
420
- ~df_test_merge_small_pd.duplicated(subset=['Game ID'], keep='first'),
421
- 0,
422
- None
423
- )
424
-
425
- df_test_merge_small_pd['gameday_type'] = df_test_merge_small_pd['Game ID'].map(statcast_dict)
426
- df_test_merge_small_pd['Statcast'] = np.where(
427
- df_test_merge_small_pd['gameday_type'].isin(['E', 'P']),
428
- True,
429
- False
430
- )
431
-
432
-
433
- df_test_merge_small_pd['Pitcher'] = df_test_merge_small_pd['Pitcher Name'] + ' (' + df_test_merge_small_pd['Pitcher Hand'] + ')'
434
-
435
-
436
- df_test_merge_small_pd['Batter'] = '<a href=https://baseballsavant.mlb.com/savant-player/'+'df_test_merge_small_pd["Player ID"].astype(str).str[2:]'+'target="_blank">'+df_test_merge_small_pd["Player"]+'</a>'
437
-
438
-
439
- df_test_merge_small_pd['Gameday'] = '<a href=https://www.mlb.com/gameday/'+df_test_merge_small_pd["Game ID"].astype(int).astype(str)+' target="_blank">Gameday</a>'
440
- df_test_merge_small_pd['Savant'] = np.where(
441
- df_test_merge_small_pd['Statcast'],
442
- '<a href=https://baseballsavant.mlb.com/gamefeed?gamePk='+df_test_merge_small_pd["Game ID"].astype(int).astype(str)+' target="_blank">Statcast</a>',
443
- '(No Statcast)'
444
- )
445
-
446
- game_index = df_test_merge_small_pd.loc[~(df_test_merge_small_pd['Game'].isnull()), 'Game'].index
447
-
448
- df_test_merge_small_pd.loc[game_index+2,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Date'])
449
-
450
- df_test_merge_small_pd.loc[game_index+3,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Team'] + ' vs ' + df_test_merge_small_pd.loc[game_index+0,'Opponent'])
451
-
452
- df_test_merge_small_pd.loc[game_index+4,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Pitcher'])
453
- df_test_merge_small_pd.loc[game_index+5,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Gameday'])
454
- df_test_merge_small_pd.loc[game_index+6,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Savant'])
455
-
456
- df_test_merge_small_pd['Game'] = df_test_merge_small_pd['Game'].replace(0,None).fillna('')
457
-
458
- df_test_merge_small_output = df_test_merge_small_pd[['Game',
459
-
460
- 'Batting',
461
- 'Player',
462
- 'Position',
463
- 'Bats']]
464
-
465
- df_order_style = df_test_merge_small_output.style
466
-
467
-
468
- df_order_style = (df_order_style.set_precision(0)
469
- .set_table_styles(
470
- [
471
-
472
-
473
- {'selector':'th', 'props' : [('border', '1px solid black')]},
474
-
475
- ],overwrite=False)
476
- .set_properties(**{'border': '3 px'}, overwrite=False)
477
- .set_table_styles([{
478
- 'selector': 'caption',
479
- 'props': [
480
- ('color', ''),
481
- ('fontname', 'Century Gothic'),
482
- ('font-size', '16px'),
483
- ('font-style', 'italic'),
484
- ('font-weight', ''),
485
- ('text-align', 'centre'),
486
- ]
487
- },
488
- {
489
- 'selector': 'th',
490
- 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')]
491
- },
492
- {
493
- 'selector': 'td',
494
- 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')]
495
- }], overwrite=False)
496
-
497
- .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '20px'}, overwrite=False)
498
- .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False)
499
-
500
- .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#d6d6d6')]}], overwrite=False)
501
- .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False)
502
- .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False)
503
- .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False)
504
- .hide_index()
505
- .set_properties(**{'border': '1px black solid'})
506
- .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '225px')]}], overwrite=False)
507
- .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '100px')]}], overwrite=False)
508
- .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '225px')]}], overwrite=False)
509
- .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '100px')]}], overwrite=False)
510
- .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '100px')]}], overwrite=False)
511
- # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False)
512
- .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False)
513
- .set_properties(
514
- **{'background-color':'#d6d6d6'}, # Apply only right border
515
- subset=df_test_merge_small_output.columns[0] # Only affects column 1
516
- )
517
- .set_properties(
518
- **{'border-top': 'none', 'border-bottom': 'none'},
519
- subset=df_test_merge_small_output.columns[0] # Apply only to column 1
520
- )
521
- .apply(highlight_alternate_rows, axis=0, subset=df_test_merge_small_output.columns[1:])
522
- )
523
-
524
-
525
- def add_thick_border(s):
526
- return ['border-top: 3px solid black' if s['Batting'] == 1 else '' for _ in s]
527
-
528
- df_order_style = df_order_style.apply(add_thick_border, axis=1)
529
-
530
-
531
- return df_order_style
532
-
533
- @output
534
- @render.table
535
- def table2():
536
- df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data()
537
- if df_test_merge_small is None:
538
- return pd.DataFrame({"Message": ["No Games as of this time"]})
539
-
540
- df_pivot_sum = df_test_merge_small.group_by(['Player ID', 'Player','Bats']).agg([
541
- pl.sum('count').alias('GP')])
542
-
543
- df_pivot_order = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Batting', values='count', aggregate_function='sum')
544
- df_pivot_position = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Position', values='count', aggregate_function='sum')
545
- df_pivot_hand = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Pitcher Hand', values='count', aggregate_function='sum')
546
-
547
- df_test_merge = df_pivot_sum.join(df_pivot_order, on=['Player ID', 'Player'], how='left')
548
- df_test_merge = df_test_merge.join(df_pivot_position, on=['Player ID', 'Player'], how='left')
549
- df_test_merge = df_test_merge.join(df_pivot_hand, on=['Player ID', 'Player'], how='left').fill_null(0)
550
- df_test_merge = df_test_merge.sort(['GP']+[str(x) for x in list(range(1,10))]
551
- ,descending=[True]+[True]*9)
552
-
553
-
554
-
555
- df_test_merge = df_test_merge.with_columns(
556
- pl.concat_str(
557
- [
558
- pl.lit('<a href=https://baseballsavant.mlb.com/savant-player/'),
559
- pl.col('Player ID').cast(pl.Utf8).str.slice(2),
560
- pl.lit(' target="_blank">'),
561
- pl.col('Player'),
562
- pl.lit('</a>')
563
- ]
564
- ).alias('Batter')
565
- )
566
-
567
-
568
-
569
- df_test_merge = df_test_merge.select([
570
- 'Player ID','Batter','Bats', 'GP', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'LHP', 'RHP'
571
- ])
572
-
573
- # First convert your data to hierarchical columns
574
- cols = {
575
- ('Player Info', 'Player ID'): 'Player ID',
576
- ('Player Info', 'Batter'): 'Batter',
577
- ('Player Info', 'Bats'): 'Bats',
578
- ('Player Info', 'GP'): 'GP',
579
- ('Batting Order', '1'): '1',
580
- ('Batting Order', '2'): '2',
581
- ('Batting Order', '3'): '3',
582
- ('Batting Order', '4'): '4',
583
- ('Batting Order', '5'): '5',
584
- ('Batting Order', '6'): '6',
585
- ('Batting Order', '7'): '7',
586
- ('Batting Order', '8'): '8',
587
- ('Batting Order', '9'): '9',
588
- ('Position', 'C'): 'C',
589
- ('Position', '1B'): '1B',
590
- ('Position', '2B'): '2B',
591
- ('Position', '3B'): '3B',
592
- ('Position', 'SS'): 'SS',
593
- ('Position', 'LF'): 'LF',
594
- ('Position', 'CF'): 'CF',
595
- ('Position', 'RF'): 'RF',
596
- ('Position', 'DH'): 'DH',
597
- ('Hand', 'LHP'): 'LHP',
598
- ('Hand', 'RHP'): 'RHP'
599
- }
600
- # Assuming your polars DataFrame is called df
601
- # Convert to pandas
602
- df_pandas = df_test_merge.to_pandas()
603
-
604
-
605
- df_pandas = df_pandas.replace({0: ''})
606
-
607
- # Rename columns with multi-index
608
- df_pandas.columns = pd.MultiIndex.from_tuples(
609
- [(k[0], k[1]) for k in cols.keys()]
610
- )
611
-
612
-
613
- df_pivot_style = df_pandas.style
614
- thick_border_cols = [3, 4, 13,22] # 0-based index
615
-
616
-
617
-
618
- # # Create a function to apply gradient only to integers
619
- # def apply_gradient(val):
620
- # if isinstance(val, int): # Check if the value is an integer
621
- # # Normalize the integer for the gradient (optional, here it's just a simple scale)
622
- # print(val)
623
- # return f'background-color: {norm(val)}'
624
-
625
- # return '' # No background for non-integer values
626
- norm = plt.Normalize(vmin=0, vmax=df_pandas.select_dtypes(include=['int']).max().max())
627
-
628
-
629
- def apply_gradient(val):
630
- if isinstance(val, int): # Check if the value is an integer
631
- # Normalize the integer for the gradient
632
- return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}'
633
- return '' # No background for non-integer values
634
-
635
- df_pivot_style =(df_pivot_style.set_precision(0)
636
- .set_table_styles(
637
- [
638
-
639
- {"selector": "td:nth-child(4)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
640
- {"selector": "td:nth-child(13)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
641
- {"selector": "td:nth-child(22)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
642
- {"selector": "td:nth-child(24)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
643
-
644
-
645
- {'selector': 'thead th:nth-child(4)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
646
- {'selector': 'thead th:nth-child(13)', 'props': [('border-right', '3px solid black')]},
647
- {'selector': 'thead th:nth-child(22)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
648
- {'selector': 'thead th:nth-child(24)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
649
-
650
-
651
- {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]},
652
-
653
-
654
- {'selector':'th', 'props' : [('border', '1px solid black')]},
655
-
656
- ],overwrite=False)
657
- .set_properties(**{'border': '3 px'}, overwrite=False)
658
- .set_table_styles([{
659
- 'selector': 'caption',
660
- 'props': [
661
- ('color', ''),
662
- ('fontname', 'Century Gothic'),
663
- ('font-size', '16px'),
664
- ('font-style', 'italic'),
665
- ('font-weight', ''),
666
- ('text-align', 'centre'),
667
- ]
668
- },
669
- {
670
- 'selector': 'th',
671
- 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')]
672
- },
673
- {
674
- 'selector': 'td',
675
- 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')]
676
- }], overwrite=False)
677
-
678
- .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False)
679
- .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False)
680
-
681
- .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False)
682
- .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False)
683
- .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False)
684
- .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False)
685
- .hide_index()
686
- .set_properties(**{'border': '1px black solid'})
687
- .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '100px')]}], overwrite=False)
688
- .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '225px')]}], overwrite=False)
689
- # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False)
690
- .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False)
691
- .apply(highlight_alternate_rows, axis=0, subset=df_pandas.columns[:])
692
- .applymap(apply_gradient)
693
- )
694
- return df_pivot_style
695
-
696
- @output
697
- @render.table
698
- def table3():
699
-
700
- df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data()
701
- if df_test_merge_small is None:
702
- return pd.DataFrame({"Message": ["No Games as of this time"]})
703
- df_test_merge_small_ids = df_test_merge_small.to_pandas()[['Player ID','Player','Team']].drop_duplicates(subset='Player ID').reset_index(drop=True)
704
- df_test_merge_small_ids['yahoo_name'] = df_test_merge_small_ids['Player'].apply(lambda x: (difflib.get_close_matches(x, df_2023['full'])[:1] or [None])[0])
705
- df_test_merge_small_ids = df_test_merge_small_ids.merge(right=team_abb_df,left_on=['Team'],right_on=['mlb_team'],how='left')
706
-
707
-
708
- #summary_2023 = summary_2023.merge(right=df_2023[['full','pos_new','percent_owned','display_position']],left_on=['cap_name','pos'],right_on=['full','pos_new'],how='left')
709
- df_test_merge_small_ids = df_test_merge_small_ids.merge(right=df_2023[['full','editorial_team_abbr','average_pick','display_position']],left_on=['yahoo_name','yahoo_team'],right_on=['full','editorial_team_abbr'],how='left').dropna()
710
-
711
- df_test_merge_small_eli = df_test_merge_small.to_pandas().merge(right=df_test_merge_small_ids[['Player ID','average_pick','display_position']],left_on=['Player ID'],right_on=['Player ID'],how='inner').fillna('')
712
- df_test_merge_small_eli['average_pick'] = df_test_merge_small_eli['average_pick'].replace('-','')
713
- df_test_merge_small_eli_small = df_test_merge_small_eli[df_test_merge_small_eli.apply(lambda x: x.Position not in x.display_position, axis=1)]
714
- df_test_merge_small_eli_small = df_test_merge_small_eli_small[df_test_merge_small_eli_small.Position != 'DH'].reset_index(drop=True)
715
- df_test_merge_small_eli_small_pivot = df_test_merge_small_eli_small.pivot_table(index=['Player ID','Player','Team','average_pick','display_position'], columns='Position', values='count', aggfunc='count').fillna(0)
716
- df_test_merge_small_eli_small_pivot['GP'] = df_test_merge_small_eli_small_pivot.sum(axis=1)
717
- df_test_merge_small_eli_small_pivot.index.names = ['Player ID','Player','Team','ADP','Yahoo Position']
718
-
719
- elig_list = ['GP','C','1B','2B','3B','SS','LF','CF','RF']
720
- for i in elig_list:
721
- if i not in df_test_merge_small_eli_small_pivot:
722
- df_test_merge_small_eli_small_pivot[i] = ''
723
- df_test_merge_small_eli_small_pivot = df_test_merge_small_eli_small_pivot[['GP','C','1B','2B','3B','SS','LF','CF','RF']].sort_values(by='GP',ascending=False)
724
-
725
- # df_test_merge_small_eli_small_pivot = df_test_merge_small_eli_small_pivot.astype({col: 'int' for col in df_test_merge_small_eli_small_pivot.columns})
726
-
727
- # First convert your data to hierarchical columns
728
- cols = {
729
- ('Player Info', 'Player ID'): 'Player ID',
730
- ('Player Info', 'Player'): 'Player',
731
- ('Player Info', 'Team'): 'Team',
732
- ('Player Info', 'ADP'): 'ADP',
733
- ('Player Info', 'Yahoo Position '): 'Yahoo Position',
734
- ('Starts at New Position', 'GP'): 'GP',
735
- ('Starts at New Position', 'C'): 'C',
736
- ('Starts at New Position', '1B'): '1B',
737
- ('Starts at New Position', '2B'): '2B',
738
- ('Starts at New Position', '3B'): '3B',
739
- ('Starts at New Position', 'SS'): 'SS',
740
- ('Starts at New Position', 'LF'): 'LF',
741
- ('Starts at New Position', 'CF'): 'CF',
742
- ('Starts at New Position', 'RF'): 'RF',
743
-
744
- }
745
- # Assuming your polars DataFrame is called df
746
- # Convert to pandas
747
- df_yahoo_pandas = df_test_merge_small_eli_small_pivot.reset_index()
748
-
749
- df_yahoo_pandas = df_yahoo_pandas[~df_yahoo_pandas['Yahoo Position'].str.contains('P')]
750
-
751
- norm = plt.Normalize(vmin=0, vmax=df_yahoo_pandas['GP'].max())
752
- df_yahoo_pandas = df_yahoo_pandas.replace({0: ''})
753
-
754
- # Rename columns with multi-index
755
- df_yahoo_pandas.columns = pd.MultiIndex.from_tuples(
756
- [(k[0], k[1]) for k in cols.keys()]
757
- )
758
-
759
- df_yahoo_style = df_yahoo_pandas.style
760
-
761
-
762
-
763
- def apply_gradient(val):
764
- if isinstance(val, float): # Check if the value is an integer
765
- # Normalize the integer for the gradient
766
- return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}'
767
- return '' # No background for non-integer values
768
-
769
- df_yahoo_style = (df_yahoo_style.set_precision(0)
770
- .set_table_styles(
771
- [
772
-
773
- {"selector": "td:nth-child(5)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
774
- {"selector": "td:nth-child(6)", "props": [("border-right", "3px solid black")]},
775
- {"selector": "td:nth-child(14)", "props": [("border-right", "3px solid black")]},
776
-
777
- {'selector': 'thead th:nth-child(5)', 'props': [('border-right', '3px solid black')]},
778
- {'selector': 'thead th:nth-child(6)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
779
- {'selector': 'thead th:nth-child(14)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
780
-
781
- {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]},
782
-
783
-
784
- {'selector':'th', 'props' : [('border', '1px solid black')]},
785
-
786
- ],overwrite=False)
787
- .set_properties(**{'border': '3 px'}, overwrite=False)
788
- .set_table_styles([{
789
- 'selector': 'caption',
790
- 'props': [
791
- ('color', ''),
792
- ('fontname', 'Century Gothic'),
793
- ('font-size', '16px'),
794
- ('font-style', 'italic'),
795
- ('font-weight', ''),
796
- ('text-align', 'centre'),
797
- ]
798
- },
799
- {
800
- 'selector': 'th',
801
- 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')]
802
- },
803
- {
804
- 'selector': 'td',
805
- 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')]
806
- }], overwrite=False)
807
-
808
- .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False)
809
- .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False)
810
-
811
- .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False)
812
- .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False)
813
- .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False)
814
- .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False)
815
- .hide_index()
816
- .set_properties(**{'border': '1px black solid'})
817
-
818
- .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '100px')]}], overwrite=False)
819
- .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '225px')]}], overwrite=False)
820
- .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '50px')]}], overwrite=False)
821
- .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '50px')]}], overwrite=False)
822
- .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '150px')]}], overwrite=False)
823
- # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False)
824
- .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False)
825
- .apply(highlight_alternate_rows, axis=0, subset=df_yahoo_pandas.columns[:])
826
- .applymap(apply_gradient)
827
- )
828
- return df_yahoo_style
829
-
830
- app = App(app_ui, server)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #import packages
2
+ import pandas as pd
3
+ import json
4
+ import numpy as np
5
+ import requests
6
+ pd.options.mode.chained_assignment = None
7
+ from datetime import datetime
8
+ import time
9
+ import difflib
10
+ from datetime import datetime, timedelta
11
+ import api_scraper
12
+ import polars as pl
13
+ import matplotlib.colors
14
+ import matplotlib.colors as mcolors
15
+ from shiny import App, ui, render, reactive
16
+
17
+ def add_empty_rows(df, n_empty, period):
18
+ """ adds 'n_empty' empty rows every 'period' rows to 'df'.
19
+ Returns a new DataFrame. """
20
+
21
+ # to make sure that the DataFrame index is a RangeIndex(start=0, stop=len(df))
22
+ # and that the original df object is not mutated.
23
+ df = df.reset_index(drop=True)
24
+
25
+ # length of the new DataFrame containing the NaN rows
26
+ len_new_index = len(df) + n_empty*(len(df) // period)
27
+ # index of the new DataFrame
28
+ new_index = pd.RangeIndex(len_new_index)
29
+
30
+ # add an offset (= number of NaN rows up to that row)
31
+ # to the current df.index to align with new_index.
32
+ df.index += n_empty * (df.index
33
+ .to_series()
34
+ .groupby(df.index // period)
35
+ .ngroup())
36
+
37
+ # reindex by aligning df.index with new_index.
38
+ # Values of new_index not present in df.index are filled with NaN.
39
+ new_df = df.reindex(new_index)
40
+
41
+ return new_df
42
+
43
+ unique_team_list = [120,
44
+ 141,
45
+ 140,
46
+ 139,
47
+ 138,
48
+ 137,
49
+ 136,
50
+ 135,
51
+ 134,
52
+ 143,
53
+ 133,
54
+ 147,
55
+ 121,
56
+ 142,
57
+ 158,
58
+ 146,
59
+ 119,
60
+ 108,
61
+ 118,
62
+ 117,
63
+ 116,
64
+ 145,
65
+ 115,
66
+ 114,
67
+ 113,
68
+ 112,
69
+ 111,
70
+ 110,
71
+ 109,
72
+ 144]
73
+
74
+ ## Create a dataframe of teams to assist with selecting a player to search
75
+ #specifically for the case where multiple players share the same name
76
+ #Make an api call to get a dictionary of all teams
77
+ teams = requests.get(url='https://statsapi.mlb.com/api/v1/teams/').json()
78
+ #Select only teams that are at the MLB level
79
+ mlb_teams_city = [x['franchiseName'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
80
+ mlb_teams_name = [x['teamName'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
81
+ mlb_teams_franchise = [x['name'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
82
+ mlb_teams_id = [x['id'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
83
+ mlb_teams_abb = [x['abbreviation'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball']
84
+
85
+ #Create a dataframe of all the teams
86
+ mlb_teams_df = pd.DataFrame(data={'team_id':mlb_teams_id,'city':mlb_teams_franchise,'name':mlb_teams_name,'franchise':mlb_teams_franchise,'abbreviation':mlb_teams_abb})
87
+ ##Create a dataframe of all players in the database
88
+ #Make an api call to get a dictionary of all players
89
+ player_data = requests.get(url='https://statsapi.mlb.com/api/v1/sports/11/players').json()
90
+
91
+ #Select relevant data that will help distinguish players from one another
92
+ fullName_list = [x['fullName'] for x in player_data['people']]
93
+ id_list = [x['id'] for x in player_data['people']]
94
+ position_list = [x['primaryPosition']['abbreviation'] for x in player_data['people']]
95
+ team_list = [x['currentTeam']['id']for x in player_data['people']]
96
+
97
+ #Create a dataframe of players and their current team ids
98
+ player_df_all = pd.DataFrame(data={'id':id_list,'name':fullName_list,'position':position_list,'team_id':team_list})
99
+ #Use the teams dataframe to merge the team name to the players dataframe
100
+ player_df_all = player_df_all.merge(right=mlb_teams_df[['team_id','franchise']],left_on='team_id',right_on='team_id',how='left',suffixes=['','_y'])
101
+ #drop the duplicated id column
102
+ player_df_all = player_df_all.drop(columns=['team_id'])
103
+ #make a column of the names all uppercase to make lookups easier
104
+ player_df_all['upper_name'] = player_df_all['name'].str.upper()
105
+ #rename to make the data clearer
106
+ player_df_all = player_df_all.rename(columns={'franchise':'currentTeam'})
107
+
108
+
109
+
110
+ import matplotlib.pyplot as plt
111
+ colour_palette = ['#FFB000','#648FFF','#785EF0',
112
+ '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED']
113
+
114
+ cmap_up = mcolors.LinearSegmentedColormap.from_list("", ['#FFFFFF', '#FFB000'])
115
+
116
+
117
+ # Function to alternate row colors
118
+ def highlight_alternate_rows(x):
119
+ return ['background-color: #ebebeb' if i % 2 == 0 else '' for i in range(len(x))]
120
+ # Function to apply thick border to data cells
121
+ # Columns after which we want a thick vertical line
122
+
123
+ scraper = api_scraper.MLB_Scrape()
124
+ df_teams = scraper.get_teams()
125
+
126
+ teams_mlb = df_teams.filter(pl.col("league_id").is_in([103,104])).sort("abbreviation")
127
+ teams_dict = dict(zip(teams_mlb['team_id'],teams_mlb['abbreviation']))
128
+
129
+ teams_name_dict = dict(zip(teams_mlb['team_id'],teams_mlb['franchise']))
130
+
131
+ {109: 'Arizona Diamondbacks',
132
+ 144: 'Atlanta Braves',
133
+ 110: 'Baltimore Orioles',
134
+ 111: 'Boston Red Sox',
135
+ 112: 'Chicago Cubs',
136
+ 145: 'Chicago White Sox',
137
+ 113: 'Cincinnati Reds',
138
+ 114: 'Cleveland Guardians',
139
+ 115: 'Colorado Rockies',
140
+ 116: 'Detroit Tigers',
141
+ 117: 'Houston Astros',
142
+ 118: 'Kansas City Royals',
143
+ 108: 'Los Angeles Angels',
144
+ 119: 'Los Angeles Dodgers',
145
+ 146: 'Miami Marlins',
146
+ 158: 'Milwaukee Brewers',
147
+ 142: 'Minnesota Twins',
148
+ 121: 'New York Mets',
149
+ 147: 'New York Yankees',
150
+ #133: 'Athletics',
151
+ 133: 'Oakland Athletics',
152
+ 143: 'Philadelphia Phillies',
153
+ 134: 'Pittsburgh Pirates',
154
+ 135: 'San Diego Padres',
155
+ 137: 'San Francisco Giants',
156
+ 136: 'Seattle Mariners',
157
+ 138: 'St. Louis Cardinals',
158
+ 139: 'Tampa Bay Rays',
159
+ 140: 'Texas Rangers',
160
+ 141: 'Toronto Blue Jays',
161
+ 120: 'Washington Nationals'}
162
+
163
+
164
+ data_r_1 = requests.get("https://pub-api-ro.fantasysports.yahoo.com/fantasy/v2/league/458.l.1423;out=settings/players;position=ALL;start=0;count=5000;sort=rank_season;search=;out=percent_owned;out=auction_values,ranks;ranks=season;ranks_by_position=season;out=expert_ranks;expert_ranks.rank_type=projected_season_remaining/draft_analysis;cut_types=diamond;slices=last7days?format=json_f").json()
165
+ #data_r_2 = requests.get("https://pub-api-ro.fantasysports.yahoo.com/fantasy/v2/league/422.l.1416;out=settings/players;position=ALL;start=758;count=5000;sort=rank_season;search=;out=auction_values,ranks;ranks=season;ranks_by_position=season;out=expert_ranks;expert_ranks.rank_type=projected_season_remaining/draft_analysis;cut_types=diamond;slices=last7days?format=json_f").json()
166
+ # 757 is bad
167
+ #https://pub-api-ro.fantasysports.yahoo.com/fantasy/v2/league/422.l.1416;out=settings/players;position=ALL;start=0;count=756;sort=rank_season;search=;out=auction_values,ranks;ranks=season;ranks_by_position=season;out=expert_ranks;expert_ranks.rank_type=projected_season_remaining/draft_analysis;cut_types=diamond;slices=last7days?format=json_f
168
+
169
+ total_list = []
170
+
171
+ for x in data_r_1['fantasy_content']['league']['players']:
172
+ single_list = []
173
+
174
+ single_list.append((x['player']['player_id']))
175
+ single_list.append(x['player']['name']['full'])
176
+ single_list.append(x['player']['name']['first'])
177
+ single_list.append(x['player']['name']['last'])
178
+ single_list.append(x['player']['draft_analysis']['average_pick'])
179
+ single_list.append(x['player']['average_auction_cost'])
180
+ single_list.append(x['player']['display_position'])
181
+ single_list.append(x['player']['editorial_team_abbr'])
182
+ total_list.append(single_list)
183
+
184
+ df_2023 = pd.DataFrame(data=total_list, columns=['player_id','full','first','last','average_pick', 'average_cost','display_position','editorial_team_abbr'])
185
+
186
+
187
+ team_abb_list = ['ATL', 'AZ', 'BAL', 'BOS', 'CHC', 'CIN', 'CLE', 'COL', 'CWS',
188
+ 'DET', 'HOU', 'KC', 'LAA', 'LAD', 'MIA', 'MIL', 'MIN', 'NYM',
189
+ 'NYY', 'ATH', 'PHI', 'PIT', 'SD', 'SEA', 'SF', 'STL', 'TB', 'TEX',
190
+ 'TOR', 'WSH']
191
+
192
+ team_abb_list_yahoo = ['ATL', 'ARI', 'BAL', 'BOS', 'CHC', 'CIN', 'CLE', 'COL', 'CWS',
193
+ 'DET', 'HOU', 'KC', 'LAA', 'LAD', 'MIA', 'MIL', 'MIN', 'NYM',
194
+ 'NYY', 'ATH', 'PHI', 'PIT', 'SD', 'SEA', 'SF', 'STL', 'TB', 'TEX',
195
+ 'TOR', 'WSH']
196
+ team_abb_df = pd.DataFrame({'mlb_team':team_abb_list,'yahoo_team':team_abb_list_yahoo})
197
+
198
+
199
+
200
+ from shiny import App, ui, render
201
+ import pandas as pd
202
+
203
+ # Create sample data for the tables
204
+ data1 = pd.DataFrame({
205
+ 'Name': ['Alice', 'Bob', 'Charlie'],
206
+ 'Age': [25, 30, 35],
207
+ 'City': ['New York', 'London', 'Paris']
208
+ })
209
+
210
+ data2 = pd.DataFrame({
211
+ 'Product': ['Laptop', 'Phone', 'Tablet'],
212
+ 'Price': [1200, 800, 500],
213
+ 'Stock': [50, 100, 75]
214
+ })
215
+
216
+ data3 = pd.DataFrame({
217
+ 'Country': ['USA', 'UK', 'France'],
218
+ 'Population': ['331M', '67M', '67M'],
219
+ 'Language': ['English', 'English', 'French']
220
+ })
221
+
222
+ app_ui = ui.page_sidebar(
223
+
224
+ ui.sidebar(
225
+ ui.markdown("#### 2025 Spring Training Lineup Tracker"),
226
+ ui.input_select(
227
+ "team_id",
228
+ "Select Team",
229
+ choices=teams_name_dict
230
+ ),
231
+ # ui.hr(), # Add a horizontal line for separation
232
+ ui.div(
233
+
234
+ ui.div(
235
+ "By: ", # Plain text
236
+ ui.tags.a(
237
+ "@TJStats", # Only the handle is linked
238
+ href="https://x.com/TJStats",
239
+ target="_blank"
240
+ )
241
+ ),
242
+ ui.tags.p("Data: MLB"),
243
+ ui.tags.p(
244
+ ui.tags.a(
245
+ "Support me on Patreon for more baseball content",
246
+ href="https://www.patreon.com/TJ_Stats",
247
+ target="_blank"
248
+ )
249
+ ),
250
+ style="color: #666; text-align: left;"
251
+
252
+
253
+ )
254
+ ,width=500),
255
+
256
+ ui.card(
257
+ ui.output_text("selected_team_info"),
258
+ ui.navset_card_tab(
259
+ ui.nav_panel(
260
+ "Lineups",
261
+ ui.div({"style": "font-size:1.7em;"}, ui.output_text("lineup_title")),
262
+ ui.output_table("table1")
263
+ ),
264
+ ui.nav_panel(
265
+ "Summary",
266
+ ui.div({"style": "font-size:1.7em;"}, ui.output_text("summary_title")),
267
+ ui.output_table("table2")
268
+ ),
269
+ ui.nav_panel(
270
+ "Fantasy Eligibility",
271
+ ui.div({"style": "font-size:1.7em;"}, ui.output_text("fantasy_title")),
272
+ ui.output_table("table3")
273
+ )
274
+ )
275
+ )
276
+ )
277
+
278
+ def server(input, output, session):
279
+
280
+ @render.text
281
+ def lineup_title():
282
+
283
+ return f"{teams_name_dict[int(input.team_id())]} Spring Training Lineups"
284
+
285
+ @render.text
286
+ def summary_title():
287
+
288
+ return f"{teams_name_dict[int(input.team_id())]} Spring Training Lineup Summary"
289
+
290
+ @render.text
291
+ def fantasy_title():
292
+
293
+ return f"{teams_name_dict[int(input.team_id())]} Spring Training Position Eligibility Tracker - Yahoo"
294
+
295
+
296
+ @reactive.calc
297
+ def cached_data():
298
+ team_id_select = int(input.team_id())
299
+
300
+ df_schedule = scraper.get_schedule(year_input=[2025],sport_id=[1],game_type=['S','E'])
301
+
302
+ # df_schedule_p = scraper.get_schedule(year_input=[2024],sport_id=[21],game_type=['E'])
303
+
304
+ # df_schedule_all = pl.concat([df_schedule,df_schedule_p])
305
+
306
+ df_schedule_all = pl.concat([df_schedule])
307
+
308
+
309
+ df_schedule_team = df_schedule_all.filter((pl.col('date') <= datetime.today().date())&((pl.col('home_id') == team_id_select)|(pl.col('away_id') == team_id_select)))
310
+ if df_schedule_team.is_empty():
311
+ return None, None, None
312
+ statcast_dict = dict(zip(df_schedule_team['game_id'],df_schedule_team['gameday_type']))
313
+ game_list = df_schedule_team['game_id'][:]
314
+ game_data = scraper.get_data(game_list)
315
+
316
+ print('Importing New Games.')
317
+ lineup_data = []
318
+ game_id = []
319
+ date = []
320
+ player_id = []
321
+ player_name = []
322
+ position = []
323
+ team_id = []
324
+ batting_order = []
325
+ handedness_batter = []
326
+ away_home = []
327
+ handedness_pitcher = []
328
+ pitcher_name = []
329
+ for y in range(0,len(game_data)):
330
+ game_id.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])*[game_data[y]['gameData']['game']['pk']])
331
+ date.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])*[game_data[y]['gameData']['datetime']['officialDate']])
332
+ player_id.append([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
333
+ player_name.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['person']['fullName'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
334
+ position.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['allPositions'][0]['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
335
+ team_id.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['parentTeamId'] if 'parentTeamId' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
336
+ batting_order.append([game_data[y]['liveData']['boxscore']['teams']['away']['players'][x]['battingOrder'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
337
+ away_home.append(['away' if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
338
+ handedness_batter.append([game_data[y]['gameData']['players'][x]['batSide']['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['away']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
339
+ handedness_pitcher.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['home']['id'])]['pitchHand']['code']+'HP' if 'home' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
340
+ pitcher_name.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['home']['id'])]['fullName'] if 'home' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['away']['players']])
341
+
342
+ game_id.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])*[game_data[y]['gameData']['game']['pk']])
343
+ date.append(len([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])*[game_data[y]['gameData']['datetime']['officialDate']])
344
+ player_id.append([x if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
345
+ player_name.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['person']['fullName'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
346
+ position.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['allPositions'][0]['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
347
+ team_id.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['parentTeamId'] if 'parentTeamId' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
348
+ batting_order.append([game_data[y]['liveData']['boxscore']['teams']['home']['players'][x]['battingOrder'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
349
+ away_home.append(['home' if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
350
+ handedness_batter.append([game_data[y]['gameData']['players'][x]['batSide']['code'] if 'battingOrder' in game_data[y]['liveData']['boxscore']['teams']['home']['players'][x] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
351
+ handedness_pitcher.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['away']['id'])]['pitchHand']['code']+'HP' if 'away' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
352
+ pitcher_name.append([game_data[y]['gameData']['players']['ID'+str(game_data[y]['gameData']['probablePitchers']['away']['id'])]['fullName'] if 'away' in game_data[y]['gameData']['probablePitchers'] else None for x in game_data[y]['liveData']['boxscore']['teams']['home']['players']])
353
+
354
+
355
+
356
+ game_id_final = [item for sublist in game_id for item in sublist]
357
+ date_final = [item for sublist in date for item in sublist]
358
+ player_id_final = [item for sublist in player_id for item in sublist]
359
+ player_name_final = [item for sublist in player_name for item in sublist]
360
+ position_final = [item for sublist in position for item in sublist]
361
+ team_id_final = [item for sublist in team_id for item in sublist]
362
+ batting_order_final = [item for sublist in batting_order for item in sublist]
363
+ away_home_final = [item for sublist in away_home for item in sublist]
364
+ handedness_batter_final = [item for sublist in handedness_batter for item in sublist]
365
+ handedness_pitcher_final = [item for sublist in handedness_pitcher for item in sublist]
366
+ pitcher_name_final = [item for sublist in pitcher_name for item in sublist]
367
+
368
+ position_df = pl.DataFrame(data={'position':[1,2,3,4,5,6,7,8,9,10],'position_name':['P','C','1B','2B','3B','SS','LF','CF','RF','DH']})
369
+ batting_order_full = pl.DataFrame(data={'game_id':game_id_final ,
370
+ 'date':date_final,
371
+ 'player_id':player_id_final,
372
+ 'player_name':player_name_final,
373
+ 'position':position_final,
374
+ 'team_id':team_id_final,
375
+ 'batting_order':batting_order_final,
376
+ 'away_home':away_home_final,
377
+ 'handedness_batter':handedness_batter_final,
378
+ 'handedness_pitcher':handedness_pitcher_final,
379
+ 'pitcher_name':pitcher_name_final})
380
+
381
+ # batting_order_full = batting_order_full
382
+
383
+
384
+
385
+ batting_order_full = batting_order_full.with_columns(pl.col('position').cast(pl.Int32))
386
+ batting_order_full = batting_order_full.join(df_teams[['team_id', 'franchise', 'abbreviation']], on='team_id', how='left')
387
+ position_df = position_df.with_columns(pl.col('position').cast(pl.Int32))
388
+ batting_order_full = batting_order_full.join(position_df, on='position', how='left')
389
+ batting_order_full_opp = batting_order_full.filter(pl.col('team_id') != team_id_select)
390
+
391
+ batting_order_full = batting_order_full.filter(pl.col('team_id') == team_id_select)
392
+ batting_order_full_filter = batting_order_full.filter(pl.col('batting_order').cast(pl.Int32) % 100 == 0)
393
+
394
+ batting_order_full_filter = batting_order_full_filter.sort(by=['abbreviation', 'franchise', 'date', 'game_id', 'batting_order'], descending=[False, False, False, False, False]).with_row_count().drop('row_nr')
395
+ batting_order_full_filter = batting_order_full_filter.unique(subset=['batting_order','game_id','away_home'])
396
+
397
+ batting_order_full_filter = batting_order_full_filter.with_columns(pl.col('batting_order').cast(pl.Int32))
398
+
399
+
400
+ df_test_merge = batting_order_full_filter.clone()
401
+ df_test_merge = df_test_merge.with_columns(pl.col('*').fill_null(np.nan))
402
+
403
+ df_test_merge = df_test_merge.sort(['player_id', 'date']).fill_null(strategy='forward')
404
+ df_test_merge_small = df_test_merge.select([
405
+ 'game_id', 'date', 'abbreviation', 'batting_order', 'player_id', 'player_name',
406
+ 'position_name', 'handedness_batter', 'handedness_pitcher', 'pitcher_name'
407
+ ]).sort(['date', 'game_id', 'abbreviation', 'batting_order'])
408
+
409
+ df_test_merge_small = df_test_merge_small.select(['game_id',
410
+ 'date', 'abbreviation', 'batting_order', 'player_id', 'player_name',
411
+ 'position_name', 'handedness_batter', 'handedness_pitcher', 'pitcher_name'
412
+ ]).fill_null('')
413
+
414
+ df_test_merge_small = df_test_merge_small.with_columns([
415
+ (pl.col('batting_order').cast(pl.Int32) / 100).cast(pl.Int32).alias('batting_order'),
416
+ pl.lit(1).alias('count'),
417
+ ])
418
+
419
+ df_test_merge_small = df_test_merge_small.rename({'game_id': 'Game ID',
420
+ 'date': 'Date', 'abbreviation': 'Team', 'batting_order': 'Batting',
421
+ 'player_id': 'Player ID', 'player_name': 'Player', 'position_name': 'Position',
422
+ 'handedness_batter': 'Bats', 'handedness_pitcher': 'Pitcher Hand',
423
+ 'pitcher_name': 'Pitcher Name'
424
+ })
425
+
426
+ return df_test_merge_small,batting_order_full_opp,statcast_dict
427
+
428
+
429
+
430
+ @output
431
+ @render.table
432
+ def table1():
433
+ df,batting_order_full_opp,statcast_dict = cached_data()
434
+ if df is None:
435
+ return pd.DataFrame({"Message": ["No Games as of this time"]})
436
+ team_opp = dict(zip(batting_order_full_opp['game_id'],batting_order_full_opp['abbreviation']))
437
+
438
+ df_test_merge_small_pd = df.to_pandas()
439
+
440
+ df_test_merge_small_pd['Opponent'] = df_test_merge_small_pd['Game ID'].map(team_opp)
441
+
442
+ # Create a new column with the date and opponent for the first occurrence of each game ID
443
+ df_test_merge_small_pd['Game'] = np.where(
444
+ ~df_test_merge_small_pd.duplicated(subset=['Game ID'], keep='first'),
445
+ 0,
446
+ None
447
+ )
448
+
449
+ df_test_merge_small_pd['gameday_type'] = df_test_merge_small_pd['Game ID'].map(statcast_dict)
450
+ df_test_merge_small_pd['Statcast'] = np.where(
451
+ df_test_merge_small_pd['gameday_type'].isin(['E', 'P']),
452
+ True,
453
+ False
454
+ )
455
+
456
+
457
+ df_test_merge_small_pd['Pitcher'] = df_test_merge_small_pd['Pitcher Name'] + ' (' + df_test_merge_small_pd['Pitcher Hand'] + ')'
458
+
459
+
460
+ df_test_merge_small_pd['Batter'] = '<a href=https://baseballsavant.mlb.com/savant-player/'+'df_test_merge_small_pd["Player ID"].astype(str).str[2:]'+'target="_blank">'+df_test_merge_small_pd["Player"]+'</a>'
461
+
462
+
463
+ df_test_merge_small_pd['Gameday'] = '<a href=https://www.mlb.com/gameday/'+df_test_merge_small_pd["Game ID"].astype(int).astype(str)+' target="_blank">Gameday</a>'
464
+ df_test_merge_small_pd['Savant'] = np.where(
465
+ df_test_merge_small_pd['Statcast'],
466
+ '<a href=https://baseballsavant.mlb.com/gamefeed?gamePk='+df_test_merge_small_pd["Game ID"].astype(int).astype(str)+' target="_blank">Statcast</a>',
467
+ '(No Statcast)'
468
+ )
469
+
470
+ game_index = df_test_merge_small_pd.loc[~(df_test_merge_small_pd['Game'].isnull()), 'Game'].index
471
+
472
+ df_test_merge_small_pd.loc[game_index+2,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Date'])
473
+
474
+ df_test_merge_small_pd.loc[game_index+3,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Team'] + ' vs ' + df_test_merge_small_pd.loc[game_index+0,'Opponent'])
475
+
476
+ df_test_merge_small_pd.loc[game_index+4,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Pitcher'])
477
+ df_test_merge_small_pd.loc[game_index+5,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Gameday'])
478
+ df_test_merge_small_pd.loc[game_index+6,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Savant'])
479
+
480
+ df_test_merge_small_pd['Game'] = df_test_merge_small_pd['Game'].replace(0,None).fillna('')
481
+
482
+ df_test_merge_small_output = df_test_merge_small_pd[['Game',
483
+
484
+ 'Batting',
485
+ 'Player',
486
+ 'Position',
487
+ 'Bats']]
488
+
489
+ df_order_style = df_test_merge_small_output.style
490
+
491
+
492
+ df_order_style = (df_order_style.set_precision(0)
493
+ .set_table_styles(
494
+ [
495
+
496
+
497
+ {'selector':'th', 'props' : [('border', '1px solid black')]},
498
+
499
+ ],overwrite=False)
500
+ .set_properties(**{'border': '3 px'}, overwrite=False)
501
+ .set_table_styles([{
502
+ 'selector': 'caption',
503
+ 'props': [
504
+ ('color', ''),
505
+ ('fontname', 'Century Gothic'),
506
+ ('font-size', '16px'),
507
+ ('font-style', 'italic'),
508
+ ('font-weight', ''),
509
+ ('text-align', 'centre'),
510
+ ]
511
+ },
512
+ {
513
+ 'selector': 'th',
514
+ 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')]
515
+ },
516
+ {
517
+ 'selector': 'td',
518
+ 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')]
519
+ }], overwrite=False)
520
+
521
+ .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '20px'}, overwrite=False)
522
+ .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False)
523
+
524
+ .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#d6d6d6')]}], overwrite=False)
525
+ .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False)
526
+ .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False)
527
+ .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False)
528
+ .hide_index()
529
+ .set_properties(**{'border': '1px black solid'})
530
+ .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '225px')]}], overwrite=False)
531
+ .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '100px')]}], overwrite=False)
532
+ .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '225px')]}], overwrite=False)
533
+ .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '100px')]}], overwrite=False)
534
+ .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '100px')]}], overwrite=False)
535
+ # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False)
536
+ .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False)
537
+ .set_properties(
538
+ **{'background-color':'#d6d6d6'}, # Apply only right border
539
+ subset=df_test_merge_small_output.columns[0] # Only affects column 1
540
+ )
541
+ .set_properties(
542
+ **{'border-top': 'none', 'border-bottom': 'none'},
543
+ subset=df_test_merge_small_output.columns[0] # Apply only to column 1
544
+ )
545
+ .apply(highlight_alternate_rows, axis=0, subset=df_test_merge_small_output.columns[1:])
546
+ )
547
+
548
+
549
+ def add_thick_border(s):
550
+ return ['border-top: 3px solid black' if s['Batting'] == 1 else '' for _ in s]
551
+
552
+ df_order_style = df_order_style.apply(add_thick_border, axis=1)
553
+
554
+
555
+ return df_order_style
556
+
557
+ @output
558
+ @render.table
559
+ def table2():
560
+ df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data()
561
+ if df_test_merge_small is None:
562
+ return pd.DataFrame({"Message": ["No Games as of this time"]})
563
+
564
+ df_pivot_sum = df_test_merge_small.group_by(['Player ID', 'Player','Bats']).agg([
565
+ pl.sum('count').alias('GP')])
566
+
567
+ df_pivot_order = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Batting', values='count', aggregate_function='sum')
568
+ df_pivot_position = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Position', values='count', aggregate_function='sum')
569
+ df_pivot_hand = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Pitcher Hand', values='count', aggregate_function='sum')
570
+
571
+ df_test_merge = df_pivot_sum.join(df_pivot_order, on=['Player ID', 'Player'], how='left')
572
+ df_test_merge = df_test_merge.join(df_pivot_position, on=['Player ID', 'Player'], how='left')
573
+ df_test_merge = df_test_merge.join(df_pivot_hand, on=['Player ID', 'Player'], how='left').fill_null(0)
574
+ df_test_merge = df_test_merge.sort(['GP']+[str(x) for x in list(range(1,10))]
575
+ ,descending=[True]+[True]*9)
576
+
577
+
578
+
579
+ df_test_merge = df_test_merge.with_columns(
580
+ pl.concat_str(
581
+ [
582
+ pl.lit('<a href=https://baseballsavant.mlb.com/savant-player/'),
583
+ pl.col('Player ID').cast(pl.Utf8).str.slice(2),
584
+ pl.lit(' target="_blank">'),
585
+ pl.col('Player'),
586
+ pl.lit('</a>')
587
+ ]
588
+ ).alias('Batter')
589
+ )
590
+
591
+
592
+
593
+ df_test_merge = df_test_merge.select([
594
+ 'Player ID','Batter','Bats', 'GP', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'LHP', 'RHP'
595
+ ])
596
+
597
+ # First convert your data to hierarchical columns
598
+ cols = {
599
+ ('Player Info', 'Player ID'): 'Player ID',
600
+ ('Player Info', 'Batter'): 'Batter',
601
+ ('Player Info', 'Bats'): 'Bats',
602
+ ('Player Info', 'GP'): 'GP',
603
+ ('Batting Order', '1'): '1',
604
+ ('Batting Order', '2'): '2',
605
+ ('Batting Order', '3'): '3',
606
+ ('Batting Order', '4'): '4',
607
+ ('Batting Order', '5'): '5',
608
+ ('Batting Order', '6'): '6',
609
+ ('Batting Order', '7'): '7',
610
+ ('Batting Order', '8'): '8',
611
+ ('Batting Order', '9'): '9',
612
+ ('Position', 'C'): 'C',
613
+ ('Position', '1B'): '1B',
614
+ ('Position', '2B'): '2B',
615
+ ('Position', '3B'): '3B',
616
+ ('Position', 'SS'): 'SS',
617
+ ('Position', 'LF'): 'LF',
618
+ ('Position', 'CF'): 'CF',
619
+ ('Position', 'RF'): 'RF',
620
+ ('Position', 'DH'): 'DH',
621
+ ('Pitcher', 'LHP'): 'LHP',
622
+ ('Pitcher', 'RHP'): 'RHP'
623
+ }
624
+ # Assuming your polars DataFrame is called df
625
+ # Convert to pandas
626
+ df_pandas = df_test_merge.to_pandas()
627
+
628
+
629
+ df_pandas = df_pandas.replace({0: ''})
630
+
631
+ # Rename columns with multi-index
632
+ df_pandas.columns = pd.MultiIndex.from_tuples(
633
+ [(k[0], k[1]) for k in cols.keys()]
634
+ )
635
+
636
+
637
+ df_pivot_style = df_pandas.style
638
+ thick_border_cols = [3, 4, 13,22] # 0-based index
639
+
640
+
641
+
642
+ # # Create a function to apply gradient only to integers
643
+ # def apply_gradient(val):
644
+ # if isinstance(val, int): # Check if the value is an integer
645
+ # # Normalize the integer for the gradient (optional, here it's just a simple scale)
646
+ # print(val)
647
+ # return f'background-color: {norm(val)}'
648
+
649
+ # return '' # No background for non-integer values
650
+ norm = plt.Normalize(vmin=0, vmax=df_pandas.select_dtypes(include=['int']).max().max())
651
+
652
+
653
+ def apply_gradient(val):
654
+ if isinstance(val, int): # Check if the value is an integer
655
+ # Normalize the integer for the gradient
656
+ return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}'
657
+ return '' # No background for non-integer values
658
+
659
+ df_pivot_style =(df_pivot_style.set_precision(0)
660
+ .set_table_styles(
661
+ [
662
+
663
+ {"selector": "td:nth-child(4)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
664
+ {"selector": "td:nth-child(13)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
665
+ {"selector": "td:nth-child(22)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
666
+ {"selector": "td:nth-child(24)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
667
+
668
+
669
+ {'selector': 'thead th:nth-child(4)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
670
+ {'selector': 'thead th:nth-child(13)', 'props': [('border-right', '3px solid black')]},
671
+ {'selector': 'thead th:nth-child(22)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
672
+ {'selector': 'thead th:nth-child(24)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
673
+
674
+
675
+ {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]},
676
+
677
+
678
+ {'selector':'th', 'props' : [('border', '1px solid black')]},
679
+
680
+ ],overwrite=False)
681
+ .set_properties(**{'border': '3 px'}, overwrite=False)
682
+ .set_table_styles([{
683
+ 'selector': 'caption',
684
+ 'props': [
685
+ ('color', ''),
686
+ ('fontname', 'Century Gothic'),
687
+ ('font-size', '16px'),
688
+ ('font-style', 'italic'),
689
+ ('font-weight', ''),
690
+ ('text-align', 'centre'),
691
+ ]
692
+ },
693
+ {
694
+ 'selector': 'th',
695
+ 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')]
696
+ },
697
+ {
698
+ 'selector': 'td',
699
+ 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')]
700
+ }], overwrite=False)
701
+
702
+ .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False)
703
+ .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False)
704
+
705
+ .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False)
706
+ .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False)
707
+ .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False)
708
+ .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False)
709
+ .hide_index()
710
+ .set_properties(**{'border': '1px black solid'})
711
+ .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '100px')]}], overwrite=False)
712
+ .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '225px')]}], overwrite=False)
713
+ # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False)
714
+ .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False)
715
+ .apply(highlight_alternate_rows, axis=0, subset=df_pandas.columns[:])
716
+ .applymap(apply_gradient)
717
+ )
718
+ return df_pivot_style
719
+
720
+ @output
721
+ @render.table
722
+ def table3():
723
+
724
+ df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data()
725
+ if df_test_merge_small is None:
726
+ return pd.DataFrame({"Message": ["No Games as of this time"]})
727
+ df_test_merge_small_ids = df_test_merge_small.to_pandas()[['Player ID','Player','Team']].drop_duplicates(subset='Player ID').reset_index(drop=True)
728
+ df_test_merge_small_ids['yahoo_name'] = df_test_merge_small_ids['Player'].apply(lambda x: (difflib.get_close_matches(x, df_2023['full'])[:1] or [None])[0])
729
+ df_test_merge_small_ids = df_test_merge_small_ids.merge(right=team_abb_df,left_on=['Team'],right_on=['mlb_team'],how='left')
730
+
731
+
732
+ #summary_2023 = summary_2023.merge(right=df_2023[['full','pos_new','percent_owned','display_position']],left_on=['cap_name','pos'],right_on=['full','pos_new'],how='left')
733
+ df_test_merge_small_ids = df_test_merge_small_ids.merge(right=df_2023[['full','editorial_team_abbr','average_pick','display_position']],left_on=['yahoo_name','yahoo_team'],right_on=['full','editorial_team_abbr'],how='left').dropna()
734
+
735
+ df_test_merge_small_eli = df_test_merge_small.to_pandas().merge(right=df_test_merge_small_ids[['Player ID','average_pick','display_position']],left_on=['Player ID'],right_on=['Player ID'],how='inner').fillna('')
736
+ df_test_merge_small_eli['average_pick'] = df_test_merge_small_eli['average_pick'].replace('-','')
737
+ df_test_merge_small_eli_small = df_test_merge_small_eli[df_test_merge_small_eli.apply(lambda x: x.Position not in x.display_position, axis=1)]
738
+ df_test_merge_small_eli_small = df_test_merge_small_eli_small[df_test_merge_small_eli_small.Position != 'DH'].reset_index(drop=True)
739
+ df_test_merge_small_eli_small_pivot = df_test_merge_small_eli_small.pivot_table(index=['Player ID','Player','Team','average_pick','display_position'], columns='Position', values='count', aggfunc='count').fillna(0)
740
+ df_test_merge_small_eli_small_pivot['GP'] = df_test_merge_small_eli_small_pivot.sum(axis=1)
741
+ df_test_merge_small_eli_small_pivot.index.names = ['Player ID','Player','Team','ADP','Yahoo Position']
742
+
743
+ elig_list = ['GP','C','1B','2B','3B','SS','LF','CF','RF']
744
+ for i in elig_list:
745
+ if i not in df_test_merge_small_eli_small_pivot:
746
+ df_test_merge_small_eli_small_pivot[i] = ''
747
+ df_test_merge_small_eli_small_pivot = df_test_merge_small_eli_small_pivot[['GP','C','1B','2B','3B','SS','LF','CF','RF']].sort_values(by='GP',ascending=False)
748
+
749
+ # df_test_merge_small_eli_small_pivot = df_test_merge_small_eli_small_pivot.astype({col: 'int' for col in df_test_merge_small_eli_small_pivot.columns})
750
+
751
+ # First convert your data to hierarchical columns
752
+ cols = {
753
+ ('Player Info', 'Player ID'): 'Player ID',
754
+ ('Player Info', 'Player'): 'Player',
755
+ ('Player Info', 'Team'): 'Team',
756
+ ('Player Info', 'ADP'): 'ADP',
757
+ ('Player Info', 'Yahoo Position '): 'Yahoo Position',
758
+ ('Starts at New Position', 'GP'): 'GP',
759
+ ('Starts at New Position', 'C'): 'C',
760
+ ('Starts at New Position', '1B'): '1B',
761
+ ('Starts at New Position', '2B'): '2B',
762
+ ('Starts at New Position', '3B'): '3B',
763
+ ('Starts at New Position', 'SS'): 'SS',
764
+ ('Starts at New Position', 'LF'): 'LF',
765
+ ('Starts at New Position', 'CF'): 'CF',
766
+ ('Starts at New Position', 'RF'): 'RF',
767
+
768
+ }
769
+ # Assuming your polars DataFrame is called df
770
+ # Convert to pandas
771
+ df_yahoo_pandas = df_test_merge_small_eli_small_pivot.reset_index()
772
+
773
+ df_yahoo_pandas = df_yahoo_pandas[~df_yahoo_pandas['Yahoo Position'].str.contains('P')]
774
+
775
+ norm = plt.Normalize(vmin=0, vmax=df_yahoo_pandas['GP'].max())
776
+ df_yahoo_pandas = df_yahoo_pandas.replace({0: ''})
777
+
778
+ # Rename columns with multi-index
779
+ df_yahoo_pandas.columns = pd.MultiIndex.from_tuples(
780
+ [(k[0], k[1]) for k in cols.keys()]
781
+ )
782
+
783
+ df_yahoo_style = df_yahoo_pandas.style
784
+
785
+
786
+
787
+ def apply_gradient(val):
788
+ if isinstance(val, float): # Check if the value is an integer
789
+ # Normalize the integer for the gradient
790
+ return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}'
791
+ return '' # No background for non-integer values
792
+
793
+ df_yahoo_style = (df_yahoo_style.set_precision(0)
794
+ .set_table_styles(
795
+ [
796
+
797
+ {"selector": "td:nth-child(5)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column
798
+ {"selector": "td:nth-child(6)", "props": [("border-right", "3px solid black")]},
799
+ {"selector": "td:nth-child(14)", "props": [("border-right", "3px solid black")]},
800
+
801
+ {'selector': 'thead th:nth-child(5)', 'props': [('border-right', '3px solid black')]},
802
+ {'selector': 'thead th:nth-child(6)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
803
+ {'selector': 'thead th:nth-child(14)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header
804
+
805
+ {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]},
806
+
807
+
808
+ {'selector':'th', 'props' : [('border', '1px solid black')]},
809
+
810
+ ],overwrite=False)
811
+ .set_properties(**{'border': '3 px'}, overwrite=False)
812
+ .set_table_styles([{
813
+ 'selector': 'caption',
814
+ 'props': [
815
+ ('color', ''),
816
+ ('fontname', 'Century Gothic'),
817
+ ('font-size', '16px'),
818
+ ('font-style', 'italic'),
819
+ ('font-weight', ''),
820
+ ('text-align', 'centre'),
821
+ ]
822
+ },
823
+ {
824
+ 'selector': 'th',
825
+ 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')]
826
+ },
827
+ {
828
+ 'selector': 'td',
829
+ 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')]
830
+ }], overwrite=False)
831
+
832
+ .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False)
833
+ .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False)
834
+
835
+ .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False)
836
+ .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False)
837
+ .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False)
838
+ .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False)
839
+ .hide_index()
840
+ .set_properties(**{'border': '1px black solid'})
841
+
842
+ .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '100px')]}], overwrite=False)
843
+ .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '225px')]}], overwrite=False)
844
+ .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '50px')]}], overwrite=False)
845
+ .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '50px')]}], overwrite=False)
846
+ .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '150px')]}], overwrite=False)
847
+ # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False)
848
+ .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False)
849
+ .apply(highlight_alternate_rows, axis=0, subset=df_yahoo_pandas.columns[:])
850
+ .applymap(apply_gradient)
851
+ )
852
+ return df_yahoo_style
853
+
854
+ app = App(app_ui, server)