Spaces:
Paused
Paused
| #import packages | |
| import pandas as pd | |
| import json | |
| import numpy as np | |
| import requests | |
| pd.options.mode.chained_assignment = None | |
| from datetime import datetime | |
| import time | |
| import difflib | |
| from datetime import datetime, timedelta | |
| import api_scraper | |
| import polars as pl | |
| import matplotlib.colors | |
| import matplotlib.colors as mcolors | |
| from shiny import App, ui, render, reactive | |
| def add_empty_rows(df, n_empty, period): | |
| """ adds 'n_empty' empty rows every 'period' rows to 'df'. | |
| Returns a new DataFrame. """ | |
| # to make sure that the DataFrame index is a RangeIndex(start=0, stop=len(df)) | |
| # and that the original df object is not mutated. | |
| df = df.reset_index(drop=True) | |
| # length of the new DataFrame containing the NaN rows | |
| len_new_index = len(df) + n_empty*(len(df) // period) | |
| # index of the new DataFrame | |
| new_index = pd.RangeIndex(len_new_index) | |
| # add an offset (= number of NaN rows up to that row) | |
| # to the current df.index to align with new_index. | |
| df.index += n_empty * (df.index | |
| .to_series() | |
| .groupby(df.index // period) | |
| .ngroup()) | |
| # reindex by aligning df.index with new_index. | |
| # Values of new_index not present in df.index are filled with NaN. | |
| new_df = df.reindex(new_index) | |
| return new_df | |
| unique_team_list = [120, | |
| 141, | |
| 140, | |
| 139, | |
| 138, | |
| 137, | |
| 136, | |
| 135, | |
| 134, | |
| 143, | |
| 133, | |
| 147, | |
| 121, | |
| 142, | |
| 158, | |
| 146, | |
| 119, | |
| 108, | |
| 118, | |
| 117, | |
| 116, | |
| 145, | |
| 115, | |
| 114, | |
| 113, | |
| 112, | |
| 111, | |
| 110, | |
| 109, | |
| 144] | |
| ## Create a dataframe of teams to assist with selecting a player to search | |
| #specifically for the case where multiple players share the same name | |
| #Make an api call to get a dictionary of all teams | |
| teams = requests.get(url='https://statsapi.mlb.com/api/v1/teams/').json() | |
| #Select only teams that are at the MLB level | |
| # mlb_teams_city = [x['franchiseName'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball'] | |
| # mlb_teams_name = [x['teamName'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball'] | |
| # mlb_teams_franchise = [x['name'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball'] | |
| # mlb_teams_id = [x['id'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball'] | |
| # mlb_teams_abb = [x['abbreviation'] for x in teams['teams'] if x['sport']['name'] == 'Major League Baseball'] | |
| mlb_teams_city = [x.get('franchiseName', None) for x in teams.get('teams', [])] | |
| mlb_teams_name = [x.get('teamName', None) for x in teams.get('teams', [])] | |
| mlb_teams_franchise = [x.get('name', None) for x in teams.get('teams', [])] | |
| mlb_teams_id = [x.get('id', None) for x in teams.get('teams', [])] | |
| mlb_teams_abb = [x.get('abbreviation', None) for x in teams.get('teams', [])] | |
| #Create a dataframe of all the teams | |
| 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}) | |
| ##Create a dataframe of all players in the database | |
| #Make an api call to get a dictionary of all players | |
| player_data = requests.get(url='https://statsapi.mlb.com/api/v1/sports/11/players').json() | |
| #Select relevant data that will help distinguish players from one another | |
| fullName_list = [x['fullName'] for x in player_data['people']] | |
| id_list = [x['id'] for x in player_data['people']] | |
| position_list = [x['primaryPosition']['abbreviation'] for x in player_data['people']] | |
| team_list = [x['currentTeam']['id']for x in player_data['people']] | |
| #Create a dataframe of players and their current team ids | |
| player_df_all = pd.DataFrame(data={'id':id_list,'name':fullName_list,'position':position_list,'team_id':team_list}) | |
| #Use the teams dataframe to merge the team name to the players dataframe | |
| 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']) | |
| #drop the duplicated id column | |
| player_df_all = player_df_all.drop(columns=['team_id']) | |
| #make a column of the names all uppercase to make lookups easier | |
| player_df_all['upper_name'] = player_df_all['name'].str.upper() | |
| #rename to make the data clearer | |
| player_df_all = player_df_all.rename(columns={'franchise':'currentTeam'}) | |
| import matplotlib.pyplot as plt | |
| colour_palette = ['#FFB000','#648FFF','#785EF0', | |
| '#DC267F','#FE6100','#3D1EB2','#894D80','#16AA02','#B5592B','#A3C1ED'] | |
| cmap_up = mcolors.LinearSegmentedColormap.from_list("", ['#FFFFFF', '#FFB000']) | |
| # Function to alternate row colors | |
| def highlight_alternate_rows(x): | |
| return ['background-color: #ebebeb' if i % 2 == 0 else '' for i in range(len(x))] | |
| # Function to apply thick border to data cells | |
| # Columns after which we want a thick vertical line | |
| scraper = api_scraper.MLB_Scrape() | |
| df_teams = scraper.get_teams() | |
| teams_mlb = df_teams.filter(pl.col("league_id").is_in([103,104])).sort("abbreviation") | |
| teams_dict = dict(zip(teams_mlb['team_id'],teams_mlb['abbreviation'])) | |
| teams_name_dict = dict(zip(teams_mlb['team_id'],teams_mlb['franchise'])) | |
| {109: 'Arizona Diamondbacks', | |
| 144: 'Atlanta Braves', | |
| 110: 'Baltimore Orioles', | |
| 111: 'Boston Red Sox', | |
| 112: 'Chicago Cubs', | |
| 145: 'Chicago White Sox', | |
| 113: 'Cincinnati Reds', | |
| 114: 'Cleveland Guardians', | |
| 115: 'Colorado Rockies', | |
| 116: 'Detroit Tigers', | |
| 117: 'Houston Astros', | |
| 118: 'Kansas City Royals', | |
| 108: 'Los Angeles Angels', | |
| 119: 'Los Angeles Dodgers', | |
| 146: 'Miami Marlins', | |
| 158: 'Milwaukee Brewers', | |
| 142: 'Minnesota Twins', | |
| 121: 'New York Mets', | |
| 147: 'New York Yankees', | |
| #133: 'Athletics', | |
| 133: 'Oakland Athletics', | |
| 143: 'Philadelphia Phillies', | |
| 134: 'Pittsburgh Pirates', | |
| 135: 'San Diego Padres', | |
| 137: 'San Francisco Giants', | |
| 136: 'Seattle Mariners', | |
| 138: 'St. Louis Cardinals', | |
| 139: 'Tampa Bay Rays', | |
| 140: 'Texas Rangers', | |
| 141: 'Toronto Blue Jays', | |
| 120: 'Washington Nationals'} | |
| 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() | |
| #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() | |
| # 757 is bad | |
| #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 | |
| total_list = [] | |
| for x in data_r_1['fantasy_content']['league']['players']: | |
| single_list = [] | |
| single_list.append((x['player']['player_id'])) | |
| single_list.append(x['player']['name']['full']) | |
| single_list.append(x['player']['name']['first']) | |
| single_list.append(x['player']['name']['last']) | |
| single_list.append(x['player']['draft_analysis']['average_pick']) | |
| single_list.append(x['player']['average_auction_cost']) | |
| single_list.append(x['player']['display_position']) | |
| single_list.append(x['player']['editorial_team_abbr']) | |
| total_list.append(single_list) | |
| df_2023 = pd.DataFrame(data=total_list, columns=['player_id','full','first','last','average_pick', 'average_cost','display_position','editorial_team_abbr']) | |
| team_abb_list = ['ATL', 'AZ', 'BAL', 'BOS', 'CHC', 'CIN', 'CLE', 'COL', 'CWS', | |
| 'DET', 'HOU', 'KC', 'LAA', 'LAD', 'MIA', 'MIL', 'MIN', 'NYM', | |
| 'NYY', 'ATH', 'PHI', 'PIT', 'SD', 'SEA', 'SF', 'STL', 'TB', 'TEX', | |
| 'TOR', 'WSH'] | |
| team_abb_list_yahoo = ['ATL', 'ARI', 'BAL', 'BOS', 'CHC', 'CIN', 'CLE', 'COL', 'CWS', | |
| 'DET', 'HOU', 'KC', 'LAA', 'LAD', 'MIA', 'MIL', 'MIN', 'NYM', | |
| 'NYY', 'ATH', 'PHI', 'PIT', 'SD', 'SEA', 'SF', 'STL', 'TB', 'TEX', | |
| 'TOR', 'WSH'] | |
| team_abb_df = pd.DataFrame({'mlb_team':team_abb_list,'yahoo_team':team_abb_list_yahoo}) | |
| from shiny import App, ui, render | |
| import pandas as pd | |
| app_ui = ui.page_sidebar( | |
| ui.sidebar( | |
| ui.markdown("#### 2025 MLB Lineup Tracker"), | |
| ui.input_select( | |
| "team_id", | |
| "Select Team", | |
| choices=teams_name_dict | |
| ), | |
| ui.output_ui("player_select"), | |
| # ui.hr(), # Add a horizontal line for separation | |
| ui.div( | |
| ui.div( | |
| "By: ", # Plain text | |
| ui.tags.a( | |
| "@TJStats", # Only the handle is linked | |
| href="https://x.com/TJStats", | |
| target="_blank" | |
| ) | |
| ), | |
| ui.tags.p("Data: MLB"), | |
| ui.tags.p( | |
| ui.tags.a( | |
| "Support me on Patreon for more baseball content", | |
| href="https://www.patreon.com/TJ_Stats", | |
| target="_blank" | |
| ) | |
| ), | |
| style="color: #666; text-align: left;" | |
| ) | |
| ,width=500), | |
| ui.card( | |
| ui.output_text("selected_team_info"), | |
| ui.navset_card_tab( | |
| ui.nav_panel( | |
| "Lineups", | |
| ui.div({"style": "font-size:1.7em;"}, ui.output_text("lineup_title")), | |
| ui.output_table("table1") | |
| ), | |
| ui.nav_panel( | |
| "Summary", | |
| ui.div({"style": "font-size:1.7em;"}, ui.output_text("summary_title")), | |
| ui.output_table("table2") | |
| ), | |
| ui.nav_panel( | |
| "Fantasy Eligibility", | |
| ui.div({"style": "font-size:1.7em;"}, ui.output_text("fantasy_title")), | |
| ui.output_table("table3") | |
| ), | |
| ui.nav_panel( | |
| "Player Teammates", | |
| ui.div({"style": "font-size:1.7em;"}, ui.output_text("player_title")), | |
| ui.output_table("table4") | |
| ) | |
| ) | |
| ) | |
| ) | |
| def server(input, output, session): | |
| def player_select(): | |
| df,batting_order_full_opp,statcast_dict = cached_data() | |
| df = df.sort(['Player']) | |
| player_dict = dict(zip(df['Player ID'],df['Player'])) | |
| return ui.input_select( | |
| "player_select", | |
| f"Select Player", | |
| choices=player_dict | |
| ) | |
| def lineup_title(): | |
| return f"{teams_name_dict[int(input.team_id())]} Lineups" | |
| def summary_title(): | |
| return f"{teams_name_dict[int(input.team_id())]} Lineup Summary" | |
| def fantasy_title(): | |
| return f"{teams_name_dict[int(input.team_id())]} Position Eligibility Tracker - Yahoo" | |
| def player_title(): | |
| return f"{teams_name_dict[int(input.team_id())]} Teammate Summary" | |
| def cached_data(): | |
| team_id_select = int(input.team_id()) | |
| df_schedule = scraper.get_schedule(year_input=[2025],sport_id=[1],game_type=['R']) | |
| # df_schedule_p = scraper.get_schedule(year_input=[2024],sport_id=[21],game_type=['E']) | |
| # df_schedule_all = pl.concat([df_schedule,df_schedule_p]) | |
| df_schedule_all = pl.concat([df_schedule]) | |
| 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))) | |
| if df_schedule_team.is_empty(): | |
| return None, None, None | |
| statcast_dict = dict(zip(df_schedule_team['game_id'],df_schedule_team['gameday_type'])) | |
| game_list = df_schedule_team['game_id'][:] | |
| game_data = scraper.get_data(game_list) | |
| print('Importing New Games.') | |
| lineup_data = [] | |
| game_id = [] | |
| date = [] | |
| player_id = [] | |
| player_name = [] | |
| position = [] | |
| team_id = [] | |
| batting_order = [] | |
| handedness_batter = [] | |
| away_home = [] | |
| handedness_pitcher = [] | |
| pitcher_name = [] | |
| for y in range(0,len(game_data)): | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| team_id.append([df_schedule_team.filter(df_schedule_team['game_id']==game_data[y]['gamePk'])['away_id'][0]]*len([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']])) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| team_id.append([df_schedule_team.filter(df_schedule_team['game_id']==game_data[y]['gamePk'])['home_id'][0]]*len([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']])) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| 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']]) | |
| game_id_final = [item for sublist in game_id for item in sublist] | |
| date_final = [item for sublist in date for item in sublist] | |
| player_id_final = [item for sublist in player_id for item in sublist] | |
| player_name_final = [item for sublist in player_name for item in sublist] | |
| position_final = [item for sublist in position for item in sublist] | |
| team_id_final = [item for sublist in team_id for item in sublist] | |
| batting_order_final = [item for sublist in batting_order for item in sublist] | |
| away_home_final = [item for sublist in away_home for item in sublist] | |
| handedness_batter_final = [item for sublist in handedness_batter for item in sublist] | |
| handedness_pitcher_final = [item for sublist in handedness_pitcher for item in sublist] | |
| pitcher_name_final = [item for sublist in pitcher_name for item in sublist] | |
| 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']}) | |
| batting_order_full = pl.DataFrame(data={'game_id':game_id_final , | |
| 'date':date_final, | |
| 'player_id':player_id_final, | |
| 'player_name':player_name_final, | |
| 'position':position_final, | |
| 'team_id':team_id_final, | |
| 'batting_order':batting_order_final, | |
| 'away_home':away_home_final, | |
| 'handedness_batter':handedness_batter_final, | |
| 'handedness_pitcher':handedness_pitcher_final, | |
| 'pitcher_name':pitcher_name_final}) | |
| # batting_order_full = batting_order_full | |
| batting_order_full = batting_order_full.with_columns(pl.col('position').cast(pl.Int32)) | |
| batting_order_full = batting_order_full.join(df_teams[['team_id', 'franchise', 'abbreviation']], on='team_id', how='left') | |
| position_df = position_df.with_columns(pl.col('position').cast(pl.Int32)) | |
| batting_order_full = batting_order_full.join(position_df, on='position', how='left') | |
| batting_order_full_opp = batting_order_full.filter(pl.col('team_id') != team_id_select) | |
| batting_order_full = batting_order_full.filter(pl.col('team_id') == team_id_select) | |
| batting_order_full_filter = batting_order_full.filter(pl.col('batting_order').cast(pl.Int32) % 100 == 0) | |
| 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') | |
| batting_order_full_filter = batting_order_full_filter.unique(subset=['batting_order','game_id','away_home']) | |
| batting_order_full_filter = batting_order_full_filter.with_columns(pl.col('batting_order').cast(pl.Int32)) | |
| df_test_merge = batting_order_full_filter.clone() | |
| df_test_merge = df_test_merge.with_columns(pl.col('*').fill_null(np.nan)) | |
| df_test_merge = df_test_merge.sort(['player_id', 'date']).fill_null(strategy='forward') | |
| df_test_merge_small = df_test_merge.select([ | |
| 'game_id', 'date', 'abbreviation', 'batting_order', 'player_id', 'player_name', | |
| 'position_name', 'handedness_batter', 'handedness_pitcher','away_home', 'pitcher_name' | |
| ]).sort(['date', 'game_id', 'abbreviation', 'batting_order']) | |
| df_test_merge_small = df_test_merge_small.select(['game_id', | |
| 'date', 'abbreviation', 'batting_order', 'player_id', 'player_name', | |
| 'position_name', 'handedness_batter', 'handedness_pitcher','away_home', 'pitcher_name' | |
| ]).fill_null('') | |
| df_test_merge_small = df_test_merge_small.with_columns([ | |
| (pl.col('batting_order').cast(pl.Int32) / 100).cast(pl.Int32).alias('batting_order'), | |
| pl.lit(1).alias('count'), | |
| ]) | |
| df_test_merge_small = df_test_merge_small.rename({'game_id': 'Game ID', | |
| 'date': 'Date', 'abbreviation': 'Team', 'batting_order': 'Batting', | |
| 'player_id': 'Player ID', 'player_name': 'Player', 'position_name': 'Position', | |
| 'handedness_batter': 'Bats','away_home':'Home', | |
| 'handedness_pitcher': 'Pitcher Hand', | |
| 'pitcher_name': 'Pitcher Name' | |
| }) | |
| return df_test_merge_small,batting_order_full_opp,statcast_dict | |
| def table1(): | |
| df,batting_order_full_opp,statcast_dict = cached_data() | |
| if df is None: | |
| return pd.DataFrame({"Message": ["No Games as of this time"]}) | |
| team_opp = dict(zip(batting_order_full_opp['game_id'],batting_order_full_opp['abbreviation'])) | |
| df_test_merge_small_pd = df.to_pandas() | |
| df_test_merge_small_pd['Opponent'] = df_test_merge_small_pd['Game ID'].map(team_opp) | |
| # Create a new column with the date and opponent for the first occurrence of each game ID | |
| df_test_merge_small_pd['Game'] = np.where( | |
| ~df_test_merge_small_pd.duplicated(subset=['Game ID'], keep='first'), | |
| 0, | |
| None | |
| ) | |
| df_test_merge_small_pd['gameday_type'] = df_test_merge_small_pd['Game ID'].map(statcast_dict) | |
| df_test_merge_small_pd['Statcast'] = np.where( | |
| df_test_merge_small_pd['gameday_type'].isin(['E', 'P']), | |
| True, | |
| False | |
| ) | |
| df_test_merge_small_pd['vs_at'] = np.where( | |
| df_test_merge_small_pd['Home'].isin(['home']), | |
| ' vs ', | |
| ' @ ' | |
| ) | |
| df_test_merge_small_pd['Pitcher'] = df_test_merge_small_pd['Pitcher Name'] + ' (' + df_test_merge_small_pd['Pitcher Hand'] + ')' | |
| 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>' | |
| 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>' | |
| df_test_merge_small_pd['Savant'] = np.where( | |
| df_test_merge_small_pd['Statcast'], | |
| '<a href=https://baseballsavant.mlb.com/gamefeed?gamePk='+df_test_merge_small_pd["Game ID"].astype(int).astype(str)+' target="_blank">Statcast</a>', | |
| '(No Statcast)' | |
| ) | |
| game_index = df_test_merge_small_pd.loc[~(df_test_merge_small_pd['Game'].isnull()), 'Game'].index | |
| df_test_merge_small_pd.loc[game_index+2,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Date']) | |
| df_test_merge_small_pd.loc[game_index+3,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Team'] + df_test_merge_small_pd.loc[game_index+0,'vs_at'] + df_test_merge_small_pd.loc[game_index+0,'Opponent']) | |
| df_test_merge_small_pd.loc[game_index+4,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Pitcher']) | |
| df_test_merge_small_pd.loc[game_index+5,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Gameday']) | |
| df_test_merge_small_pd.loc[game_index+6,'Game'] = list(df_test_merge_small_pd.loc[game_index+0,'Savant']) | |
| df_test_merge_small_pd['Game'] = df_test_merge_small_pd['Game'].replace(0,None).fillna('') | |
| df_test_merge_small_output = df_test_merge_small_pd[['Game', | |
| 'Batting', | |
| 'Player', | |
| 'Position', | |
| 'Bats']] | |
| df_order_style = df_test_merge_small_output.style | |
| df_order_style = (df_order_style.set_precision(0) | |
| .set_table_styles( | |
| [ | |
| {'selector':'th', 'props' : [('border', '1px solid black')]}, | |
| ],overwrite=False) | |
| .set_properties(**{'border': '3 px'}, overwrite=False) | |
| .set_table_styles([{ | |
| 'selector': 'caption', | |
| 'props': [ | |
| ('color', ''), | |
| ('fontname', 'Century Gothic'), | |
| ('font-size', '16px'), | |
| ('font-style', 'italic'), | |
| ('font-weight', ''), | |
| ('text-align', 'centre'), | |
| ] | |
| }, | |
| { | |
| 'selector': 'th', | |
| 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')] | |
| }, | |
| { | |
| 'selector': 'td', | |
| 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')] | |
| }], overwrite=False) | |
| .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '20px'}, overwrite=False) | |
| .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#d6d6d6')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False) | |
| .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False) | |
| .hide_index() | |
| .set_properties(**{'border': '1px black solid'}) | |
| .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '225px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '100px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '225px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '100px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '100px')]}], overwrite=False) | |
| # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False) | |
| .set_properties( | |
| **{'background-color':'#d6d6d6'}, # Apply only right border | |
| subset=df_test_merge_small_output.columns[0] # Only affects column 1 | |
| ) | |
| .set_properties( | |
| **{'border-top': 'none', 'border-bottom': 'none'}, | |
| subset=df_test_merge_small_output.columns[0] # Apply only to column 1 | |
| ) | |
| .apply(highlight_alternate_rows, axis=0, subset=df_test_merge_small_output.columns[1:]) | |
| ) | |
| def add_thick_border(s): | |
| return ['border-top: 3px solid black' if s['Batting'] == 1 else '' for _ in s] | |
| df_order_style = df_order_style.apply(add_thick_border, axis=1) | |
| return df_order_style | |
| def table2(): | |
| df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data() | |
| import polars as pl | |
| df_test_merge_small = df_test_merge_small.with_columns( | |
| pl.col("Home").replace({"home": "H", "away": "A"}) | |
| ) | |
| print(df_test_merge_small) | |
| if df_test_merge_small is None: | |
| return pd.DataFrame({"Message": ["No Games as of this time"]}) | |
| df_pivot_sum = df_test_merge_small.group_by(['Player ID', 'Player','Bats']).agg([ | |
| pl.sum('count').alias('GP')]) | |
| df_pivot_order = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Batting', values='count', aggregate_function='sum') | |
| df_pivot_position = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Position', values='count', aggregate_function='sum') | |
| df_pivot_hand = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Pitcher Hand', values='count', aggregate_function='sum') | |
| df_pivot_home = df_test_merge_small.pivot(index=['Player ID', 'Player'], columns='Home', values='count', aggregate_function='sum') | |
| df_test_merge = df_pivot_sum.join(df_pivot_order, on=['Player ID', 'Player'], how='left') | |
| df_test_merge = df_test_merge.join(df_pivot_position, on=['Player ID', 'Player'], how='left') | |
| df_test_merge = df_test_merge.join(df_pivot_hand, on=['Player ID', 'Player'], how='left') | |
| df_test_merge = df_test_merge.join(df_pivot_home, on=['Player ID', 'Player'], how='left').fill_null(0) | |
| df_test_merge = df_test_merge.sort(['GP']+[str(x) for x in list(range(1,10))] | |
| ,descending=[True]+[True]*9) | |
| df_test_merge = df_test_merge.with_columns( | |
| pl.concat_str( | |
| [ | |
| pl.lit('<a href=https://baseballsavant.mlb.com/savant-player/'), | |
| pl.col('Player ID').cast(pl.Utf8).str.slice(2), | |
| pl.lit(' target="_blank">'), | |
| pl.col('Player'), | |
| pl.lit('</a>') | |
| ] | |
| ).alias('Batter') | |
| ) | |
| # List of desired columns, including RHP and LHP | |
| desired_columns = [ | |
| 'Batter', 'Bats', 'GP', '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
| 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'LHP', 'RHP','H','A' | |
| ] | |
| # Ensure all desired columns exist in the Polars DataFrame. | |
| # If a column is missing, add it with a default value (e.g., empty string '') | |
| for col in desired_columns: | |
| if col not in df_test_merge.columns: | |
| df_test_merge = df_test_merge.with_columns(pl.lit('').alias(col)) | |
| # Now select the columns in the desired order | |
| df_test_merge = df_test_merge.select(desired_columns) | |
| # Define your mapping for hierarchical columns. | |
| cols = { | |
| # ('Player Info', 'Player ID'): 'Player ID', | |
| ('Player Info', 'Batter'): 'Batter', | |
| ('Player Info', 'Bats'): 'Bats', | |
| ('Player Info', 'GP'): 'GP', | |
| ('Batting Order', '1'): '1', | |
| ('Batting Order', '2'): '2', | |
| ('Batting Order', '3'): '3', | |
| ('Batting Order', '4'): '4', | |
| ('Batting Order', '5'): '5', | |
| ('Batting Order', '6'): '6', | |
| ('Batting Order', '7'): '7', | |
| ('Batting Order', '8'): '8', | |
| ('Batting Order', '9'): '9', | |
| ('Position', 'C'): 'C', | |
| ('Position', '1B'): '1B', | |
| ('Position', '2B'): '2B', | |
| ('Position', '3B'): '3B', | |
| ('Position', 'SS'): 'SS', | |
| ('Position', 'LF'): 'LF', | |
| ('Position', 'CF'): 'CF', | |
| ('Position', 'RF'): 'RF', | |
| ('Position', 'DH'): 'DH', | |
| ('Pitcher', 'LHP'): 'LHP', | |
| ('Pitcher', 'RHP'): 'RHP', | |
| ('Home', 'H'): 'H', | |
| ('Home', 'A'): 'A' | |
| } | |
| # Convert the Polars DataFrame to a pandas DataFrame | |
| df_pandas = df_test_merge.to_pandas() | |
| # Replace any zeros with empty strings (if needed) | |
| df_pandas = df_pandas.replace({0: ''}) | |
| # Create the MultiIndex for columns. | |
| # The order of tuples should correspond exactly to the order in desired_columns. | |
| # We can build the new MultiIndex by mapping the desired_columns using the `cols` dictionary. | |
| new_columns = [] | |
| for col in desired_columns: | |
| # Find the key in cols where value matches col. | |
| # This assumes your mapping has unique values. | |
| for key, value in cols.items(): | |
| if value == col: | |
| new_columns.append(key) | |
| break | |
| # Double-check that the length of new_columns matches the DataFrame columns. | |
| if len(new_columns) != len(df_pandas.columns): | |
| raise ValueError("Mismatch in number of columns between new MultiIndex and DataFrame columns.") | |
| # Apply the new MultiIndex to the DataFrame | |
| df_pandas.columns = pd.MultiIndex.from_tuples(new_columns) | |
| # Now your DataFrame has hierarchical columns and guaranteed 'LHP' and 'RHP' columns. | |
| df_pivot_style = df_pandas.style | |
| thick_border_cols = [2, 3, 12,21,23] # 0-based index | |
| # # Create a function to apply gradient only to integers | |
| # def apply_gradient(val): | |
| # if isinstance(val, int): # Check if the value is an integer | |
| # # Normalize the integer for the gradient (optional, here it's just a simple scale) | |
| # print(val) | |
| # return f'background-color: {norm(val)}' | |
| # return '' # No background for non-integer values | |
| norm = plt.Normalize(vmin=0, vmax=df_pandas.select_dtypes(include=['int']).max().max()) | |
| def apply_gradient(val): | |
| if isinstance(val, int): # Check if the value is an integer | |
| # Normalize the integer for the gradient | |
| return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}' | |
| return '' # No background for non-integer values | |
| df_pivot_style =(df_pivot_style.set_precision(0) | |
| .set_table_styles( | |
| [ | |
| {"selector": "td:nth-child(3)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column | |
| {"selector": "td:nth-child(12)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column | |
| {"selector": "td:nth-child(21)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column | |
| {"selector": "td:nth-child(23)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd | |
| {"selector": "td:nth-child(25)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column | |
| {'selector': 'thead th:nth-child(3)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| {'selector': 'thead th:nth-child(12)', 'props': [('border-right', '3px solid black')]}, | |
| {'selector': 'thead th:nth-child(21)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| {'selector': 'thead th:nth-child(23)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| {'selector': 'thead th:nth-child(25)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]}, | |
| {'selector':'th', 'props' : [('border', '1px solid black')]}, | |
| ],overwrite=False) | |
| .set_properties(**{'border': '3 px'}, overwrite=False) | |
| .set_table_styles([{ | |
| 'selector': 'caption', | |
| 'props': [ | |
| ('color', ''), | |
| ('fontname', 'Century Gothic'), | |
| ('font-size', '16px'), | |
| ('font-style', 'italic'), | |
| ('font-weight', ''), | |
| ('text-align', 'centre'), | |
| ] | |
| }, | |
| { | |
| 'selector': 'th', | |
| 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')] | |
| }, | |
| { | |
| 'selector': 'td', | |
| 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')] | |
| }], overwrite=False) | |
| .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False) | |
| .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False) | |
| .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False) | |
| .hide_index() | |
| .set_properties(**{'border': '1px black solid'}) | |
| # .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '100px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '225px')]}], overwrite=False) | |
| # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False) | |
| .apply(highlight_alternate_rows, axis=0, subset=df_pandas.columns[:]) | |
| .applymap(apply_gradient) | |
| ) | |
| return df_pivot_style | |
| def table3(): | |
| df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data() | |
| if df_test_merge_small is None: | |
| return pd.DataFrame({"Message": ["No Games as of this time"]}) | |
| df_test_merge_small_ids = df_test_merge_small.to_pandas()[['Player ID','Player','Team']].drop_duplicates(subset='Player ID').reset_index(drop=True) | |
| 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]) | |
| df_test_merge_small_ids = df_test_merge_small_ids.merge(right=team_abb_df,left_on=['Team'],right_on=['mlb_team'],how='left') | |
| #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') | |
| 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() | |
| 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('') | |
| df_test_merge_small_eli['average_pick'] = df_test_merge_small_eli['average_pick'].replace('-','') | |
| 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)] | |
| df_test_merge_small_eli_small = df_test_merge_small_eli_small[df_test_merge_small_eli_small.Position != 'DH'].reset_index(drop=True) | |
| 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) | |
| df_test_merge_small_eli_small_pivot['GP'] = df_test_merge_small_eli_small_pivot.sum(axis=1) | |
| df_test_merge_small_eli_small_pivot.index.names = ['Player ID','Player','Team','ADP','Yahoo Position'] | |
| elig_list = ['GP','C','1B','2B','3B','SS','LF','CF','RF'] | |
| for i in elig_list: | |
| if i not in df_test_merge_small_eli_small_pivot: | |
| df_test_merge_small_eli_small_pivot[i] = '' | |
| 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) | |
| # 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}) | |
| # First convert your data to hierarchical columns | |
| cols = { | |
| ('Player Info', 'Player ID'): 'Player ID', | |
| ('Player Info', 'Player'): 'Player', | |
| ('Player Info', 'Team'): 'Team', | |
| ('Player Info', 'ADP'): 'ADP', | |
| ('Player Info', 'Yahoo Position '): 'Yahoo Position', | |
| ('Starts at New Position', 'GP'): 'GP', | |
| ('Starts at New Position', 'C'): 'C', | |
| ('Starts at New Position', '1B'): '1B', | |
| ('Starts at New Position', '2B'): '2B', | |
| ('Starts at New Position', '3B'): '3B', | |
| ('Starts at New Position', 'SS'): 'SS', | |
| ('Starts at New Position', 'LF'): 'LF', | |
| ('Starts at New Position', 'CF'): 'CF', | |
| ('Starts at New Position', 'RF'): 'RF', | |
| } | |
| # Assuming your polars DataFrame is called df | |
| # Convert to pandas | |
| df_yahoo_pandas = df_test_merge_small_eli_small_pivot.reset_index() | |
| df_yahoo_pandas = df_yahoo_pandas[~df_yahoo_pandas['Yahoo Position'].str.contains('P')] | |
| norm = plt.Normalize(vmin=0, vmax=df_yahoo_pandas['GP'].max()) | |
| df_yahoo_pandas = df_yahoo_pandas.replace({0: ''}) | |
| # Rename columns with multi-index | |
| df_yahoo_pandas.columns = pd.MultiIndex.from_tuples( | |
| [(k[0], k[1]) for k in cols.keys()] | |
| ) | |
| df_yahoo_style = df_yahoo_pandas.style | |
| def apply_gradient(val): | |
| if isinstance(val, float): # Check if the value is an integer | |
| # Normalize the integer for the gradient | |
| return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}' | |
| return '' # No background for non-integer values | |
| df_yahoo_style = (df_yahoo_style.set_precision(0) | |
| .set_table_styles( | |
| [ | |
| {"selector": "td:nth-child(5)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column | |
| {"selector": "td:nth-child(6)", "props": [("border-right", "3px solid black")]}, | |
| {"selector": "td:nth-child(14)", "props": [("border-right", "3px solid black")]}, | |
| {'selector': 'thead th:nth-child(5)', 'props': [('border-right', '3px solid black')]}, | |
| {'selector': 'thead th:nth-child(6)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| {'selector': 'thead th:nth-child(14)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]}, | |
| {'selector':'th', 'props' : [('border', '1px solid black')]}, | |
| ],overwrite=False) | |
| .set_properties(**{'border': '3 px'}, overwrite=False) | |
| .set_table_styles([{ | |
| 'selector': 'caption', | |
| 'props': [ | |
| ('color', ''), | |
| ('fontname', 'Century Gothic'), | |
| ('font-size', '16px'), | |
| ('font-style', 'italic'), | |
| ('font-weight', ''), | |
| ('text-align', 'centre'), | |
| ] | |
| }, | |
| { | |
| 'selector': 'th', | |
| 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')] | |
| }, | |
| { | |
| 'selector': 'td', | |
| 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')] | |
| }], overwrite=False) | |
| .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False) | |
| .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False) | |
| .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False) | |
| .hide_index() | |
| .set_properties(**{'border': '1px black solid'}) | |
| .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '100px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '225px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '50px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '50px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '150px')]}], overwrite=False) | |
| # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False) | |
| .apply(highlight_alternate_rows, axis=0, subset=df_yahoo_pandas.columns[:]) | |
| .applymap(apply_gradient) | |
| ) | |
| return df_yahoo_style | |
| def table4(): | |
| df_test_merge_small,batting_order_full_opp,statcast_dict = cached_data() | |
| player_dict = dict(zip(df_test_merge_small['Player ID'],df_test_merge_small['Player'])) | |
| import polars as pl | |
| df_test_merge_small = df_test_merge_small.with_columns( | |
| pl.col("Home").replace({"home": "H", "away": "A"}) | |
| ) | |
| print(df_test_merge_small) | |
| if df_test_merge_small is None: | |
| return pd.DataFrame({"Message": ["No Games as of this time"]}) | |
| df_selected_player_games = df_test_merge_small.filter(pl.col('Player ID') == input.player_select())['Game ID'].unique() | |
| df_test_merge_small = df_test_merge_small.filter(pl.col('Game ID').is_in(df_selected_player_games)) | |
| df_test_merge_small = df_test_merge_small.with_columns( | |
| pl.lit(input.player_select()).alias('Selected Player ID'), | |
| pl.lit(player_dict[input.player_select()]).alias('Selected Player') | |
| ) | |
| df_pivot_sum = df_test_merge_small.group_by(['Selected Player ID','Selected Player', 'Player']).agg([ | |
| pl.sum('count').alias('GP')]).sort('GP',descending=True) | |
| # df_pivot_sum = df_pivot_sum.filter(pl.col('Player') != pl.col('Selected Player')) | |
| df_pivot_sum = df_pivot_sum.with_columns( | |
| pl.when(pl.col('Player') == pl.col('Selected Player')) | |
| .then(pl.lit(1)) | |
| .otherwise(pl.lit(0)) | |
| .alias('is_selected') | |
| ).sort(['is_selected', 'GP'], descending=[True, True]).drop('is_selected') | |
| df_pivot_sum = df_pivot_sum.with_columns(pl.col('GP').cast(pl.Float64)) | |
| df_pivot_sum_pd = df_pivot_sum.to_pandas() | |
| df_pivot_sum_pd.iloc[1:, 0] = '' | |
| df_pivot_sum_pd.iloc[1:, 1] = '' | |
| norm = plt.Normalize(vmin=0, vmax=df_pivot_sum_pd['GP'].max()) | |
| def apply_gradient(val): | |
| if isinstance(val, float): # Check if the value is an integer | |
| # Normalize the integer for the gradient | |
| return f'background-color: {mcolors.to_hex(cmap_up(norm(val)))}' | |
| return '' # No background for non-integer values | |
| def add_bottom_border(s): | |
| return ['border-bottom: 1px solid black' if i == len(s) - 1 else '' for i in range(len(s))] | |
| df_yahoo_style = (df_pivot_sum_pd.style.set_precision(0) | |
| .set_table_styles( | |
| [ | |
| # {"selector": "td:nth-child(2)", "props": [("border-right", "3px solid black")]}, # Thick right border for the 3rd column | |
| # {"selector": "td:nth-child(4)", "props": [("border-right", "3px solid black")]}, | |
| # {"selector": "td:nth-child(14)", "props": [("border-right", "3px solid black")]}, | |
| # {'selector': 'thead th:nth-child(5)', 'props': [('border-right', '3px solid black')]}, | |
| # {'selector': 'thead th:nth-child(6)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| # {'selector': 'thead th:nth-child(14)', 'props': [('border-right', '3px solid black')]}, # Thick right border for the 3rd header | |
| # {'selector': 'th.col_heading.level0', 'props': [('border-right', '3px solid black')]}, | |
| {'selector':'th', 'props' : [('border', '1px solid black')]}, | |
| ],overwrite=False) | |
| .set_properties(**{'border': '3 px'}, overwrite=False) | |
| .set_table_styles([{ | |
| 'selector': 'caption', | |
| 'props': [ | |
| ('color', ''), | |
| ('fontname', 'Century Gothic'), | |
| ('font-size', '16px'), | |
| ('font-style', 'italic'), | |
| ('font-weight', ''), | |
| ('text-align', 'centre'), | |
| ] | |
| }, | |
| { | |
| 'selector': 'th', | |
| 'props': [('font-size', '16px'), ('text-align', 'center'), ('Height', 'px'), ('color', 'black')] | |
| }, | |
| { | |
| 'selector': 'td', | |
| 'props': [('text-align', 'center'), ('font-size', '16px'), ('color', 'black')] | |
| }], overwrite=False) | |
| .set_properties(**{'background-color': 'White', 'index': 'White', 'min-width': '35px'}, overwrite=False) | |
| .set_table_styles([{'selector': 'th:first-child', 'props': [('background-color', 'white')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level0', 'props': [('background-color', '#b6b6b6')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'th.col_heading.level1', 'props': [('background-color', '#a3a3a3')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'tr', 'props': [('line-height', '20px')]}], overwrite=False) | |
| .set_properties(**{'Height': '8px'}, **{'text-align': 'center'}, overwrite=False) | |
| .hide_index() | |
| .set_properties(**{'border': '1px black solid'}) | |
| .set_table_styles([{'selector': 'thead th:nth-child(1)', 'props': [('min-width', '150px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '225px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(3)', 'props': [('min-width', '225px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th:nth-child(4)', 'props': [('min-width', '50px')]}], overwrite=False) | |
| # .set_table_styles([{'selector': 'thead th:nth-child(5)', 'props': [('min-width', '150px')]}], overwrite=False) | |
| # .set_table_styles([{'selector': 'thead th:nth-child(2)', 'props': [('min-width', '250px')]}], overwrite=False) | |
| .set_table_styles([{'selector': 'thead th', 'props': [('height', '30px')]}], overwrite=False) | |
| .apply(highlight_alternate_rows, axis=0, subset=df_pivot_sum_pd.columns[2:]) | |
| .applymap(apply_gradient) | |
| .set_properties( | |
| **{'border-top': 'none', 'border-bottom': 'none'}, | |
| subset=df_pivot_sum_pd.columns[0:2] # Apply only to column 1 | |
| ).apply(add_bottom_border, axis=0) | |
| ) | |
| return df_yahoo_style | |
| return df_pivot_sum_pd | |
| app = App(app_ui, server) | |