James McCool
Refactor optimal lineup export logic to apply salary and team count filters before converting player names to IDs, ensuring accurate data processing for DraftKings and FanDuel. Update column mappings for NBA and WNBA to reflect new player positions.
c34709f
| import streamlit as st | |
| import numpy as np | |
| import pandas as pd | |
| import streamlit as st | |
| import unicodedata | |
| import math | |
| import re | |
| from database import db, wnba_db | |
| st.set_page_config(layout="wide") | |
| dk_nba_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| dk_nba_sd_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| fd_nba_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| fd_nba_sd_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| dk_wnba_columns = ['G1', 'G2', 'F1', 'F2', 'F3', 'UTIL', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| dk_wnba_sd_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| fd_wnba_columns = ['G1', 'G2', 'G3', 'F1', 'F2', 'F3', 'F4', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| fd_wnba_sd_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'] | |
| dk_hb_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| fd_hb_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| showdown_selections = ['Showdown #1', 'Showdown #2', 'Showdown #3', 'Showdown #4', 'Showdown #5', 'Showdown #6', 'Showdown #7', 'Showdown #8', 'Showdown #9', 'Showdown #10', 'Showdown #11', 'Showdown #12', 'Showdown #13', 'Showdown #14', 'Showdown #15'] | |
| dk_db_showdown_selections = ['DK_NBA_SD_seed_frame_Showdown #1', 'DK_NBA_SD_seed_frame_Showdown #2', 'DK_NBA_SD_seed_frame_Showdown #3', 'DK_NBA_SD_seed_frame_Showdown #4', 'DK_NBA_SD_seed_frame_Showdown #5', 'DK_NBA_SD_seed_frame_Showdown #6', | |
| 'DK_NBA_SD_seed_frame_Showdown #7', 'DK_NBA_SD_seed_frame_Showdown #8', 'DK_NBA_SD_seed_frame_Showdown #9', 'DK_NBA_SD_seed_frame_Showdown #10', 'DK_NBA_SD_seed_frame_Showdown #11', 'DK_NBA_SD_seed_frame_Showdown #12', 'DK_NBA_SD_seed_frame_Showdown #13', | |
| 'DK_NBA_SD_seed_frame_Showdown #14', 'DK_NBA_SD_seed_frame_Showdown #15'] | |
| fd_db_showdown_selections = ['FD_NBA_SD_seed_frame_Showdown #1', 'FD_NBA_SD_seed_frame_Showdown #2', 'FD_NBA_SD_seed_frame_Showdown #3', 'FD_NBA_SD_seed_frame_Showdown #4', 'FD_NBA_SD_seed_frame_Showdown #5', 'FD_NBA_SD_seed_frame_Showdown #6', | |
| 'FD_NBA_SD_seed_frame_Showdown #7', 'FD_NBA_SD_seed_frame_Showdown #8', 'FD_NBA_SD_seed_frame_Showdown #9', 'FD_NBA_SD_seed_frame_Showdown #10', 'FD_NBA_SD_seed_frame_Showdown #11', 'FD_NBA_SD_seed_frame_Showdown #12', 'FD_NBA_SD_seed_frame_Showdown #13', | |
| 'FD_NBA_SD_seed_frame_Showdown #14', 'FD_NBA_SD_seed_frame_Showdown #15'] | |
| dk_showdown_db_translation = dict(zip(showdown_selections, dk_db_showdown_selections)) | |
| fd_showdown_db_translation = dict(zip(showdown_selections, fd_db_showdown_selections)) | |
| roo_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'} | |
| st.markdown(""" | |
| <style> | |
| /* Tab styling */ | |
| .stElementContainer [data-baseweb="button-group"] { | |
| gap: 2.000rem; | |
| padding: 4px; | |
| } | |
| .stElementContainer [kind="segmented_control"] { | |
| height: 2.000rem; | |
| white-space: pre-wrap; | |
| background-color: #DAA520; | |
| color: white; | |
| border-radius: 20px; | |
| gap: 1px; | |
| padding: 10px 20px; | |
| font-weight: bold; | |
| transition: all 0.3s ease; | |
| } | |
| .stElementContainer [kind="segmented_controlActive"] { | |
| height: 3.000rem; | |
| background-color: #DAA520; | |
| border: 3px solid #FFD700; | |
| border-radius: 10px; | |
| color: black; | |
| } | |
| .stElementContainer [kind="segmented_control"]:hover { | |
| background-color: #FFD700; | |
| cursor: pointer; | |
| } | |
| div[data-baseweb="select"] > div { | |
| background-color: #DAA520; | |
| color: white; | |
| } | |
| </style>""", unsafe_allow_html=True) | |
| def define_dk_showdown_slates(): | |
| collection = db["Player_SD_Range_Of_Outcomes"] | |
| cursor = collection.find() | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display[raw_display['site'] == 'Draftkings'] | |
| unique_slates = raw_display['slate'].unique() | |
| slate_names = [] | |
| for slate in unique_slates: | |
| slate_data = raw_display[raw_display['slate'] == slate] | |
| slate_name = slate_data.iloc[0]['Team'] + ' vs. ' + slate_data.iloc[0]['Opp'] | |
| slate_names.append(slate_name) | |
| slate_name_lookup = dict(zip(slate_names, unique_slates)) | |
| return slate_names, slate_name_lookup | |
| def define_fd_showdown_slates(): | |
| collection = db["Player_SD_Range_Of_Outcomes"] | |
| cursor = collection.find() | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display[raw_display['site'] == 'Fanduel'] | |
| unique_slates = raw_display['slate'].unique() | |
| slate_names = [] | |
| for slate in unique_slates: | |
| slate_data = raw_display[raw_display['slate'] == slate] | |
| slate_name = slate_data.iloc[0]['Team'] + ' vs. ' + slate_data.iloc[0]['Opp'] | |
| slate_names.append(slate_name) | |
| slate_name_lookup = dict(zip(slate_names, unique_slates)) | |
| return slate_names, slate_name_lookup | |
| def init_baselines(type_var: str, league: str): | |
| if type_var == 'Showdown': | |
| if league == 'NBA': | |
| collection = db["Player_SD_Range_Of_Outcomes"] | |
| elif league == 'WNBA': | |
| collection = wnba_db["Player_SD_Range_Of_Outcomes"] | |
| cursor = collection.find() | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display[['Player', 'Minutes Proj', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '4x%', '5x%', '6x%', 'GPP%', | |
| 'Own', 'Small_Own', 'Large_Own', 'Cash_Own', 'CPT_Own', 'LevX', 'ValX', 'site', 'version', 'slate', 'timestamp', 'player_id']] | |
| raw_display['Median'] = raw_display['Median'].replace('', 0).astype(float) | |
| raw_display = raw_display.rename(columns={"player_id": "player_ID"}) | |
| raw_display = raw_display.loc[raw_display['Median'] > 0] | |
| raw_display = raw_display.apply(pd.to_numeric, errors='ignore') | |
| sd_raw = raw_display.sort_values(by='Median', ascending=False) | |
| dk_sd_roo_raw = sd_raw[sd_raw['site'] == 'Draftkings'] | |
| dk_sd_id_map = dict(zip(dk_sd_roo_raw['Player'], dk_sd_roo_raw['player_ID'])) | |
| fd_sd_roo_raw = sd_raw[sd_raw['site'] == 'Fanduel'] | |
| fd_sd_id_map = dict(zip(fd_sd_roo_raw['Player'], fd_sd_roo_raw['player_ID'])) | |
| fd_sd_roo_raw['player_ID'] = fd_sd_roo_raw['player_ID'].astype(str) | |
| fd_sd_roo_raw['player_ID'] = fd_sd_roo_raw['player_ID'].str.rsplit('-', n=1).str[0].astype(str) | |
| timestamp = sd_raw['timestamp'].values[0] | |
| roo_raw = None | |
| dk_roo_raw = None | |
| fd_roo_raw = None | |
| dk_id_map = None | |
| fd_id_map = None | |
| else: | |
| if league == 'NBA': | |
| collection = db["Player_Range_Of_Outcomes"] | |
| elif league == 'WNBA': | |
| collection = wnba_db["Player_Range_Of_Outcomes"] | |
| cursor = collection.find() | |
| raw_display = pd.DataFrame(list(cursor)) | |
| try: | |
| raw_display = raw_display[['Player', 'Minutes Proj', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '4x%', '5x%', '6x%', 'GPP%', | |
| 'Own', 'Small_Own', 'Large_Own', 'Cash_Own', 'CPT_Own', 'LevX', 'ValX', 'site', 'version', 'slate', 'timestamp', 'player_ID']] | |
| except: | |
| raw_display = raw_display[['Player', 'Minutes Proj', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '4x%', '5x%', '6x%', 'GPP%', | |
| 'Own', 'Small_Own', 'Large_Own', 'Cash_Own', 'CPT_Own', 'LevX', 'ValX', 'site', 'version', 'slate', 'timestamp', 'player_id']] | |
| raw_display = raw_display.rename(columns={"player_id": "player_ID"}) | |
| raw_display['Median'] = raw_display['Median'].replace('', 0).astype(float) | |
| raw_display = raw_display.loc[raw_display['Median'] > 0] | |
| dk_roo_raw = raw_display[raw_display['site'] == 'Draftkings'] | |
| fd_roo_raw = raw_display[raw_display['site'] == 'Fanduel'] | |
| dk_id_map = dict(zip(dk_roo_raw['Player'], dk_roo_raw['player_ID'])) | |
| fd_id_map = dict(zip(fd_roo_raw['Player'], fd_roo_raw['player_ID'])) | |
| raw_display = raw_display.apply(pd.to_numeric, errors='ignore') | |
| roo_raw = raw_display.sort_values(by='Median', ascending=False) | |
| timestamp = roo_raw['timestamp'].values[0] | |
| sd_raw = None | |
| dk_sd_roo_raw = None | |
| fd_sd_roo_raw = None | |
| dk_sd_id_map = None | |
| fd_sd_id_map = None | |
| return roo_raw, dk_roo_raw, fd_roo_raw, sd_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map, timestamp | |
| def init_DK_lineups(type_var, slate_var, prio_var, prio_mix, db_translation, lineup_num, player_var2): | |
| if prio_var == 'Mix': | |
| prio_var = None | |
| if type_var == 'Regular': | |
| if slate_var == 'Main': | |
| collection = db['DK_NBA_name_map'] | |
| cursor = collection.find() | |
| raw_data = pd.DataFrame(list(cursor)) | |
| names_dict = dict(zip(raw_data['key'], raw_data['value'])) | |
| collection = db['DK_NBA_seed_frame_Main Slate'] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX']) | |
| raw_display = raw_display[['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| dict_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| # Map names | |
| raw_display[dict_columns] = raw_display[dict_columns].apply(lambda x: x.map(names_dict)) | |
| elif slate_var == 'Secondary': | |
| collection = db['DK_NBA_Secondary_name_map'] | |
| cursor = collection.find() | |
| raw_data = pd.DataFrame(list(cursor)) | |
| names_dict = dict(zip(raw_data['key'], raw_data['value'])) | |
| collection = db['DK_NBA_seed_frame_Secondary Slate'] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX']) | |
| raw_display = raw_display[['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| dict_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| # Map names | |
| raw_display[dict_columns] = raw_display[dict_columns].apply(lambda x: x.map(names_dict)) | |
| elif slate_var == 'Auxiliary': | |
| collection = db['DK_NBA_Late_name_map'] | |
| cursor = collection.find() | |
| raw_data = pd.DataFrame(list(cursor)) | |
| names_dict = dict(zip(raw_data['key'], raw_data['value'])) | |
| collection = db['DK_NBA_seed_frame_Late Slate'] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX']) | |
| raw_display = raw_display[['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| dict_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| # Map names | |
| raw_display[dict_columns] = raw_display[dict_columns].apply(lambda x: x.map(names_dict)) | |
| elif type_var == 'Showdown': | |
| collection = db[db_translation[slate_var]] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5']) | |
| raw_display = raw_display[['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| DK_seed = raw_display.to_numpy() | |
| return DK_seed | |
| def init_FD_lineups(type_var, slate_var, prio_var, prio_mix, db_translation, lineup_num, player_var2): | |
| if prio_var == 'Mix': | |
| prio_var = None | |
| if type_var == 'Regular': | |
| if slate_var == 'Main': | |
| collection = db['FD_NBA_name_map'] | |
| cursor = collection.find() | |
| raw_data = pd.DataFrame(list(cursor)) | |
| names_dict = dict(zip(raw_data['key'], raw_data['value'])) | |
| collection = db['FD_NBA_seed_frame_Main Slate'] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C']) | |
| raw_display = raw_display[['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| dict_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| # Map names | |
| raw_display[dict_columns] = raw_display[dict_columns].apply(lambda x: x.map(names_dict)) | |
| elif slate_var == 'Secondary': | |
| collection = db['FD_NBA_Secondary_name_map'] | |
| cursor = collection.find() | |
| raw_data = pd.DataFrame(list(cursor)) | |
| names_dict = dict(zip(raw_data['key'], raw_data['value'])) | |
| collection = db['FD_NBA_Secondary_seed_frame_Secondary Slate'] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C']) | |
| raw_display = raw_display[['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| dict_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| # Map names | |
| raw_display[dict_columns] = raw_display[dict_columns].apply(lambda x: x.map(names_dict)) | |
| elif slate_var == 'Auxiliary': | |
| collection = db['FD_NBA_Late_name_map'] | |
| cursor = collection.find() | |
| raw_data = pd.DataFrame(list(cursor)) | |
| names_dict = dict(zip(raw_data['key'], raw_data['value'])) | |
| collection = db['FD_NBA_Late_seed_frame_Late Slate'] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num = ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C']) | |
| raw_display = raw_display[['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| dict_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| # Map names | |
| raw_display[dict_columns] = raw_display[dict_columns].apply(lambda x: x.map(names_dict)) | |
| elif type_var == 'Showdown': | |
| collection = db[db_translation[slate_var]] | |
| if prio_var == None: | |
| if player_var2 != []: | |
| player_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| query_conditions = [] | |
| for player in player_var2: | |
| # Create a condition for each player to check if they appear in any column | |
| player_condition = {'$or': [{col: player} for col in player_columns]} | |
| query_conditions.append(player_condition) | |
| # Combine all player conditions with $or | |
| if query_conditions: | |
| filter_query = {'$or': query_conditions} | |
| cursor1 = collection.find(filter_query).limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find(filter_query).sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor1 = collection.find().limit(math.ceil(lineup_num * (prio_mix / 100))) | |
| cursor2 = collection.find().sort('Own', -1).limit(math.ceil(lineup_num * ((100 - prio_mix) / 100))) | |
| raw_display = pd.concat([pd.DataFrame(list(cursor1)), pd.DataFrame(list(cursor2))]) | |
| else: | |
| cursor = collection.find().sort(prio_var, -1).limit(lineup_num) | |
| raw_display = pd.DataFrame(list(cursor)) | |
| raw_display = raw_display.drop_duplicates(subset=['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5']) | |
| raw_display = raw_display[['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own']] | |
| FD_seed = raw_display.to_numpy() | |
| return FD_seed | |
| def normalize_special_characters(text): | |
| """Convert accented characters to their ASCII equivalents""" | |
| if pd.isna(text): | |
| return text | |
| # Normalize unicode characters to their closest ASCII equivalents | |
| normalized = unicodedata.normalize('NFKD', str(text)) | |
| # Remove diacritics (accents, umlauts, etc.) | |
| ascii_text = ''.join(c for c in normalized if not unicodedata.combining(c)) | |
| return ascii_text | |
| def map_mask_parse(df: pd.DataFrame, map: dict, threshold: float, site_var: str): | |
| print(df.iloc[:, :-7].head(10)) | |
| if site_var == 'Draftkings': | |
| proj_df = df.iloc[:, :-7].replace(map).astype(float) | |
| elif site_var == 'Fanduel': | |
| proj_df = df.iloc[:, :-7].replace(map).astype(float) | |
| print(proj_df.head(10)) | |
| mask = (proj_df >= threshold).all(axis=1) | |
| df = df[mask] | |
| return df | |
| def convert_df_to_csv(df): | |
| return df.to_csv().encode('utf-8') | |
| def convert_df(array): | |
| array = pd.DataFrame(array, columns=column_names) | |
| return array.to_csv().encode('utf-8') | |
| def convert_pm_df(array): | |
| array = pd.DataFrame(array) | |
| return array.to_csv().encode('utf-8') | |
| def convert_hb_df(array, column_names): | |
| array = pd.DataFrame(array, columns=column_names) | |
| return array.to_csv().encode('utf-8') | |
| try: | |
| slate_names_dk, slate_name_lookup_dk = define_dk_showdown_slates() | |
| except: | |
| slate_names_dk = [] | |
| slate_name_lookup_dk = {} | |
| try: | |
| slate_names_fd, slate_name_lookup_fd = define_fd_showdown_slates() | |
| except: | |
| slate_names_fd = [] | |
| slate_name_lookup_fd = {} | |
| app_load_reset_column, app_view_site_column, = st.columns([1, 9]) | |
| with app_load_reset_column: | |
| if st.button("Load/Reset Data", key='reset_data_button'): | |
| st.cache_data.clear() | |
| roo_raw, dk_roo_raw, fd_roo_raw, sd_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map, timestamp = init_baselines('Regular', 'NBA') | |
| try: | |
| slate_names_dk, slate_name_lookup_dk = define_dk_showdown_slates() | |
| except: | |
| slate_names_dk = [] | |
| slate_name_lookup_dk = {} | |
| try: | |
| slate_names_fd, slate_name_lookup_fd = define_fd_showdown_slates() | |
| except: | |
| slate_names_fd = [] | |
| slate_name_lookup_fd = {} | |
| dk_lineups = init_DK_lineups('Regular', 'Main', 'proj', 50, dk_showdown_db_translation, 25000, []) | |
| fd_lineups = init_FD_lineups('Regular', 'Main', 'proj', 50, fd_showdown_db_translation, 25000, []) | |
| for key in st.session_state.keys(): | |
| del st.session_state[key] | |
| with app_view_site_column: | |
| with st.container(): | |
| app_view_column, sport_select_column, app_site_column, app_type_column = st.columns([2, 2, 2, 2]) | |
| with app_view_column: | |
| view_var = st.selectbox("Select view", ["Simple", "Advanced"], key='view_selectbox') | |
| with sport_select_column: | |
| sport_var = st.selectbox("What league do you want to view?", ('NBA', 'WNBA'), key='sport_selectbox') | |
| with app_site_column: | |
| site_var = st.selectbox("What site do you want to view?", ('Draftkings', 'Fanduel'), key='site_selectbox') | |
| with app_type_column: | |
| type_var = st.selectbox("What type of data do you want to view?", ('Regular', 'Showdown'), key='type_selectbox') | |
| selected_tab = st.segmented_control( | |
| "Select Tab", | |
| options=["Player ROO", "Handbuilder", "Optimals"], | |
| selection_mode='single', | |
| default='Player ROO', | |
| width='stretch', | |
| label_visibility='collapsed', | |
| key='tab_selector' | |
| ) | |
| if selected_tab == 'Handbuilder': | |
| if 'handbuilder_data' not in st.session_state: | |
| roo_raw, dk_roo_raw, fd_roo_raw, sd_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map, timestamp = init_baselines('Regular', 'NBA') | |
| st.session_state['handbuilder_data'] = roo_raw | |
| t_stamp = f"Last Update: " + str(timestamp) + f" CST" | |
| else: | |
| pass | |
| # Use the lightweight handbuilder data | |
| if site_var == 'Draftkings': | |
| handbuild_roo = st.session_state['handbuilder_data'][st.session_state['handbuilder_data']['site'] == 'Draftkings'] | |
| else: | |
| handbuild_roo = st.session_state['handbuilder_data'][st.session_state['handbuilder_data']['site'] == 'Fanduel'] | |
| handbuilder_header_column, handbuilder_slate_column = st.columns(2) | |
| with handbuilder_header_column: | |
| st.header("Handbuilder") | |
| with handbuilder_slate_column: | |
| slate_var3 = st.selectbox("Slate Selection", options=['Main', 'Secondary', 'Auxiliary'], key='handbuilder_slate_selectbox') | |
| if site_var == 'Draftkings': | |
| if slate_var3 == 'Main': | |
| handbuild_roo = handbuild_roo[handbuild_roo['slate'] == 'Main Slate'] | |
| elif slate_var3 == 'Secondary': | |
| handbuild_roo = handbuild_roo[handbuild_roo['slate'] == 'Secondary Slate'] | |
| elif slate_var3 == 'Auxiliary': | |
| handbuild_roo = handbuild_roo[handbuild_roo['slate'] == 'Late Slate'] | |
| elif site_var == 'Fanduel': | |
| if slate_var3 == 'Main': | |
| handbuild_roo = handbuild_roo[handbuild_roo['slate'] == 'Main Slate'] | |
| elif slate_var3 == 'Secondary': | |
| handbuild_roo = handbuild_roo[handbuild_roo['slate'] == 'Secondary Slate'] | |
| elif slate_var3 == 'Auxiliary': | |
| handbuild_roo = handbuild_roo[handbuild_roo['slate'] == 'Late Slate'] | |
| # --- POSITION LIMITS --- | |
| if site_var == 'Draftkings': | |
| position_limits = { | |
| 'PG': 1, | |
| 'SG': 1, | |
| 'SF': 1, | |
| 'PF': 1, | |
| 'C': 1, | |
| 'G': 1, | |
| 'F': 1, | |
| 'FLEX': 1, | |
| } | |
| max_salary = 50000 | |
| max_players = 8 | |
| else: | |
| position_limits = { | |
| 'PG': 2, | |
| 'SG': 2, | |
| 'SF': 2, | |
| 'PF': 2, | |
| 'C': 1, | |
| } | |
| max_salary = 60000 | |
| max_players = 9 | |
| # --- LINEUP STATE --- | |
| if 'handbuilder_lineup' not in st.session_state: | |
| st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own']) | |
| # Count positions in the current lineup | |
| lineup = st.session_state['handbuilder_lineup'] | |
| slot_counts = lineup['Slot'].value_counts() if not lineup.empty else {} | |
| # --- PLAYER FILTERS --- | |
| with st.expander("Player Filters"): | |
| handbuilder_player_filters_column, handbuilder_player_filters_salary_column = st.columns(2) | |
| with handbuilder_player_filters_column: | |
| pos_select3 = st.multiselect("Select your position(s)", options=['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] if site_var == 'Draftkings' else ['PG', 'SG', 'SF', 'PF', 'C'], key='pos_select3_multiselect') | |
| with handbuilder_player_filters_salary_column: | |
| salary_var = st.number_input("Salary Max", min_value = 0, max_value = 15000, value = 15000, step = 100, key='handbuilder_salary_max_input') | |
| # --- TEAM FILTER UI --- | |
| with st.expander("Team Filters"): | |
| all_teams = sorted(handbuild_roo['Team'].unique()) | |
| st.markdown("**Toggle teams to include:**") | |
| team_cols = st.columns(len(all_teams) // 2 + 1) | |
| selected_teams = [] | |
| for idx, team in enumerate(all_teams): | |
| col = team_cols[idx % len(team_cols)] | |
| if f"handbuilder_team_{team}" not in st.session_state: | |
| st.session_state[f"handbuilder_team_{team}"] = False | |
| checked = col.toggle(team, value=st.session_state[f"handbuilder_team_{team}"], key=f"handbuilder_team_{team}_toggle") | |
| if checked: | |
| selected_teams.append(team) | |
| # If no teams selected, show all teams | |
| if selected_teams: | |
| st.session_state['player_select_df'] = handbuild_roo[ | |
| handbuild_roo['Team'].isin(selected_teams) | |
| ][['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own']].drop_duplicates(subset=['Player', 'Team']).copy() | |
| else: | |
| st.session_state['player_select_df'] = handbuild_roo[['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own']].drop_duplicates(subset=['Player', 'Team']).copy() | |
| # If no teams selected, show all teams | |
| if pos_select3: | |
| position_mask_2 = handbuild_roo['Position'].apply(lambda x: any(pos in x for pos in pos_select3)) | |
| st.session_state['player_select_df'] = st.session_state['player_select_df'][position_mask_2][['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own']].drop_duplicates(subset=['Player', 'Team']).copy() | |
| else: | |
| st.session_state['player_select_df'] = st.session_state['player_select_df'][['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own']].drop_duplicates(subset=['Player', 'Team']).copy() | |
| st.session_state['player_select_df'] = st.session_state['player_select_df'][st.session_state['player_select_df']['Salary'] <= salary_var] | |
| # --- FILTER OUT PLAYERS WHOSE ALL ELIGIBLE POSITIONS ARE FILLED --- | |
| def is_player_eligible(row): | |
| eligible_positions = re.split(r'[/, ]+', row['Position']) | |
| # Player is eligible if at least one of their positions is not at max | |
| for pos in eligible_positions: | |
| if slot_counts.get(pos, 0) < position_limits.get(pos, 0): | |
| return True | |
| return False | |
| # st.session_state['player_select_df'] = st.session_state['player_select_df'][st.session_state['player_select_df'].apply(is_player_eligible, axis=1)] | |
| print(st.session_state['player_select_df'].head(10)) | |
| handbuilder_lineup_build_column, handbuilder_player_select_column = st.columns([1, 2]) | |
| with handbuilder_player_select_column: | |
| st.subheader("Player Select") | |
| # Display player selection dataframe with single row selection | |
| event = st.dataframe( | |
| st.session_state['player_select_df'].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').background_gradient(cmap='RdYlGn_r', subset=['Salary', 'Own']).format(precision=2), | |
| on_select="rerun", | |
| selection_mode="single-row", | |
| key="player_select_dataframe", | |
| height=500, | |
| hide_index=True | |
| ) | |
| # Add Player button | |
| if st.button("Add Selected Player to Lineup", key="add_player_button"): | |
| if event and "rows" in event.selection and len(event.selection["rows"]) > 0: | |
| idx = event.selection["rows"][0] | |
| player_row = st.session_state['player_select_df'].iloc[[idx]] | |
| eligible_positions = re.split(r'[/, ]+', player_row['Position'].iloc[0]) | |
| # Find the first eligible slot that is not full | |
| slot_to_fill = None | |
| player_position_string = player_row['Position'].iloc[0] | |
| if site_var == 'Draftkings': | |
| # DraftKings NBA slots | |
| for slot in ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX']: | |
| if slot_counts.get(slot, 0) < position_limits.get(slot, 0): | |
| if slot == 'FLEX': | |
| # FLEX can be any position | |
| slot_to_fill = slot | |
| break | |
| elif slot == 'G': | |
| # G can be PG or SG | |
| if 'PG' in player_position_string or 'SG' in player_position_string: | |
| slot_to_fill = slot | |
| break | |
| elif slot == 'F': | |
| # F can be SF or PF | |
| if 'SF' in player_position_string or 'PF' in player_position_string: | |
| slot_to_fill = slot | |
| break | |
| elif slot in player_position_string: | |
| # Explicit positions (PG, SG, SF, PF, C) - check if slot appears in position string | |
| slot_to_fill = slot | |
| break | |
| else: | |
| # FanDuel NBA slots | |
| for slot in ['PG', 'SG', 'SF', 'PF', 'C']: | |
| if slot_counts.get(slot, 0) < position_limits.get(slot, 0): | |
| if slot in player_position_string: | |
| slot_to_fill = slot | |
| break | |
| if slot_to_fill is not None: | |
| # Avoid duplicates | |
| if not player_row['Player'].iloc[0] in st.session_state['handbuilder_lineup']['Player'].values: | |
| # Add the slot info | |
| player_row = player_row.assign(Slot=slot_to_fill) | |
| st.session_state['handbuilder_lineup'] = pd.concat( | |
| [st.session_state['handbuilder_lineup'], player_row[['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own', 'Slot']]], | |
| ignore_index=True | |
| ) | |
| st.success(f"Added {player_row['Player'].iloc[0]} to {slot_to_fill} slot") | |
| else: | |
| st.warning(f"{player_row['Player'].iloc[0]} is already in the lineup") | |
| else: | |
| st.error("No available slots for this player") | |
| else: | |
| st.warning("Please select a player first") | |
| with handbuilder_lineup_build_column: | |
| st.subheader("Lineup Build") | |
| # --- EXPLICIT LINEUP ORDER --- | |
| if site_var == 'Draftkings': | |
| lineup_slots = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| else: | |
| lineup_slots = ['PG', 'PG', 'SG', 'SG', 'SF', 'SF', 'PF', 'PF', 'C'] | |
| display_columns = ['Slot', 'Player', 'Position', 'Team', 'Salary', 'Median', 'Own'] | |
| filled_lineup = st.session_state['handbuilder_lineup'] | |
| display_rows = [] | |
| used_indices = set() | |
| if not filled_lineup.empty: | |
| for slot in lineup_slots: | |
| match = filled_lineup[(filled_lineup['Slot'] == slot) & (~filled_lineup.index.isin(used_indices))] | |
| if not match.empty: | |
| row = match.iloc[0] | |
| used_indices.add(match.index[0]) | |
| display_rows.append({ | |
| 'Slot': slot, | |
| 'Player': row['Player'], | |
| 'Position': row['Position'], | |
| 'Team': row['Team'], | |
| 'Salary': row['Salary'], | |
| 'Median': row['Median'], | |
| '4x%': row['4x%'], | |
| 'Own': row['Own'] | |
| }) | |
| else: | |
| display_rows.append({ | |
| 'Slot': slot, | |
| 'Player': '', | |
| 'Position': '', | |
| 'Team': '', | |
| 'Salary': np.nan, | |
| 'Median': np.nan, | |
| '4x%': np.nan, | |
| 'Own': np.nan | |
| }) | |
| st.session_state['lineup_display_df'] = pd.DataFrame(display_rows, columns=display_columns) | |
| # Show the lineup table as a static display | |
| st.dataframe( | |
| st.session_state['lineup_display_df'].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn', subset=['Median']).background_gradient(cmap='RdYlGn_r', subset=['Salary', 'Own']).format(precision=2), | |
| height=445, | |
| hide_index=True | |
| ) | |
| # --- SUMMARY ROW --- | |
| if not filled_lineup.empty: | |
| total_salary = filled_lineup['Salary'].sum() | |
| total_median = filled_lineup['Median'].sum() | |
| avg_4x = filled_lineup['4x%'].mean() | |
| total_own = filled_lineup['Own'].sum() | |
| most_common_team = filled_lineup['Team'].mode()[0] if not filled_lineup['Team'].mode().empty else "" | |
| summary_row = pd.DataFrame({ | |
| 'Slot': [''], | |
| 'Player': ['TOTAL'], | |
| 'Position': [''], | |
| 'Team': [most_common_team], | |
| 'Salary': [total_salary], | |
| 'Median': [total_median], | |
| '4x%': [avg_4x], | |
| 'Own': [total_own] | |
| }) | |
| summary_row = summary_row[['Salary', 'Median', 'Own']].head(max_players) | |
| handbuilder_lineup_build_salary_column, handbuilder_lineup_build_median_column = st.columns([2, 3]) | |
| with handbuilder_lineup_build_salary_column: | |
| if (max_players - len(filled_lineup)) > 0: | |
| st.markdown(f""" | |
| <div style='text-align: left; vertical-align: top; margin-top: 0; padding-top: 0;''> | |
| <b>💰 Per Player:</b> ${round((max_salary - total_salary) / (max_players - len(filled_lineup)), 0)} | |
| </div> | |
| """, | |
| unsafe_allow_html=True) | |
| else: | |
| st.markdown(f""" | |
| <div style='text-align: left; vertical-align: top; margin-top: 0; padding-top: 0;''> | |
| <b>💰 Leftover:</b> ${round(max_salary - total_salary, 0)} | |
| </div> | |
| """, | |
| unsafe_allow_html=True) | |
| with handbuilder_lineup_build_median_column: | |
| if total_salary <= max_salary: | |
| st.markdown( | |
| f""" | |
| <div style='text-align: right; vertical-align: top; margin-top: 0; padding-top: 0;''> | |
| <b>💰 Salary:</b> ${round(total_salary, 0)} | |
| <b>🔥 Median:</b> {round(total_median, 2)} | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| else: | |
| st.markdown( | |
| f""" | |
| <div style='text-align: right; vertical-align: top; margin-top: 0; padding-top: 0;''> | |
| <b>❌ Salary:</b> ${round(total_salary, 0)} | |
| <b>🔥 Median:</b> {round(total_median, 2)} | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Remove Player button | |
| if not filled_lineup.empty: | |
| players_to_remove = st.multiselect( | |
| "Select players to remove:", | |
| options=filled_lineup['Player'].tolist(), | |
| key="remove_player_multiselect" | |
| ) | |
| if st.button("Confirm Remove", key="confirm_remove_button"): | |
| st.session_state['handbuilder_lineup'] = st.session_state['handbuilder_lineup'][ | |
| ~st.session_state['handbuilder_lineup']['Player'].isin(players_to_remove) | |
| ] | |
| if players_to_remove: | |
| st.success(f"Removed {', '.join(players_to_remove)} from lineup") | |
| else: | |
| st.warning("No players selected for removal") | |
| st.rerun() | |
| # Optionally, add a button to clear the lineup | |
| clear_col, save_col, export_col, clear_saved_col, blank_col = st.columns([2, 2, 2, 2, 12]) | |
| with clear_col: | |
| if st.button("Clear Lineup", key='clear_lineup_button'): | |
| st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', '4x%', 'Own', 'Slot']) | |
| # Clear the dataframe selections by resetting the previous selection state | |
| st.session_state['previous_player_selection'] = [] | |
| # Force dataframe to re-render with new key to clear selections | |
| st.session_state['dataframe_key_counter'] = st.session_state.get('dataframe_key_counter', 0) + 1 | |
| st.rerun() | |
| with save_col: | |
| if st.button("Save Lineup", key='save_lineup_button'): | |
| if 'saved_lineups' in st.session_state: | |
| st.session_state['saved_lineups'].append(st.session_state['lineup_display_df']['Player'].tolist()) | |
| print(st.session_state['saved_lineups']) | |
| else: | |
| st.session_state['saved_lineups'] = [st.session_state['lineup_display_df']['Player'].tolist()] | |
| print(st.session_state['saved_lineups']) | |
| with export_col: | |
| if 'saved_lineups' in st.session_state and st.session_state['saved_lineups']: | |
| # Convert list of lists to numpy array | |
| saved_lineups_array = np.array(st.session_state['saved_lineups']) | |
| st.download_button( | |
| label="Export Handbuilds", | |
| data=convert_hb_df(saved_lineups_array, dk_hb_columns if site_var == 'Draftkings' else fd_hb_columns), | |
| file_name='handbuilds_export.csv', | |
| mime='text/csv', | |
| key='export_handbuilds_button' | |
| ) | |
| else: | |
| st.write("No saved lineups to export") | |
| if 'saved_lineups' in st.session_state: | |
| st.table(pd.DataFrame(st.session_state['saved_lineups'], columns=dk_hb_columns if site_var == 'Draftkings' else fd_hb_columns)) | |
| else: | |
| st.write("No saved lineups") | |
| with clear_saved_col: | |
| if st.button("Clear Saved", key='clear_saved_button'): | |
| if 'saved_lineups' in st.session_state: | |
| del st.session_state['saved_lineups'] | |
| if selected_tab == 'Player ROO': | |
| roo_raw, dk_roo_raw, fd_roo_raw, sd_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map, timestamp = init_baselines(type_var, sport_var) | |
| t_stamp = f"Last Update: " + str(timestamp) + f" CST" | |
| with st.expander("Info and Filters"): | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| if site_var == 'Draftkings': | |
| slate_var2 = st.radio("Which slate data are you loading?", (slate_names_dk if type_var == 'Showdown' else ['Main Slate', 'Secondary Slate', 'Late Slate']), key='slate_var3_radio') | |
| elif site_var == 'Fanduel': | |
| slate_var2 = st.radio("Which slate data are you loading?", (slate_names_fd if type_var == 'Showdown' else ['Main Slate', 'Secondary Slate', 'Late Slate']), key='slate_var3_radio') | |
| if type_var == 'Regular': | |
| if slate_var2 == 'Main Slate': | |
| if site_var == 'Draftkings': | |
| site_baselines = dk_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == 'Main Slate'] | |
| elif site_var == 'Fanduel': | |
| site_baselines = fd_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == 'Main Slate'] | |
| elif slate_var2 == 'Secondary Slate': | |
| if site_var == 'Draftkings': | |
| site_baselines = dk_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == 'Secondary Slate'] | |
| elif site_var == 'Fanduel': | |
| site_baselines = fd_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == 'Secondary Slate'] | |
| elif slate_var2 == 'Late Slate': | |
| if site_var == 'Draftkings': | |
| site_baselines = dk_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == 'Late Slate'] | |
| elif site_var == 'Fanduel': | |
| site_baselines = fd_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == 'Late Slate'] | |
| elif type_var == 'Showdown': | |
| if site_var == 'Draftkings': | |
| site_baselines = dk_sd_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == slate_name_lookup_dk[slate_var2]] | |
| elif site_var == 'Fanduel': | |
| site_baselines = fd_sd_roo_raw | |
| raw_baselines = site_baselines[site_baselines['slate'] == slate_name_lookup_fd[slate_var2]] | |
| with col3: | |
| split_var2 = st.radio("Slate Range", ('Full Slate Run', 'Specific Games'), key='split_var2') | |
| if split_var2 == 'Specific Games': | |
| team_var2 = st.multiselect('Select teams for ROO', options=raw_baselines['Team'].unique(), key='team_var2') | |
| else: | |
| team_var2 = raw_baselines.Team.values.tolist() | |
| pos_var2 = st.selectbox('Position Filter', options=['All', 'PG', 'SG', 'SF', 'PF', 'C'], key='pos_var2') | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| low_salary = st.number_input('Enter Lowest Salary', min_value=300, max_value=15000, value=300, step=100, key='low_salary') | |
| with col2: | |
| high_salary = st.number_input('Enter Highest Salary', min_value=300, max_value=25000, value=25000, step=100, key='high_salary') | |
| display_container_1 = st.empty() | |
| display_dl_container_1 = st.empty() | |
| display_proj = raw_baselines[raw_baselines['Team'].isin(team_var2)] | |
| display_proj = display_proj[display_proj['Salary'].between(low_salary, high_salary)] | |
| if view_var == 'Advanced': | |
| display_proj = display_proj[['Player', 'Minutes Proj', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '4x%', '5x%', '6x%', 'GPP%', | |
| 'Own', 'Small_Own', 'Large_Own', 'Cash_Own', 'CPT_Own', 'LevX', 'ValX']] | |
| elif view_var == 'Simple': | |
| display_proj = display_proj[['Player', 'Position', 'Salary', 'Median', 'GPP%', 'Own']] | |
| export_data = raw_baselines.copy() | |
| export_data_pm = raw_baselines[['Player', 'Position', 'Team', 'Salary', 'Median', 'Own', 'CPT_Own']] | |
| export_data_pm = export_data_pm.rename(columns={'Own': 'ownership', 'Median': 'median', 'Player': 'player_names', 'Position': 'position', 'Team': 'team', 'Salary': 'salary', 'CPT_Own': 'captain ownership'}) | |
| # display_proj = display_proj.set_index('Player') | |
| st.session_state.display_proj = display_proj.set_index('Player', drop=True) | |
| reg_dl_col, pm_dl_col, blank_col = st.columns([2, 2, 6]) | |
| with reg_dl_col: | |
| st.download_button( | |
| label="Export ROO (Regular)", | |
| data=convert_df_to_csv(export_data), | |
| file_name='NBA_ROO_export.csv', | |
| mime='text/csv', | |
| ) | |
| with pm_dl_col: | |
| st.download_button( | |
| label="Export ROO (Portfolio Manager)", | |
| data=convert_df_to_csv(export_data_pm), | |
| file_name='NBA_ROO_export.csv', | |
| mime='text/csv', | |
| ) | |
| if 'display_proj' in st.session_state: | |
| if pos_var2 == 'All': | |
| st.session_state.display_proj = st.session_state.display_proj | |
| elif pos_var2 != 'All': | |
| st.session_state.display_proj = st.session_state.display_proj[st.session_state.display_proj['Position'].str.contains(pos_var2)] | |
| st.dataframe(st.session_state.display_proj.style.set_properties(**{'font-size': '6pt'}).background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(roo_format, precision=2), | |
| height=1000, use_container_width = True) | |
| if selected_tab == 'Optimals': | |
| roo_raw, dk_roo_raw, fd_roo_raw, sd_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map, timestamp = init_baselines(type_var, sport_var) | |
| t_stamp = f"Last Update: " + str(timestamp) + f" CST" | |
| st.header("Optimals") | |
| with st.expander("Info and Filters"): | |
| st.info("These filters will display various optimals in the table below. If you want to export the entire set of 10,000 optimals, hit the 'Prepare full data export' button. If you would like to apply the filters here to the 10,000 optimals before you export, use the 'Prepare full data export (Filter)' button.") | |
| prio_col, optimals_site_col, optimals_macro_col, optimals_salary_col, optimals_stacks_col = st.columns(5) | |
| with prio_col: | |
| prio_var = st.radio("Which priority variable do you want to use?", ('proj', 'Own', 'Mix'), key='prio_var_radio') | |
| prio_mix = st.number_input("If Mix, what split of Projection/Ownership to dedicate to Projection?", min_value=0, max_value=100, value=50, step=1) | |
| lineup_num = st.number_input("How many lineups do you want to work with?", min_value=1000, max_value=50000, value=25000, step=100, key='lineup_download_var_input') | |
| with optimals_site_col: | |
| if type_var == 'Regular': | |
| if site_var == 'Draftkings': | |
| raw_baselines = dk_roo_raw | |
| elif site_var == 'Fanduel': | |
| raw_baselines = fd_roo_raw | |
| elif type_var == 'Showdown': | |
| if site_var == 'Draftkings': | |
| raw_baselines = dk_sd_roo_raw | |
| elif site_var == 'Fanduel': | |
| raw_baselines = fd_sd_roo_raw | |
| if site_var == 'Draftkings': | |
| slate_var3 = st.radio("Which slate data are you loading?", (slate_names_dk if type_var == 'Showdown' else ['Main', 'Secondary', 'Auxiliary']), key='slate_var3_radio') | |
| elif site_var == 'Fanduel': | |
| slate_var3 = st.radio("Which slate data are you loading?", (slate_names_fd if type_var == 'Showdown' else ['Main', 'Secondary', 'Auxiliary']), key='slate_var3_radio') | |
| with optimals_macro_col: | |
| lineup_num_var = st.number_input("How many lineups do you want to display?", min_value=1, max_value=1000, value=150, step=1, key='lineup_num_var_input') | |
| player_var2 = st.multiselect('Query for lineups including:', options = raw_baselines['Player'].unique(), key='player_var2_multiselect', default=[]) | |
| if type_var == 'Regular': | |
| if site_var == 'Draftkings': | |
| dk_lineups = init_DK_lineups(type_var, slate_var3, prio_var, prio_mix, dk_showdown_db_translation, lineup_num, player_var2) | |
| elif site_var == 'Fanduel': | |
| fd_lineups = init_FD_lineups(type_var, slate_var3, prio_var, prio_mix, fd_showdown_db_translation, lineup_num, player_var2) | |
| elif type_var == 'Showdown': | |
| if site_var == 'Draftkings': | |
| dk_lineups = init_DK_lineups(type_var, slate_name_lookup_dk[slate_var3], prio_var, prio_mix, dk_showdown_db_translation, lineup_num, player_var2) | |
| elif site_var == 'Fanduel': | |
| fd_lineups = init_FD_lineups(type_var, slate_name_lookup_fd[slate_var3], prio_var, prio_mix, fd_showdown_db_translation, lineup_num, player_var2) | |
| with optimals_salary_col: | |
| if site_var == 'Draftkings': | |
| salary_min_var = st.number_input("Minimum salary used", min_value = 0, max_value = 50000, value = 49000, step = 100, key = 'salary_min_var_dk') | |
| salary_max_var = st.number_input("Maximum salary used", min_value = 0, max_value = 50000, value = 50000, step = 100, key = 'salary_max_var_dk') | |
| elif site_var == 'Fanduel': | |
| salary_min_var = st.number_input("Minimum salary used", min_value = 0, max_value = 60000, value = 59000, step = 100, key = 'salary_min_var_fd') | |
| salary_max_var = st.number_input("Maximum salary used", min_value = 0, max_value = 60000, value = 60000, step = 100, key = 'salary_max_var_fd') | |
| projection_var = st.number_input("Minimum projection used", min_value=0.0, max_value=100.0, value=0.0, step=1.0, key='projection_var_input') | |
| with optimals_stacks_col: | |
| if site_var == 'Draftkings': | |
| min_stacks_var = st.number_input("Minimum stacks used", min_value = 0, max_value = 5, value = 1, step = 1, key = 'min_stacks_var_dk') | |
| max_stacks_var = st.number_input("Maximum stacks used", min_value = 0, max_value = 5, value = 5, step = 1, key = 'max_stacks_var_dk') | |
| elif site_var == 'Fanduel': | |
| min_stacks_var = st.number_input("Minimum stacks used", min_value = 0, max_value = 4, value = 1, step = 1, key = 'min_stacks_var_fd') | |
| max_stacks_var = st.number_input("Maximum stacks used", min_value = 0, max_value = 4, value = 4, step = 1, key = 'max_stacks_var_fd') | |
| ownership_var = st.number_input("Minimum ownership used", min_value=0.0, max_value=100.0, value=0.0, step=1.0, key='ownership_var_input') | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| ROO_slice = raw_baselines | |
| player_salaries = dict(zip(ROO_slice['Player'], ROO_slice['Salary'])) | |
| if sport_var == 'NBA': | |
| column_names = dk_nba_columns | |
| elif sport_var == 'WNBA': | |
| column_names = dk_wnba_columns | |
| elif type_var == 'Showdown': | |
| player_salaries = dict(zip(raw_baselines['Player'], raw_baselines['Salary'])) | |
| if sport_var == 'NBA': | |
| column_names = dk_nba_sd_columns | |
| elif sport_var == 'WNBA': | |
| column_names = dk_wnba_sd_columns | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| ROO_slice = raw_baselines | |
| player_salaries = dict(zip(ROO_slice['Player'], ROO_slice['Salary'])) | |
| if sport_var == 'NBA': | |
| column_names = fd_nba_columns | |
| elif sport_var == 'WNBA': | |
| column_names = fd_wnba_columns | |
| elif type_var == 'Showdown': | |
| player_salaries = dict(zip(raw_baselines['Player'], raw_baselines['Salary'])) | |
| if sport_var == 'NBA': | |
| column_names = fd_nba_sd_columns | |
| elif sport_var == 'WNBA': | |
| column_names = fd_wnba_sd_columns | |
| reg_dl_col, filtered_dl_col, blank_dl_col = st.columns([2, 2, 6]) | |
| with reg_dl_col: | |
| if st.button("Prepare full data export", key='data_export_button'): | |
| name_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names) | |
| data_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names) | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| if sport_var == 'NBA': | |
| map_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| elif sport_var == 'WNBA': | |
| map_columns = ['G1', 'G2', 'F1', 'F2', 'F3', 'UTIL'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(dk_id_map) | |
| elif type_var == 'Showdown': | |
| map_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(dk_sd_id_map) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| if sport_var == 'NBA': | |
| map_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| elif sport_var == 'WNBA': | |
| map_columns = ['G1', 'G2', 'G3', 'F1', 'F2', 'F3', 'F4'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(fd_id_map) | |
| elif type_var == 'Showdown': | |
| map_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(fd_sd_id_map) | |
| reg_opt_col, pm_opt_col = st.columns(2) | |
| with reg_opt_col: | |
| st.download_button( | |
| label="Export optimals set (IDs)", | |
| data=convert_df(data_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_optimals_ids_button' | |
| ) | |
| st.download_button( | |
| label="Export optimals set (Names)", | |
| data=convert_df(name_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_optimals_names_button' | |
| ) | |
| with pm_opt_col: | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| data_export = data_export.set_index('PG').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| data_export = data_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| data_export = data_export.set_index('PG1').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| data_export = data_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| st.download_button( | |
| label="Portfolio Manager Export (IDs)", | |
| data=convert_pm_df(data_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_pm_ids_button' | |
| ) | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| name_export = name_export.set_index('PG').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| name_export = name_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| name_export = name_export.set_index('PG1').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| name_export = name_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| st.download_button( | |
| label="Portfolio Manager Export (Names)", | |
| data=convert_pm_df(name_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_pm_names_button' | |
| ) | |
| with filtered_dl_col: | |
| if st.button("Prepare full data export (Filtered)", key='data_export_filtered_button'): | |
| name_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names) | |
| data_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names) | |
| # Apply filters BEFORE converting to IDs | |
| data_export = data_export[data_export['salary'] >= salary_min_var] | |
| data_export = data_export[data_export['salary'] <= salary_max_var] | |
| data_export = data_export[data_export['Team_count'] >= min_stacks_var] | |
| data_export = data_export[data_export['Team_count'] <= max_stacks_var] | |
| if site_var == 'Draftkings': | |
| data_export = map_mask_parse(data_export, dict(zip(raw_baselines['Player'], raw_baselines['Median'])), projection_var, site_var) | |
| data_export = map_mask_parse(data_export, dict(zip(raw_baselines['Player'], raw_baselines['Own'])), ownership_var, site_var) | |
| elif site_var == 'Fanduel': | |
| data_export = map_mask_parse(data_export, dict(zip(raw_baselines['Player'], raw_baselines['Median'])), projection_var, site_var) | |
| data_export = map_mask_parse(data_export, dict(zip(raw_baselines['Player'], raw_baselines['Own'])), ownership_var, site_var) | |
| name_export = name_export[name_export['salary'] >= salary_min_var] | |
| name_export = name_export[name_export['salary'] <= salary_max_var] | |
| name_export = name_export[name_export['Team_count'] >= min_stacks_var] | |
| name_export = name_export[name_export['Team_count'] <= max_stacks_var] | |
| if site_var == 'Draftkings': | |
| name_export = map_mask_parse(name_export, dict(zip(raw_baselines['Player'], raw_baselines['Median'])), projection_var, site_var) | |
| name_export = map_mask_parse(name_export, dict(zip(raw_baselines['Player'], raw_baselines['Own'])), ownership_var, site_var) | |
| elif site_var == 'Fanduel': | |
| name_export = map_mask_parse(name_export, dict(zip(raw_baselines['Player'], raw_baselines['Median'])), projection_var, site_var) | |
| name_export = map_mask_parse(name_export, dict(zip(raw_baselines['Player'], raw_baselines['Own'])), ownership_var, site_var) | |
| # NOW convert player names to IDs after filtering | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| if sport_var == 'NBA': | |
| map_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| elif sport_var == 'WNBA': | |
| map_columns = ['G1', 'G2', 'F1', 'F2', 'F3', 'UTIL'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(dk_id_map) | |
| elif type_var == 'Showdown': | |
| map_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(dk_sd_id_map) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| if sport_var == 'NBA': | |
| map_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| elif sport_var == 'WNBA': | |
| map_columns = ['G1', 'G2', 'G3', 'F1', 'F2', 'F3', 'F4'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(fd_id_map) | |
| elif type_var == 'Showdown': | |
| map_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| for col_idx in map_columns: | |
| data_export[col_idx] = data_export[col_idx].map(fd_sd_id_map) | |
| reg_opt_col, pm_opt_col = st.columns(2) | |
| with reg_opt_col: | |
| st.download_button( | |
| label="Export optimals set (IDs)", | |
| data=convert_df(data_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_filtered_optimals_ids_button' | |
| ) | |
| st.download_button( | |
| label="Export optimals set (Names)", | |
| data=convert_df(name_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_filtered_optimals_names_button' | |
| ) | |
| with pm_opt_col: | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| data_export = data_export.set_index('PG').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| data_export = data_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| data_export = data_export.set_index('PG1').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| data_export = data_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| st.download_button( | |
| label="Portfolio Manager Export (IDs)", | |
| data=convert_pm_df(data_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_filtered_pm_ids_button' | |
| ) | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| name_export = name_export.set_index('PG').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| name_export = name_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| name_export = name_export.set_index('PG1').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| elif type_var == 'Showdown': | |
| name_export = name_export.set_index('CPT').drop(columns=['salary', 'proj', 'Team', 'Team_count', 'Secondary', 'Secondary_count', 'Own'], axis=1) | |
| st.download_button( | |
| label="Portfolio Manager Export (Names)", | |
| data=convert_pm_df(name_export), | |
| file_name='NBA_optimals_export.csv', | |
| mime='text/csv', | |
| key='export_filtered_pm_names_button' | |
| ) | |
| if site_var == 'Draftkings': | |
| st.session_state.working_seed = dk_lineups.copy() | |
| st.session_state.working_seed = st.session_state.working_seed | |
| if player_var2 != []: | |
| st.session_state.working_seed = st.session_state.working_seed[np.equal.outer(st.session_state.working_seed, player_var2).any(axis=1).all(axis=1)] | |
| elif player_var2 == []: | |
| st.session_state.working_seed = dk_lineups.copy() | |
| st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:lineup_num_var], columns=column_names) | |
| elif site_var == 'Fanduel': | |
| st.session_state.working_seed = fd_lineups.copy() | |
| st.session_state.working_seed = st.session_state.working_seed | |
| if player_var2 != []: | |
| st.session_state.working_seed = st.session_state.working_seed[np.equal.outer(st.session_state.working_seed, player_var2).any(axis=1).all(axis=1)] | |
| elif player_var2 == []: | |
| st.session_state.working_seed = fd_lineups.copy() | |
| st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:lineup_num_var], columns=column_names) | |
| st.session_state.data_export_display = st.session_state.data_export_display[st.session_state.data_export_display['salary'] >= salary_min_var] | |
| st.session_state.data_export_display = st.session_state.data_export_display[st.session_state.data_export_display['salary'] <= salary_max_var] | |
| if site_var == 'Draftkings': | |
| st.session_state.data_export_display = map_mask_parse(st.session_state.data_export_display, dict(zip(raw_baselines['Player'], raw_baselines['Median'])), projection_var, site_var) | |
| st.session_state.data_export_display = map_mask_parse(st.session_state.data_export_display, dict(zip(raw_baselines['Player'], raw_baselines['Own'])), ownership_var, site_var) | |
| elif site_var == 'Fanduel': | |
| st.session_state.data_export_display = map_mask_parse(st.session_state.data_export_display, dict(zip(raw_baselines['Player'], raw_baselines['Median'])), projection_var, site_var) | |
| st.session_state.data_export_display = map_mask_parse(st.session_state.data_export_display, dict(zip(raw_baselines['Player'], raw_baselines['Own'])), ownership_var, site_var) | |
| st.session_state.data_export_display = st.session_state.data_export_display[st.session_state.data_export_display['Team_count'] >= min_stacks_var] | |
| st.session_state.data_export_display = st.session_state.data_export_display[st.session_state.data_export_display['Team_count'] <= max_stacks_var] | |
| st.session_state.data_export_display = st.session_state.data_export_display.reset_index(drop=True) | |
| export_file = st.session_state.data_export_display.copy() | |
| name_export = st.session_state.data_export_display.copy() | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| if sport_var == 'NBA': | |
| map_columns = ['PG', 'SG', 'SF', 'PF', 'C', 'G', 'F', 'FLEX'] | |
| elif sport_var == 'WNBA': | |
| map_columns = ['G1', 'G2', 'F1', 'F2', 'F3', 'UTIL'] | |
| for col_idx in map_columns: | |
| export_file[col_idx] = export_file[col_idx].map(dk_id_map) | |
| elif type_var == 'Showdown': | |
| map_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| for col_idx in map_columns: | |
| export_file[col_idx] = export_file[col_idx].map(dk_sd_id_map) | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| if sport_var == 'NBA': | |
| map_columns = ['PG1', 'PG2', 'SG1', 'SG2', 'SF1', 'SF2', 'PF1', 'PF2', 'C'] | |
| elif sport_var == 'WNBA': | |
| map_columns = ['G1', 'G2', 'G3', 'F1', 'F2', 'F3', 'F4'] | |
| for col_idx in map_columns: | |
| export_file[col_idx] = export_file[col_idx].map(fd_id_map) | |
| elif type_var == 'Showdown': | |
| map_columns = ['CPT', 'FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5'] | |
| for col_idx in map_columns: | |
| export_file[col_idx] = export_file[col_idx].map(fd_sd_id_map) | |
| with st.container(): | |
| if st.button("Reset Optimals", key='reset_optimals_button'): | |
| for key in st.session_state.keys(): | |
| del st.session_state[key] | |
| if site_var == 'Draftkings': | |
| st.session_state.working_seed = dk_lineups.copy() | |
| elif site_var == 'Fanduel': | |
| st.session_state.working_seed = fd_lineups.copy() | |
| if 'data_export_display' in st.session_state: | |
| st.dataframe(st.session_state.data_export_display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), height=500, use_container_width = True, key='optimals_dataframe') | |
| st.download_button( | |
| label="Export display optimals (IDs)", | |
| data=convert_df(export_file), | |
| file_name='NBA_display_optimals.csv', | |
| mime='text/csv', | |
| key='export_display_optimals_ids_button' | |
| ) | |
| st.download_button( | |
| label="Export display optimals (Names)", | |
| data=convert_df(name_export), | |
| file_name='NBA_display_optimals.csv', | |
| mime='text/csv', | |
| key='export_display_optimals_names_button' | |
| ) | |
| with st.container(): | |
| if type_var == 'Regular': | |
| if 'working_seed' in st.session_state: | |
| # Create a new dataframe with summary statistics | |
| if site_var == 'Draftkings': | |
| summary_df = pd.DataFrame({ | |
| 'Metric': ['Min', 'Average', 'Max', 'STDdev'], | |
| 'Salary': [ | |
| np.min(st.session_state.working_seed[:,8]), | |
| np.mean(st.session_state.working_seed[:,8]), | |
| np.max(st.session_state.working_seed[:,8]), | |
| np.std(st.session_state.working_seed[:,8]) | |
| ], | |
| 'Proj': [ | |
| np.min(st.session_state.working_seed[:,9]), | |
| np.mean(st.session_state.working_seed[:,9]), | |
| np.max(st.session_state.working_seed[:,9]), | |
| np.std(st.session_state.working_seed[:,9]) | |
| ], | |
| 'Own': [ | |
| np.min(st.session_state.working_seed[:,14]), | |
| np.mean(st.session_state.working_seed[:,14]), | |
| np.max(st.session_state.working_seed[:,14]), | |
| np.std(st.session_state.working_seed[:,14]) | |
| ] | |
| }) | |
| elif site_var == 'Fanduel': | |
| summary_df = pd.DataFrame({ | |
| 'Metric': ['Min', 'Average', 'Max', 'STDdev'], | |
| 'Salary': [ | |
| np.min(st.session_state.working_seed[:,9]), | |
| np.mean(st.session_state.working_seed[:,9]), | |
| np.max(st.session_state.working_seed[:,9]), | |
| np.std(st.session_state.working_seed[:,9]) | |
| ], | |
| 'Proj': [ | |
| np.min(st.session_state.working_seed[:,10]), | |
| np.mean(st.session_state.working_seed[:,10]), | |
| np.max(st.session_state.working_seed[:,10]), | |
| np.std(st.session_state.working_seed[:,10]) | |
| ], | |
| 'Own': [ | |
| np.min(st.session_state.working_seed[:,15]), | |
| np.mean(st.session_state.working_seed[:,15]), | |
| np.max(st.session_state.working_seed[:,15]), | |
| np.std(st.session_state.working_seed[:,15]) | |
| ] | |
| }) | |
| elif type_var == 'Showdown': | |
| if 'working_seed' in st.session_state: | |
| # Create a new dataframe with summary statistics | |
| if site_var == 'Draftkings': | |
| summary_df = pd.DataFrame({ | |
| 'Metric': ['Min', 'Average', 'Max', 'STDdev'], | |
| 'Salary': [ | |
| np.min(st.session_state.working_seed[:,6]), | |
| np.mean(st.session_state.working_seed[:,6]), | |
| np.max(st.session_state.working_seed[:,6]), | |
| np.std(st.session_state.working_seed[:,6]) | |
| ], | |
| 'Proj': [ | |
| np.min(st.session_state.working_seed[:,7]), | |
| np.mean(st.session_state.working_seed[:,7]), | |
| np.max(st.session_state.working_seed[:,7]), | |
| np.std(st.session_state.working_seed[:,7]) | |
| ], | |
| 'Own': [ | |
| np.min(st.session_state.working_seed[:,12]), | |
| np.mean(st.session_state.working_seed[:,12]), | |
| np.max(st.session_state.working_seed[:,12]), | |
| np.std(st.session_state.working_seed[:,12]) | |
| ] | |
| }) | |
| elif site_var == 'Fanduel': | |
| summary_df = pd.DataFrame({ | |
| 'Metric': ['Min', 'Average', 'Max', 'STDdev'], | |
| 'Salary': [ | |
| np.min(st.session_state.working_seed[:,6]), | |
| np.mean(st.session_state.working_seed[:,6]), | |
| np.max(st.session_state.working_seed[:,6]), | |
| np.std(st.session_state.working_seed[:,6]) | |
| ], | |
| 'Proj': [ | |
| np.min(st.session_state.working_seed[:,7]), | |
| np.mean(st.session_state.working_seed[:,7]), | |
| np.max(st.session_state.working_seed[:,7]), | |
| np.std(st.session_state.working_seed[:,7]) | |
| ], | |
| 'Own': [ | |
| np.min(st.session_state.working_seed[:,12]), | |
| np.mean(st.session_state.working_seed[:,12]), | |
| np.max(st.session_state.working_seed[:,12]), | |
| np.std(st.session_state.working_seed[:,12]) | |
| ] | |
| }) | |
| # Set the index of the summary dataframe as the "Metric" column | |
| summary_df = summary_df.set_index('Metric') | |
| # Display the summary dataframe | |
| st.subheader("Optimal Statistics") | |
| st.dataframe(summary_df.style.format({ | |
| 'Salary': '{:.2f}', | |
| 'Proj': '{:.2f}', | |
| 'Own': '{:.2f}' | |
| }).background_gradient(cmap='RdYlGn', axis=0, subset=['Salary', 'Proj', 'Own']), use_container_width=True, key='optimal_stats_dataframe') | |
| with st.container(): | |
| display_freq_tab, seed_frame_freq_tab = st.tabs(["Display Frequency", "Seed Frame Frequency"]) | |
| with display_freq_tab: | |
| if 'data_export_display' in st.session_state: | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| player_columns = st.session_state.data_export_display.iloc[:, :8] | |
| elif type_var == 'Showdown': | |
| player_columns = st.session_state.data_export_display.iloc[:, :6] | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| player_columns = st.session_state.data_export_display.iloc[:, :9] | |
| elif type_var == 'Showdown': | |
| player_columns = st.session_state.data_export_display.iloc[:, :6] | |
| # Flatten the DataFrame and count unique values | |
| value_counts = player_columns.values.flatten().tolist() | |
| value_counts = pd.Series(value_counts).value_counts() | |
| percentages = (value_counts / lineup_num_var * 100).round(2) | |
| # Create a DataFrame with the results | |
| summary_df = pd.DataFrame({ | |
| 'Player': value_counts.index, | |
| 'Frequency': value_counts.values, | |
| 'Percentage': percentages.values | |
| }) | |
| # Sort by frequency in descending order | |
| summary_df['Salary'] = summary_df['Player'].map(player_salaries) | |
| summary_df = summary_df[['Player', 'Salary', 'Frequency', 'Percentage']] | |
| summary_df = summary_df.sort_values('Frequency', ascending=False) | |
| summary_df = summary_df.set_index('Player') | |
| # Display the table | |
| st.write("Player Frequency Table:") | |
| st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True, key='player_frequency_dataframe') | |
| st.download_button( | |
| label="Export player frequency", | |
| data=convert_df_to_csv(summary_df), | |
| file_name='NBA_player_frequency.csv', | |
| mime='text/csv', | |
| key='export_player_frequency_button' | |
| ) | |
| with seed_frame_freq_tab: | |
| if 'working_seed' in st.session_state: | |
| if site_var == 'Draftkings': | |
| if type_var == 'Regular': | |
| player_columns = st.session_state.working_seed[:, :8] | |
| elif type_var == 'Showdown': | |
| player_columns = st.session_state.working_seed[:, :6] | |
| elif site_var == 'Fanduel': | |
| if type_var == 'Regular': | |
| player_columns = st.session_state.working_seed[:, :9] | |
| elif type_var == 'Showdown': | |
| player_columns = st.session_state.working_seed[:, :6] | |
| # Flatten the DataFrame and count unique values | |
| value_counts = player_columns.flatten().tolist() | |
| value_counts = pd.Series(value_counts).value_counts() | |
| percentages = (value_counts / len(st.session_state.working_seed) * 100).round(2) | |
| # Create a DataFrame with the results | |
| summary_df = pd.DataFrame({ | |
| 'Player': value_counts.index, | |
| 'Frequency': value_counts.values, | |
| 'Percentage': percentages.values | |
| }) | |
| # Sort by frequency in descending order | |
| summary_df['Salary'] = summary_df['Player'].map(player_salaries) | |
| summary_df = summary_df[['Player', 'Salary', 'Frequency', 'Percentage']] | |
| summary_df = summary_df.sort_values('Frequency', ascending=False) | |
| summary_df = summary_df.set_index('Player') | |
| # Display the table | |
| st.write("Seed Frame Frequency Table:") | |
| st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True, key='seed_frame_frequency_dataframe') | |
| st.download_button( | |
| label="Export seed frame frequency", | |
| data=convert_df_to_csv(summary_df), | |
| file_name='NBA_seed_frame_frequency.csv', | |
| mime='text/csv', | |
| key='export_seed_frame_frequency_button' | |
| ) |