James McCool
commited on
Commit
·
8261cfd
1
Parent(s):
294b6d5
Implement segmented control for tab selection and enhance session state management in app.py
Browse files- Introduced a segmented control for selecting between "Data Load" and "Contest Analysis" tabs, improving user navigation.
- Updated session state handling to ensure consistent access to selected sport and game type across various components, enhancing data integrity and user experience.
- Added custom styling for tabs to improve visual appeal and usability.
app.py
CHANGED
|
@@ -119,8 +119,64 @@ def highlight_row_condition(row):
|
|
| 119 |
player_exposure_format = {'Exposure Overall': '{:.2%}', 'Exposure Top 1%': '{:.2%}', 'Exposure Top 5%': '{:.2%}', 'Exposure Top 10%': '{:.2%}', 'Exposure Top 20%': '{:.2%}'}
|
| 120 |
dupe_format = {'uniques%': '{:.2%}', 'under_5%': '{:.2%}', 'under_10%': '{:.2%}'}
|
| 121 |
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
data_select, contest_upload, portfolio_upload = st.columns(3)
|
| 125 |
|
| 126 |
with data_select:
|
|
@@ -129,10 +185,10 @@ with tab1:
|
|
| 129 |
sport_options, date_options = st.columns(2)
|
| 130 |
parse_type = 'Manual'
|
| 131 |
with sport_options:
|
| 132 |
-
sport_select = st.selectbox("Select Sport", ['MLB', 'MMA', 'GOLF', 'NBA', 'NHL', 'WNBA', 'NAS'], key='sport_select')
|
| 133 |
-
type_var = st.selectbox("Select Game Type", ['Classic', 'Showdown'], key='type_var')
|
| 134 |
try:
|
| 135 |
-
contest_names, curr_info = grab_contest_names(db, sport_select, type_var)
|
| 136 |
except:
|
| 137 |
st.error("No contests found for this sport and/or game type")
|
| 138 |
st.stop()
|
|
@@ -156,8 +212,8 @@ with tab1:
|
|
| 156 |
del st.session_state['Contest_file']
|
| 157 |
if 'Contest_file' not in st.session_state:
|
| 158 |
if st.button('Load Contest Data', key='load_contest_data'):
|
| 159 |
-
st.session_state['player_info'], st.session_state['info_maps'] = grab_contest_player_info(db, sport_select, type_var, date_select, contest_name_var, contest_id_map)
|
| 160 |
-
st.session_state['Contest_file'] = grab_contest_data(sport_select, contest_name_var, contest_id_map, date_select, date_select2)
|
| 161 |
else:
|
| 162 |
pass
|
| 163 |
with contest_upload:
|
|
@@ -169,7 +225,7 @@ with tab1:
|
|
| 169 |
del st.session_state['Contest_file']
|
| 170 |
if 'Contest_file' not in st.session_state:
|
| 171 |
st.session_state['Contest_upload'] = st.file_uploader("Upload Contest File (CSV or Excel)", type=['csv', 'xlsx', 'xls'])
|
| 172 |
-
st.session_state['player_info'], st.session_state['info_maps'] = grab_contest_player_info(db, sport_select, type_var, date_select, contest_name_var, contest_id_map)
|
| 173 |
try:
|
| 174 |
st.session_state['Contest_file'] = pd.read_csv(st.session_state['Contest_upload'])
|
| 175 |
except:
|
|
@@ -205,7 +261,7 @@ with tab1:
|
|
| 205 |
|
| 206 |
|
| 207 |
if 'Contest_file' in st.session_state:
|
| 208 |
-
st.session_state['Contest'], st.session_state['ownership_df'], st.session_state['actual_df'], st.session_state['entry_list'], check_lineups = load_contest_file(st.session_state['Contest_file'], type_var, st.session_state['player_info'], sport_select, st.session_state['portfolio_df'])
|
| 209 |
st.session_state['Contest'] = st.session_state['Contest'].dropna(how='all')
|
| 210 |
st.session_state['Contest'] = st.session_state['Contest'].reset_index(drop=True)
|
| 211 |
if st.session_state['Contest'] is not None:
|
|
@@ -216,7 +272,7 @@ with tab1:
|
|
| 216 |
st.warning("If you have confirmed that the data is correct, you can send the CSV to the database to enrich Paydirt's sources and help us create actionable tools and algorithms >>")
|
| 217 |
with upload_col:
|
| 218 |
if st.button('Send file to Database?', key='export_contest_file'):
|
| 219 |
-
return_message = export_contest_file(db, sport_select, type_var, date_select, contest_id_map[contest_name_var], st.session_state['Contest_file'])
|
| 220 |
with message_col:
|
| 221 |
try:
|
| 222 |
st.info(return_message)
|
|
@@ -237,7 +293,7 @@ with tab1:
|
|
| 237 |
st.session_state['team_dict'] = st.session_state['info_maps']['team_dict']
|
| 238 |
st.session_state['pos_dict'] = st.session_state['info_maps']['position_dict']
|
| 239 |
|
| 240 |
-
|
| 241 |
excluded_cols = ['BaseName', 'EntryCount']
|
| 242 |
exclude_stacks = ['BaseName', 'EntryCount', 'SP', 'SP1', 'SP2', 'P1', 'P2']
|
| 243 |
if 'Contest' in st.session_state and 'display_contest_info' not in st.session_state:
|
|
@@ -266,7 +322,7 @@ with tab2:
|
|
| 266 |
actual_map = st.session_state['actual_dict']
|
| 267 |
ownership_map = st.session_state['ownership_dict']
|
| 268 |
|
| 269 |
-
if type_var == 'Classic':
|
| 270 |
# Vectorized stack calculation
|
| 271 |
player_teams = working_df[st.session_state['stack_columns']].apply(
|
| 272 |
lambda x: x.map(team_map).fillna('')
|
|
@@ -328,7 +384,7 @@ with tab2:
|
|
| 328 |
working_df['finish'] = working_df['index']
|
| 329 |
working_df = working_df.drop(['sorted', 'index'], axis=1)
|
| 330 |
|
| 331 |
-
elif type_var == 'Showdown':
|
| 332 |
# Vectorized stack calculation for Showdown
|
| 333 |
player_teams = working_df.iloc[:, 2:].apply(
|
| 334 |
lambda x: x.map(team_map).fillna('')
|
|
@@ -348,7 +404,7 @@ with tab2:
|
|
| 348 |
working_df['stack'] = [result[0] for result in stack_results]
|
| 349 |
working_df['stack_size'] = [result[1] for result in stack_results]
|
| 350 |
|
| 351 |
-
if sport_select == 'GOLF':
|
| 352 |
# Vectorized calculations for GOLF
|
| 353 |
player_salaries = working_df.apply(
|
| 354 |
lambda x: x.map(salary_map).fillna(0)
|
|
@@ -539,21 +595,21 @@ with tab2:
|
|
| 539 |
with col1:
|
| 540 |
pos_var = st.selectbox("Which position(s) would you like to view?", ['All', 'Specific'], key='pos_var')
|
| 541 |
with col2:
|
| 542 |
-
if sport_select == 'MLB':
|
| 543 |
pos_select = st.multiselect("Select your position(s)", ['P', 'C', '1B', '2B', '3B', 'SS', 'OF'], key='pos_select')
|
| 544 |
-
elif sport_select == 'NBA':
|
| 545 |
pos_select = st.multiselect("Select your position(s)", ['PG', 'SG', 'SF', 'PF', 'C'], key='pos_select')
|
| 546 |
-
elif sport_select == 'WNBA':
|
| 547 |
pos_select = st.multiselect("Select your position(s)", ['PG', 'SG', 'SF', 'PF'], key='pos_select')
|
| 548 |
-
elif sport_select == 'NFL':
|
| 549 |
pos_select = st.multiselect("Select your position(s)", ['QB', 'RB', 'WR', 'TE', 'DST'], key='pos_select')
|
| 550 |
-
elif sport_select == 'NHL':
|
| 551 |
pos_select = st.multiselect("Select your position(s)", ['W', 'C', 'D', 'G'], key='pos_select')
|
| 552 |
-
elif sport_select == 'MMA':
|
| 553 |
pos_select = st.multiselect("Select your position(s)", ['All the same position', 'So', 'Yeah', 'Idk'], key='pos_select')
|
| 554 |
-
elif sport_select == 'GOLF':
|
| 555 |
pos_select = st.multiselect("Select your position(s)", ['All the same position', 'So', 'Yeah', 'Idk'], key='pos_select')
|
| 556 |
-
elif sport_select == 'NAS':
|
| 557 |
pos_select = st.multiselect("Select your position(s)", ['All the same position', 'So', 'Yeah', 'Idk'], key='pos_select')
|
| 558 |
submitted = st.form_submit_button("Submit")
|
| 559 |
if submitted:
|
|
@@ -577,9 +633,9 @@ with tab2:
|
|
| 577 |
if comp_player_var == 'Yes':
|
| 578 |
player_exp_comp = create_player_comparison(st.session_state['display_contest_info'], st.session_state['player_columns'], comp_player_select)
|
| 579 |
hold_frame = player_exp_comp.copy()
|
| 580 |
-
if sport_select == 'GOLF':
|
| 581 |
hold_frame['Pos'] = 'G'
|
| 582 |
-
elif sport_select == 'NAS':
|
| 583 |
hold_frame['Pos'] = 'C'
|
| 584 |
else:
|
| 585 |
hold_frame['Pos'] = hold_frame['Player'].map(st.session_state['map_dict']['pos_map'])
|
|
@@ -595,9 +651,9 @@ with tab2:
|
|
| 595 |
|
| 596 |
st.session_state['player_frame'] = create_player_exposures(st.session_state['display_contest_info'], st.session_state['player_columns'])
|
| 597 |
hold_frame = st.session_state['player_frame'].copy()
|
| 598 |
-
if sport_select == 'GOLF':
|
| 599 |
hold_frame['Pos'] = 'G'
|
| 600 |
-
elif sport_select == 'NAS':
|
| 601 |
hold_frame['Pos'] = 'NAS'
|
| 602 |
else:
|
| 603 |
hold_frame['Pos'] = hold_frame['Player'].map(st.session_state['map_dict']['pos_map'])
|
|
@@ -615,9 +671,9 @@ with tab2:
|
|
| 615 |
else:
|
| 616 |
st.session_state['player_frame'] = create_player_exposures(st.session_state['display_contest_info'], st.session_state['player_columns'], st.session_state['entry_names'])
|
| 617 |
hold_frame = st.session_state['player_frame'].copy()
|
| 618 |
-
if sport_select == 'GOLF':
|
| 619 |
hold_frame['Pos'] = 'G'
|
| 620 |
-
elif sport_select == 'NAS':
|
| 621 |
hold_frame['Pos'] = 'NAS'
|
| 622 |
else:
|
| 623 |
hold_frame['Pos'] = hold_frame['Player'].map(st.session_state['map_dict']['pos_map'])
|
|
|
|
| 119 |
player_exposure_format = {'Exposure Overall': '{:.2%}', 'Exposure Top 1%': '{:.2%}', 'Exposure Top 5%': '{:.2%}', 'Exposure Top 10%': '{:.2%}', 'Exposure Top 20%': '{:.2%}'}
|
| 120 |
dupe_format = {'uniques%': '{:.2%}', 'under_5%': '{:.2%}', 'under_10%': '{:.2%}'}
|
| 121 |
|
| 122 |
+
st.markdown("""
|
| 123 |
+
<style>
|
| 124 |
+
/* Tab styling */
|
| 125 |
+
.stElementContainer [data-baseweb="button-group"] {
|
| 126 |
+
gap: 2.000rem;
|
| 127 |
+
padding: 4px;
|
| 128 |
+
}
|
| 129 |
+
.stElementContainer [kind="segmented_control"] {
|
| 130 |
+
height: 2.000rem;
|
| 131 |
+
white-space: pre-wrap;
|
| 132 |
+
background-color: #DAA520;
|
| 133 |
+
color: white;
|
| 134 |
+
border-radius: 20px;
|
| 135 |
+
gap: 1px;
|
| 136 |
+
padding: 10px 20px;
|
| 137 |
+
font-weight: bold;
|
| 138 |
+
transition: all 0.3s ease;
|
| 139 |
+
}
|
| 140 |
+
.stElementContainer [kind="segmented_controlActive"] {
|
| 141 |
+
height: 3.000rem;
|
| 142 |
+
background-color: #DAA520;
|
| 143 |
+
border: 3px solid #FFD700;
|
| 144 |
+
border-radius: 10px;
|
| 145 |
+
color: black;
|
| 146 |
+
}
|
| 147 |
+
.stElementContainer [kind="segmented_control"]:hover {
|
| 148 |
+
background-color: #FFD700;
|
| 149 |
+
cursor: pointer;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
div[data-baseweb="select"] > div {
|
| 153 |
+
background-color: #DAA520;
|
| 154 |
+
color: white;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
</style>""", unsafe_allow_html=True)
|
| 158 |
+
|
| 159 |
+
try:
|
| 160 |
+
selected_tab = st.segmented_control(
|
| 161 |
+
"Select Tab",
|
| 162 |
+
options=["Data Load", "Contest Analysis"],
|
| 163 |
+
selection_mode='single',
|
| 164 |
+
default='Data Load',
|
| 165 |
+
width='stretch',
|
| 166 |
+
label_visibility='collapsed',
|
| 167 |
+
key='tab_selector'
|
| 168 |
+
)
|
| 169 |
+
except:
|
| 170 |
+
selected_tab = st.segmented_control(
|
| 171 |
+
"Select Tab",
|
| 172 |
+
options=["Data Load", "Contest Analysis"],
|
| 173 |
+
selection_mode='single',
|
| 174 |
+
default='Data Load',
|
| 175 |
+
label_visibility='collapsed',
|
| 176 |
+
key='tab_selector'
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
if selected_tab == 'Data Load':
|
| 180 |
data_select, contest_upload, portfolio_upload = st.columns(3)
|
| 181 |
|
| 182 |
with data_select:
|
|
|
|
| 185 |
sport_options, date_options = st.columns(2)
|
| 186 |
parse_type = 'Manual'
|
| 187 |
with sport_options:
|
| 188 |
+
st.session_state['sport_select'] = st.selectbox("Select Sport", ['MLB', 'MMA', 'GOLF', 'NBA', 'NHL', 'WNBA', 'NAS'], key='sport_select')
|
| 189 |
+
st.session_state['type_var'] = st.selectbox("Select Game Type", ['Classic', 'Showdown'], key='type_var')
|
| 190 |
try:
|
| 191 |
+
contest_names, curr_info = grab_contest_names(db, st.session_state['sport_select'], st.session_state['type_var'])
|
| 192 |
except:
|
| 193 |
st.error("No contests found for this sport and/or game type")
|
| 194 |
st.stop()
|
|
|
|
| 212 |
del st.session_state['Contest_file']
|
| 213 |
if 'Contest_file' not in st.session_state:
|
| 214 |
if st.button('Load Contest Data', key='load_contest_data'):
|
| 215 |
+
st.session_state['player_info'], st.session_state['info_maps'] = grab_contest_player_info(db, st.session_state['sport_select'], st.session_state['type_var'], date_select, contest_name_var, contest_id_map)
|
| 216 |
+
st.session_state['Contest_file'] = grab_contest_data(st.session_state['sport_select'], contest_name_var, contest_id_map, date_select, date_select2)
|
| 217 |
else:
|
| 218 |
pass
|
| 219 |
with contest_upload:
|
|
|
|
| 225 |
del st.session_state['Contest_file']
|
| 226 |
if 'Contest_file' not in st.session_state:
|
| 227 |
st.session_state['Contest_upload'] = st.file_uploader("Upload Contest File (CSV or Excel)", type=['csv', 'xlsx', 'xls'])
|
| 228 |
+
st.session_state['player_info'], st.session_state['info_maps'] = grab_contest_player_info(db, st.session_state['sport_select'], st.session_state['type_var'], date_select, contest_name_var, contest_id_map)
|
| 229 |
try:
|
| 230 |
st.session_state['Contest_file'] = pd.read_csv(st.session_state['Contest_upload'])
|
| 231 |
except:
|
|
|
|
| 261 |
|
| 262 |
|
| 263 |
if 'Contest_file' in st.session_state:
|
| 264 |
+
st.session_state['Contest'], st.session_state['ownership_df'], st.session_state['actual_df'], st.session_state['entry_list'], check_lineups = load_contest_file(st.session_state['Contest_file'], st.session_state['type_var'], st.session_state['player_info'], st.session_state['sport_select'], st.session_state['portfolio_df'])
|
| 265 |
st.session_state['Contest'] = st.session_state['Contest'].dropna(how='all')
|
| 266 |
st.session_state['Contest'] = st.session_state['Contest'].reset_index(drop=True)
|
| 267 |
if st.session_state['Contest'] is not None:
|
|
|
|
| 272 |
st.warning("If you have confirmed that the data is correct, you can send the CSV to the database to enrich Paydirt's sources and help us create actionable tools and algorithms >>")
|
| 273 |
with upload_col:
|
| 274 |
if st.button('Send file to Database?', key='export_contest_file'):
|
| 275 |
+
return_message = export_contest_file(db, st.session_state['sport_select'], st.session_state['type_var'], date_select, contest_id_map[contest_name_var], st.session_state['Contest_file'])
|
| 276 |
with message_col:
|
| 277 |
try:
|
| 278 |
st.info(return_message)
|
|
|
|
| 293 |
st.session_state['team_dict'] = st.session_state['info_maps']['team_dict']
|
| 294 |
st.session_state['pos_dict'] = st.session_state['info_maps']['position_dict']
|
| 295 |
|
| 296 |
+
elif selected_tab == 'Contest Analysis':
|
| 297 |
excluded_cols = ['BaseName', 'EntryCount']
|
| 298 |
exclude_stacks = ['BaseName', 'EntryCount', 'SP', 'SP1', 'SP2', 'P1', 'P2']
|
| 299 |
if 'Contest' in st.session_state and 'display_contest_info' not in st.session_state:
|
|
|
|
| 322 |
actual_map = st.session_state['actual_dict']
|
| 323 |
ownership_map = st.session_state['ownership_dict']
|
| 324 |
|
| 325 |
+
if st.session_state['type_var'] == 'Classic':
|
| 326 |
# Vectorized stack calculation
|
| 327 |
player_teams = working_df[st.session_state['stack_columns']].apply(
|
| 328 |
lambda x: x.map(team_map).fillna('')
|
|
|
|
| 384 |
working_df['finish'] = working_df['index']
|
| 385 |
working_df = working_df.drop(['sorted', 'index'], axis=1)
|
| 386 |
|
| 387 |
+
elif st.session_state['type_var'] == 'Showdown':
|
| 388 |
# Vectorized stack calculation for Showdown
|
| 389 |
player_teams = working_df.iloc[:, 2:].apply(
|
| 390 |
lambda x: x.map(team_map).fillna('')
|
|
|
|
| 404 |
working_df['stack'] = [result[0] for result in stack_results]
|
| 405 |
working_df['stack_size'] = [result[1] for result in stack_results]
|
| 406 |
|
| 407 |
+
if st.session_state['sport_select'] == 'GOLF':
|
| 408 |
# Vectorized calculations for GOLF
|
| 409 |
player_salaries = working_df.apply(
|
| 410 |
lambda x: x.map(salary_map).fillna(0)
|
|
|
|
| 595 |
with col1:
|
| 596 |
pos_var = st.selectbox("Which position(s) would you like to view?", ['All', 'Specific'], key='pos_var')
|
| 597 |
with col2:
|
| 598 |
+
if st.session_state['sport_select'] == 'MLB':
|
| 599 |
pos_select = st.multiselect("Select your position(s)", ['P', 'C', '1B', '2B', '3B', 'SS', 'OF'], key='pos_select')
|
| 600 |
+
elif st.session_state['sport_select'] == 'NBA':
|
| 601 |
pos_select = st.multiselect("Select your position(s)", ['PG', 'SG', 'SF', 'PF', 'C'], key='pos_select')
|
| 602 |
+
elif st.session_state['sport_select'] == 'WNBA':
|
| 603 |
pos_select = st.multiselect("Select your position(s)", ['PG', 'SG', 'SF', 'PF'], key='pos_select')
|
| 604 |
+
elif st.session_state['sport_select'] == 'NFL':
|
| 605 |
pos_select = st.multiselect("Select your position(s)", ['QB', 'RB', 'WR', 'TE', 'DST'], key='pos_select')
|
| 606 |
+
elif st.session_state['sport_select'] == 'NHL':
|
| 607 |
pos_select = st.multiselect("Select your position(s)", ['W', 'C', 'D', 'G'], key='pos_select')
|
| 608 |
+
elif st.session_state['sport_select'] == 'MMA':
|
| 609 |
pos_select = st.multiselect("Select your position(s)", ['All the same position', 'So', 'Yeah', 'Idk'], key='pos_select')
|
| 610 |
+
elif st.session_state['sport_select'] == 'GOLF':
|
| 611 |
pos_select = st.multiselect("Select your position(s)", ['All the same position', 'So', 'Yeah', 'Idk'], key='pos_select')
|
| 612 |
+
elif st.session_state['sport_select'] == 'NAS':
|
| 613 |
pos_select = st.multiselect("Select your position(s)", ['All the same position', 'So', 'Yeah', 'Idk'], key='pos_select')
|
| 614 |
submitted = st.form_submit_button("Submit")
|
| 615 |
if submitted:
|
|
|
|
| 633 |
if comp_player_var == 'Yes':
|
| 634 |
player_exp_comp = create_player_comparison(st.session_state['display_contest_info'], st.session_state['player_columns'], comp_player_select)
|
| 635 |
hold_frame = player_exp_comp.copy()
|
| 636 |
+
if st.session_state['sport_select'] == 'GOLF':
|
| 637 |
hold_frame['Pos'] = 'G'
|
| 638 |
+
elif st.session_state['sport_select'] == 'NAS':
|
| 639 |
hold_frame['Pos'] = 'C'
|
| 640 |
else:
|
| 641 |
hold_frame['Pos'] = hold_frame['Player'].map(st.session_state['map_dict']['pos_map'])
|
|
|
|
| 651 |
|
| 652 |
st.session_state['player_frame'] = create_player_exposures(st.session_state['display_contest_info'], st.session_state['player_columns'])
|
| 653 |
hold_frame = st.session_state['player_frame'].copy()
|
| 654 |
+
if st.session_state['sport_select'] == 'GOLF':
|
| 655 |
hold_frame['Pos'] = 'G'
|
| 656 |
+
elif st.session_state['sport_select'] == 'NAS':
|
| 657 |
hold_frame['Pos'] = 'NAS'
|
| 658 |
else:
|
| 659 |
hold_frame['Pos'] = hold_frame['Player'].map(st.session_state['map_dict']['pos_map'])
|
|
|
|
| 671 |
else:
|
| 672 |
st.session_state['player_frame'] = create_player_exposures(st.session_state['display_contest_info'], st.session_state['player_columns'], st.session_state['entry_names'])
|
| 673 |
hold_frame = st.session_state['player_frame'].copy()
|
| 674 |
+
if st.session_state['sport_select'] == 'GOLF':
|
| 675 |
hold_frame['Pos'] = 'G'
|
| 676 |
+
elif st.session_state['sport_select'] == 'NAS':
|
| 677 |
hold_frame['Pos'] = 'NAS'
|
| 678 |
else:
|
| 679 |
hold_frame['Pos'] = hold_frame['Player'].map(st.session_state['map_dict']['pos_map'])
|