Spaces:
Sleeping
Sleeping
import pandas as pd | |
import streamlit as st | |
import streamlit.components.v1 as components | |
from config import DEFAULT_ICON | |
from shared_page import common_page_config, get_local_style | |
from maximum_roster_strategy import data_loader | |
MINIMUM_WEEK = 6 | |
MAXIMUM_WEEK = 7 | |
MIN_TIER = 1 | |
MAX_TIER = 4 | |
POSITION_OPTIONS = ["RB", "WR", "TE", "QB"] | |
POSITION_ABBR_FULL_NAME_MAP = { | |
"RB": "Running Backs", | |
"WR": "Wide Receivers", | |
"TE": "Tight Ends", | |
"QB": "Quarterbacks (Superflex / 2QB Leagues Only)", | |
} | |
def load_data(): | |
return data_loader.get_google_sheet_data(), data_loader.get_timeslot_labels() | |
def get_player_grid_div(player_series: pd.Series) -> str: | |
player_notes = player_series["Hold Condition"] | |
if (outcome := player_series["Outcome"]) == "Drop": | |
player_class = "drop-player" | |
elif outcome == "Light Hold": | |
player_class = "light-hold-player" | |
elif outcome == "Hold": | |
player_class = "hold-player" | |
else: | |
player_class = "undetermined-player" | |
if isinstance(player_weekly_note := player_series["Article Notes"], str): | |
player_notes += "<br><br>" + player_weekly_note | |
return f""" | |
<details class="mrs-grid-player content"> | |
<summary class="{player_class}"> | |
{player_series["Formatted"]} | |
</summary> | |
<p> | |
{player_notes} | |
</p> | |
</details> | |
""" | |
def get_time_slot_div(time_slot_list: list[str]) -> str: | |
code_str = "" | |
for time_slot_idx, time_slot in enumerate(time_slot_list): | |
code_str += f"""<div class="timeslot{time_slot_idx + 1} timeslot">{time_slot}</div>\n""" | |
return code_str | |
def get_tier_div(tier_str: str | int, tier_num: str | int) -> str: | |
return f"""<div class="tier{tier_num} tier">Tier {tier_str}</div>""" | |
def get_player_container(df_players: pd.DataFrame, slot_number: int | str) -> str: | |
if len(df_players) == 0: | |
player_code_str = "<br>" | |
else: | |
player_code_str = "\n".join(df_players.apply(get_player_grid_div, axis=1).tolist()) | |
return f"""<div class="playerslot{slot_number} playerslot">{player_code_str}</div>""" | |
def get_position_breakdown(df: pd.DataFrame, position_abbr: str, position_full_str: str, time_slots: list[str]): | |
with st.container(): | |
st.header(position_full_str) | |
df_pos = df[df["Position"] == position_abbr] | |
grid_code_str = "" | |
grid_code_str += get_time_slot_div(time_slots) | |
tier_list = list(range(MIN_TIER, MAX_TIER + 1)) | |
slot_number = 0 | |
for tier_idx, tier in enumerate(tier_list): | |
grid_code_str += get_tier_div(tier, tier_idx + 1) | |
for time_slot in time_slots: | |
df_tier_slot = df_pos[(df_pos["TimeSlotName"] == time_slot) & (df_pos["Tier"] == tier)] | |
slot_number += 1 | |
grid_code_str += get_player_container(df_tier_slot, slot_number) | |
components.html( | |
f""" | |
{get_local_style()} | |
<div class="grid-container-{len(time_slots)}"> | |
{grid_code_str} | |
</div> | |
<br> | |
<div class="grid-legend">Colors Legend: | |
<div class="drop-player">Drop Player</div> | | |
<div class="light-hold-player">Light Hold Player</div> | | |
<div class="hold-player">Strong Hold Player</div> | |
</div> | |
""", | |
height=1000, | |
scrolling=True, | |
) | |
def get_page(): | |
page_title = "Maximum Roster Strategy" | |
st.set_page_config(page_title=page_title, page_icon=DEFAULT_ICON, layout="wide") | |
common_page_config() | |
st.title(page_title) | |
with st.expander(label="Instructions"): | |
st.write( | |
""" | |
To get started with MRS: https://solowfantasyfootball.wordpress.com/2023/09/07/maximum-roster-strategy-explained/ | |
Players are organized by game time slot, position, and tier. | |
Pick up a player during their game's time slot for potential upside if particular circumstances are met. | |
After the game, players will be colored by outcome: Drop (Red), Light Hold (Yellow), or Strong Hold (Green).""" | |
) | |
col_select, week_select = st.columns(2, gap="small") | |
url_params = st.experimental_get_query_params() | |
initial_position_index = 0 | |
if url_position := url_params.get("position"): | |
selected_position = url_position[0] | |
if selected_position in POSITION_OPTIONS: | |
initial_position_index = POSITION_OPTIONS.index(selected_position) | |
week_options = list(range(MAXIMUM_WEEK, MINIMUM_WEEK - 1, -1)) | |
initial_week_index = 0 | |
if url_week := url_params.get("week"): | |
try: | |
selected_week = int(url_week[0]) | |
except Exception: | |
st.warning("Week parameter must be integer value", icon="⚠️") | |
selected_week = MAXIMUM_WEEK | |
if selected_week in week_options: | |
initial_week_index = week_options.index(selected_week) | |
with col_select: | |
position = st.selectbox(label="Position", options=POSITION_OPTIONS, index=initial_position_index) | |
with week_select: | |
week = st.selectbox(label="Week", options=week_options, index=initial_week_index) | |
url_params.update({"position": position, "week": week}) | |
st.experimental_set_query_params(**url_params) | |
if st.experimental_get_query_params().get("refresh"): | |
st.cache_data.clear() | |
df_mrs, all_time_slots_df = load_data() | |
df_mrs = df_mrs[df_mrs["Week"] == week] | |
current_week_timeslots = ( | |
all_time_slots_df[all_time_slots_df["Week"] == week].sort_values("WeekTimeSlotIndex").TimeSlotName.tolist() | |
) | |
get_position_breakdown(df_mrs, position, POSITION_ABBR_FULL_NAME_MAP[position], current_week_timeslots) | |
if __name__ == "__main__": | |
get_page() | |