from dataclasses import dataclass import pandas as pd import streamlit as st from domain.constants import SEASON from domain.playoffs import ( PLAYOFF_WEEK_TO_NAME, ROSTER_WEEK_TO_PLAYOFF_WEEK, PLAYOFFS_TEAMS, PLAYOFF_TEAM_DEF_PLAYER, ) from queries.nflverse.github_data import get_weekly_rosters from queries.pfr.league_schedule import get_season_game_map @dataclass class PlayerOption: full_name: str gsis_id: str headshot_url: str position: str team: str gametime: pd.Timestamp | None week: int | None @classmethod def from_series(cls, input_series): return cls( full_name=input_series.full_name, gsis_id=input_series.gsis_id, headshot_url=input_series.headshot_url, position=input_series.position, team=input_series.team, gametime=input_series.gametime, week=int(input_series.week), ) @classmethod def empty_player(cls, week: int | None = None, position: str = ""): return cls(full_name="", gsis_id="", headshot_url="", position=position, team="", gametime=None, week=week) @classmethod def hidden_player(cls, week: int | None = None, position: str = ""): return cls( full_name="Hidden", gsis_id="", headshot_url="", position=position, team="", gametime=None, week=week ) def is_locked(self) -> bool: if not self.gametime: return False else: date_compare = (pd.Timestamp.now(tz="America/New_York")) + pd.Timedelta(days=0, hours=0) return self.gametime < date_compare def initialize_empty_options_map() -> dict[str, dict[int, list[PlayerOption]]]: options_map: dict[str, dict[int, list[PlayerOption]]] = {} for pos in ["QB", "RB", "WR", "TE", "K", "DEF"]: options_map[pos] = {} for week in PLAYOFF_WEEK_TO_NAME.keys(): options_map[pos][int(week)] = [PlayerOption.empty_player(week=week)] return options_map def player_options_from_df(df_options) -> dict[str, dict[int, list[PlayerOption]]]: options_map = initialize_empty_options_map() for pos, pos_week_map in options_map.items(): for week in pos_week_map.keys(): df_pos_week = df_options[((df_options.week == week) & (df_options.position == pos))] if len(df_pos_week) > 0: player_options_list = df_pos_week.apply(PlayerOption.from_series, axis=1).tolist() options_map[pos][int(week)].extend(player_options_list) return options_map def modify_defensive_players_to_be_team_defense(df_options): for team, player_id in PLAYOFF_TEAM_DEF_PLAYER: if player_id in df_options.gsis_id.values: df_options.loc[df_options.gsis_id == player_id, "position"] = "DEF" df_options.loc[df_options.gsis_id == player_id, "full_name"] = team.team_name def display_player(player_opt: PlayerOption | None): if player_opt: if player_opt.headshot_url: st.image(player_opt.headshot_url) if player_opt.full_name: st.write(player_opt.full_name) if player_opt.gametime: gametime_str = player_opt.gametime.strftime("%-m/%-d %-I:%M %p") else: gametime_str = "" st.write(f"{player_opt.team} - {gametime_str}") @st.cache_data(ttl=60 * 60 * 24) def load_options(): df_rosters = get_weekly_rosters() # get game schedules week_game_times, latest_game_time_defaults = get_season_game_map(SEASON) # sort sort_by_cols = ["position", "fantasy_points", "week"] df_rosters.sort_values(sort_by_cols, ascending=False, inplace=True) # filter data from non-playoffs df_rosters = df_rosters[df_rosters.week.isin(ROSTER_WEEK_TO_PLAYOFF_WEEK.keys())] df_rosters["week"] = df_rosters["week"].map(ROSTER_WEEK_TO_PLAYOFF_WEEK) # Filter out duplicates which occur for week 1 (bye players come from week 18) df_rosters = df_rosters.drop_duplicates(subset=["gsis_id", "week"]) # set gametime if len(df_rosters) == 0: return initialize_empty_options_map() df_rosters["gametime"] = df_rosters.apply( lambda x: week_game_times.get(x.week, {}) .get(x.team, {}) .get("gametime", latest_game_time_defaults.get(x.week, None)), axis=1, ) df_rosters["in_playoffs"] = df_rosters.apply(lambda x: x.team in PLAYOFFS_TEAMS[x.week], axis=1) df_rosters = df_rosters[df_rosters.in_playoffs] modify_defensive_players_to_be_team_defense(df_rosters) player_options = player_options_from_df(df_rosters) return player_options @st.cache_data(ttl=60 * 60 * 24) def get_map_week_player_id_option() -> dict[int, dict[str, PlayerOption]]: options_pos_week_map = load_options() options_week_id_map: dict[int, dict[str, PlayerOption]] = {k: {} for k in PLAYOFF_WEEK_TO_NAME.keys()} for _, pos_map in options_pos_week_map.items(): for week, pos_week_opt_list in pos_map.items(): for player_opt in pos_week_opt_list: options_week_id_map[week][player_opt.gsis_id] = player_opt return options_week_id_map