James McCool commited on
Commit
02bc151
·
1 Parent(s): eb2b4ba

forced unique keys

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +75 -52
src/streamlit_app.py CHANGED
@@ -305,9 +305,17 @@ def convert_hb_df(array, column_names):
305
  array = pd.DataFrame(array, columns=column_names)
306
  return array.to_csv().encode('utf-8')
307
 
 
 
 
 
 
 
 
 
308
  col1, col2 = st.columns([1, 9])
309
  with col1:
310
- if st.button("Load/Reset Data", key='reset'):
311
  st.cache_data.clear()
312
  player_stats, dk_stacks_raw, fd_stacks_raw, dk_roo_raw, fd_roo_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map = init_baselines()
313
  dk_lineups = init_DK_lineups('Regular', 'Main')
@@ -318,9 +326,9 @@ with col2:
318
  with st.container():
319
  col1, col2 = st.columns([3, 3])
320
  with col1:
321
- view_var = st.selectbox("Select view", ["Simple", "Advanced"], key='view_var')
322
  with col2:
323
- site_var = st.selectbox("What site do you want to view?", ('Draftkings', 'Fanduel'), key='site_var')
324
 
325
  player_stats, dk_stacks_raw, fd_stacks_raw, dk_roo_raw, fd_roo_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map = init_baselines()
326
 
@@ -329,11 +337,11 @@ t_stamp = f"Last Update: " + str(dk_roo_raw['timestamp'][0]) + f" CST"
329
  tab1, tab2, tab3, tab4 = st.tabs(["Stacks ROO", "Player ROO", "Optimals", "Handbuilder"])
330
 
331
  with tab1:
332
- with st.expander("Info and Filters"):
333
  st.info(t_stamp)
334
  with st.container():
335
- slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Secondary Slate', 'Late Slate', 'Thurs-Mon Slate'), key='slate_var1')
336
- split_var1 = st.radio("Would you like to view the whole slate or just specific games?", ('Full Slate Run', 'Specific Games'), key='split_var1')
337
  if site_var == 'Draftkings':
338
  raw_baselines = dk_stacks_raw[dk_stacks_raw['slate'] == str(slate_var1)]
339
  raw_baselines = raw_baselines[raw_baselines['version'] == 'overall']
@@ -343,7 +351,7 @@ with tab1:
343
  raw_baselines = raw_baselines[raw_baselines['version'] == 'overall']
344
  raw_baselines = raw_baselines.iloc[:,:-2]
345
  if split_var1 == 'Specific Games':
346
- team_var1 = st.multiselect('Which teams would you like to include in the ROO?', options = raw_baselines['Team'].unique(), key='team_var1')
347
  elif split_var1 == 'Full Slate Run':
348
  team_var1 = raw_baselines.Team.values.tolist()
349
 
@@ -353,18 +361,19 @@ with tab1:
353
  elif view_var == 'Advanced':
354
  final_stacks = final_stacks[['Team', 'QB', 'WR1_TE', 'WR2_TE', 'Total', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish',
355
  'Top_10_finish', '60+%', '2x%', '3x%', '4x%', 'Own', 'LevX']]
356
- st.dataframe(final_stacks.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), height=750, use_container_width = True)
357
  st.download_button(
358
  label="Export Tables",
359
  data=convert_df_to_csv(final_stacks),
360
  file_name='NFL_stacks_export.csv',
361
  mime='text/csv',
 
362
  )
363
 
364
  with tab2:
365
- with st.expander("Info and Filters"):
366
  st.info(t_stamp)
367
- slate_var2 = st.radio("Which data are you loading?", ('Main Slate', 'Secondary Slate', 'Late Slate', 'Thurs-Mon Slate'), key='slate_var2')
368
  if site_var == 'Draftkings':
369
  raw_baselines = dk_roo_raw[dk_roo_raw['slate'] == str(slate_var2)]
370
 
@@ -372,14 +381,14 @@ with tab2:
372
  elif site_var == 'Fanduel':
373
  raw_baselines = fd_roo_raw[fd_roo_raw['slate'] == str(slate_var2)]
374
  raw_baselines = raw_baselines.iloc[:,:-2]
375
- split_var2 = st.radio("Would you like to view the whole slate or just specific games?", ('Full Slate Run', 'Specific Games'), key='split_var2')
376
  if split_var2 == 'Specific Games':
377
- team_var2 = st.multiselect('Which teams would you like to include in the ROO?', options = raw_baselines['Team'].unique(), key='team_var2')
378
  elif split_var2 == 'Full Slate Run':
379
  team_var2 = raw_baselines.Team.values.tolist()
380
- pos_split2 = st.selectbox('What Position table would you like to view?', options = ['Overall', 'QB', 'RB', 'WR', 'TE'], key='pos_split2')
381
- pos_combos2 = st.multiselect('If Overall, specific positions?', options = ['QB', 'RB', 'WR', 'TE', 'DST'], default = ['QB', 'RB', 'WR', 'TE', 'DST'], key='pos_combos2')
382
- sal_var2 = st.slider("Is there a certain price range you want to view?", 2000, 15000, (2000, 15000), key='sal_var2')
383
 
384
  if pos_split2 == 'Overall':
385
  raw_baselines = raw_baselines[raw_baselines['version'] == 'overall']
@@ -414,21 +423,22 @@ with tab2:
414
  elif view_var == 'Advanced':
415
  final_Proj = final_Proj[['Player', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'Own', 'Small_Field_Own', 'Large_Field_Own', 'Cash_Field_Own', 'CPT_Own', 'LevX']]
416
  disp_proj = final_Proj.set_index('Player')
417
- st.dataframe(disp_proj.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), height=750, use_container_width = True)
418
  st.download_button(
419
  label="Export Tables",
420
  data=convert_df_to_csv(final_Proj),
421
  file_name='NFL_ROO_export.csv',
422
  mime='text/csv',
 
423
  )
424
 
425
  with tab3:
426
  st.header("Optimals")
427
- with st.expander("Info and Filters"):
428
  st.info("These filters will display various optimals in the table below to pick from. 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.")
429
  col1, col2, col3, col4 = st.columns(4)
430
  with col1:
431
- slate_type_var3 = st.radio("Which slate type are you loading?", ('Regular', 'Showdown'), key='slate_type_var3')
432
  if slate_type_var3 == 'Regular':
433
  if site_var == 'Draftkings':
434
  raw_baselines = dk_roo_raw
@@ -439,7 +449,7 @@ with tab3:
439
  raw_baselines = dk_sd_roo_raw
440
  elif site_var == 'Fanduel':
441
  raw_baselines = fd_sd_roo_raw
442
- slate_var3 = st.radio("Which slate data are you loading?", ('Main', 'Secondary', 'Auxiliary'), key='slate_var3')
443
  if slate_type_var3 == 'Regular':
444
  if site_var == 'Draftkings':
445
  dk_lineups = init_DK_lineups(slate_type_var3, slate_var3)
@@ -451,26 +461,26 @@ with tab3:
451
  elif site_var == 'Fanduel':
452
  fd_lineups = init_FD_lineups(slate_type_var3, slate_var3)
453
  with col2:
454
- lineup_num_var = st.number_input("How many lineups do you want to display?", min_value=1, max_value=1000, value=150, step=1)
455
- player_var1 = st.radio("Do you want a frame with specific Players?", ('Full Slate', 'Specific Players'), key='player_var1')
456
  if player_var1 == 'Specific Players':
457
- player_var2 = st.multiselect('Which players do you want?', options = raw_baselines['Player'].unique())
458
  elif player_var1 == 'Full Slate':
459
  player_var2 = raw_baselines.Player.values.tolist()
460
  with col3:
461
  if site_var == 'Draftkings':
462
- salary_min_var = st.number_input("Minimum salary used", min_value = 0, max_value = 50000, value = 49000, step = 100, key = 'salary_min_var')
463
- salary_max_var = st.number_input("Maximum salary used", min_value = 0, max_value = 50000, value = 50000, step = 100, key = 'salary_max_var')
464
  elif site_var == 'Fanduel':
465
- salary_min_var = st.number_input("Minimum salary used", min_value = 0, max_value = 60000, value = 59000, step = 100, key = 'salary_min_var')
466
- salary_max_var = st.number_input("Maximum salary used", min_value = 0, max_value = 60000, value = 60000, step = 100, key = 'salary_max_var')
467
  with col4:
468
  if site_var == 'Draftkings':
469
- min_stacks_var = st.number_input("Minimum stacks used", min_value = 0, max_value = 5, value = 1, step = 1, key = 'min_stacks_var')
470
- max_stacks_var = st.number_input("Maximum stacks used", min_value = 0, max_value = 5, value = 5, step = 1, key = 'max_stacks_var')
471
  elif site_var == 'Fanduel':
472
- min_stacks_var = st.number_input("Minimum stacks used", min_value = 0, max_value = 4, value = 1, step = 1, key = 'min_stacks_var')
473
- max_stacks_var = st.number_input("Maximum stacks used", min_value = 0, max_value = 4, value = 4, step = 1, key = 'max_stacks_var')
474
 
475
 
476
  if site_var == 'Draftkings':
@@ -496,7 +506,7 @@ with tab3:
496
 
497
  reg_dl_col, filtered_dl_col, blank_dl_col = st.columns([2, 2, 6])
498
  with reg_dl_col:
499
- if st.button("Prepare full data export", key='data_export'):
500
  name_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
501
  data_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
502
  if site_var == 'Draftkings':
@@ -524,12 +534,14 @@ with tab3:
524
  data=convert_df(data_export),
525
  file_name='NFL_optimals_export.csv',
526
  mime='text/csv',
 
527
  )
528
  st.download_button(
529
  label="Export optimals set (Names)",
530
  data=convert_df(name_export),
531
  file_name='NFL_optimals_export.csv',
532
  mime='text/csv',
 
533
  )
534
  with pm_opt_col:
535
  if site_var == 'Draftkings':
@@ -547,6 +559,7 @@ with tab3:
547
  data=convert_pm_df(data_export),
548
  file_name='NFL_optimals_export.csv',
549
  mime='text/csv',
 
550
  )
551
 
552
  if site_var == 'Draftkings':
@@ -564,9 +577,10 @@ with tab3:
564
  data=convert_pm_df(name_export),
565
  file_name='NFL_optimals_export.csv',
566
  mime='text/csv',
 
567
  )
568
  with filtered_dl_col:
569
- if st.button("Prepare full data export (Filtered)", key='data_export_filtered'):
570
  name_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
571
  data_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
572
  if site_var == 'Draftkings':
@@ -600,12 +614,14 @@ with tab3:
600
  data=convert_df(data_export),
601
  file_name='NFL_optimals_export.csv',
602
  mime='text/csv',
 
603
  )
604
  st.download_button(
605
  label="Export optimals set (Names)",
606
  data=convert_df(name_export),
607
  file_name='NFL_optimals_export.csv',
608
  mime='text/csv',
 
609
  )
610
  with pm_opt_col:
611
  if site_var == 'Draftkings':
@@ -623,6 +639,7 @@ with tab3:
623
  data=convert_pm_df(data_export),
624
  file_name='NFL_optimals_export.csv',
625
  mime='text/csv',
 
626
  )
627
 
628
  if site_var == 'Draftkings':
@@ -640,6 +657,7 @@ with tab3:
640
  data=convert_pm_df(name_export),
641
  file_name='NFL_optimals_export.csv',
642
  mime='text/csv',
 
643
  )
644
 
645
  if site_var == 'Draftkings':
@@ -697,7 +715,7 @@ with tab3:
697
  export_file[col_idx] = export_file[col_idx].map(fd_id_map)
698
 
699
  with st.container():
700
- if st.button("Reset Optimals", key='reset3'):
701
  for key in st.session_state.keys():
702
  del st.session_state[key]
703
  if site_var == 'Draftkings':
@@ -705,18 +723,20 @@ with tab3:
705
  elif site_var == 'Fanduel':
706
  st.session_state.working_seed = fd_lineups.copy()
707
  if 'data_export_display' in st.session_state:
708
- 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)
709
  st.download_button(
710
  label="Export display optimals (IDs)",
711
  data=convert_df(export_file),
712
  file_name='NFL_display_optimals.csv',
713
  mime='text/csv',
 
714
  )
715
  st.download_button(
716
  label="Export display optimals (Names)",
717
  data=convert_df(name_export),
718
  file_name='NFL_display_optimals.csv',
719
  mime='text/csv',
 
720
  )
721
 
722
  with st.container():
@@ -824,7 +844,7 @@ with tab3:
824
  'Salary': '{:.2f}',
825
  'Proj': '{:.2f}',
826
  'Own': '{:.2f}'
827
- }).background_gradient(cmap='RdYlGn', axis=0, subset=['Salary', 'Proj', 'Own']), use_container_width=True)
828
 
829
  with st.container():
830
  tab1, tab2 = st.tabs(["Display Frequency", "Seed Frame Frequency"])
@@ -862,13 +882,14 @@ with tab3:
862
 
863
  # Display the table
864
  st.write("Player Frequency Table:")
865
- st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True)
866
 
867
  st.download_button(
868
  label="Export player frequency",
869
  data=convert_df_to_csv(summary_df),
870
  file_name='NFL_player_frequency.csv',
871
  mime='text/csv',
 
872
  )
873
  with tab2:
874
  if 'working_seed' in st.session_state:
@@ -903,13 +924,14 @@ with tab3:
903
 
904
  # Display the table
905
  st.write("Seed Frame Frequency Table:")
906
- st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True)
907
 
908
  st.download_button(
909
  label="Export seed frame frequency",
910
  data=convert_df_to_csv(summary_df),
911
  file_name='NFL_seed_frame_frequency.csv',
912
  mime='text/csv',
 
913
  )
914
 
915
  with tab4:
@@ -917,7 +939,7 @@ with tab4:
917
  with col1:
918
  st.header("Handbuilder")
919
  with col2:
920
- slate_var3 = st.selectbox("Slate Selection", options=['Main', 'Secondary', 'Auxiliary'])
921
  if site_var == 'Draftkings':
922
  if slate_var3 == 'Main':
923
  handbuild_roo = dk_roo_raw[dk_roo_raw['slate'] == 'Main Slate']
@@ -970,15 +992,15 @@ with tab4:
970
  slot_counts = lineup['Slot'].value_counts() if not lineup.empty else {}
971
 
972
  # --- PLAYER FILTERS ---
973
- with st.expander("Player Filters"):
974
  col1, col2 = st.columns(2)
975
  with col1:
976
- pos_select3 = st.multiselect("Select your position(s)", options=['QB', 'RB', 'WR', 'TE', 'UTIL', 'DST'], key='pos_select3')
977
  with col2:
978
- salary_var = st.number_input("Salary Max", min_value = 0, max_value = 20000, value = 20000, step = 100)
979
 
980
  # --- TEAM FILTER UI ---
981
- with st.expander("Team Filters"):
982
  all_teams = sorted(handbuild_roo['Team'].unique())
983
  st.markdown("**Toggle teams to include:**")
984
  team_cols = st.columns(len(all_teams) // 2 + 1)
@@ -988,7 +1010,7 @@ with tab4:
988
  col = team_cols[idx % len(team_cols)]
989
  if f"handbuilder_team_{team}" not in st.session_state:
990
  st.session_state[f"handbuilder_team_{team}"] = False
991
- checked = col.toggle(team, value=st.session_state[f"handbuilder_team_{team}"], key=f"handbuilder_team_{team}")
992
  if checked:
993
  selected_teams.append(team)
994
 
@@ -1010,12 +1032,12 @@ with tab4:
1010
  player_select_df = player_select_df[player_select_df['Salary'] <= salary_var]
1011
 
1012
 
1013
- with st.expander("Quick Fill Options"):
1014
- auto_team_var = st.selectbox("Auto Fill Team", options=all_teams)
1015
- auto_size_var = st.selectbox("Auto Fill Size", options=[3, 4, 5])
1016
- auto_range_var = st.selectbox("Auto Fill Options", options=['QB/WR', 'RB/WR/TE', 'QB/WR/TE/RB'])
1017
  # --- QUICK FILL LOGIC ---
1018
- if st.button("Quick Fill", key="quick_fill"):
1019
  # 1. Get all eligible players from the selected team, not already in the lineup
1020
  current_players = set(st.session_state['handbuilder_lineup']['Player'])
1021
  team_players = player_select_df[
@@ -1198,7 +1220,7 @@ with tab4:
1198
  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),
1199
  on_select="rerun",
1200
  selection_mode=["single-row"],
1201
- key="lineup_remove",
1202
  height=445,
1203
  hide_index=True
1204
  )
@@ -1277,11 +1299,11 @@ with tab4:
1277
  # Optionally, add a button to clear the lineup
1278
  clear_col, save_col, export_col, clear_saved_col, blank_col = st.columns([2, 2, 2, 2, 12])
1279
  with clear_col:
1280
- if st.button("Clear Lineup", key='clear_lineup'):
1281
  st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', '2x%', 'Own', 'Slot'])
1282
  st.rerun()
1283
  with save_col:
1284
- if st.button("Save Lineup", key='save_lineup'):
1285
  if 'saved_lineups' in st.session_state:
1286
  st.session_state['saved_lineups'].append(lineup_display_df['Player'].tolist())
1287
  print(st.session_state['saved_lineups'])
@@ -1298,6 +1320,7 @@ with tab4:
1298
  data=convert_hb_df(saved_lineups_array, dk_hb_columns if site_var == 'Draftkings' else fd_hb_columns),
1299
  file_name='handbuilds_export.csv',
1300
  mime='text/csv',
 
1301
  )
1302
  else:
1303
  st.write("No saved lineups to export")
@@ -1308,7 +1331,7 @@ with tab4:
1308
  st.write("No saved lineups")
1309
 
1310
  with clear_saved_col:
1311
- if st.button("Clear Saved", key='clear_saved'):
1312
  if 'saved_lineups' in st.session_state:
1313
  del st.session_state['saved_lineups']
1314
  st.rerun()
 
305
  array = pd.DataFrame(array, columns=column_names)
306
  return array.to_csv().encode('utf-8')
307
 
308
+ # Add this function at the top after imports
309
+ def get_unique_key(prefix, base_key):
310
+ """Generate a unique key for Streamlit elements"""
311
+ if f"{prefix}_{base_key}" not in st.session_state:
312
+ st.session_state[f"{prefix}_{base_key}"] = 0
313
+ st.session_state[f"{prefix}_{base_key}"] += 1
314
+ return f"{prefix}_{base_key}_{st.session_state[f'{prefix}_{base_key}']}"
315
+
316
  col1, col2 = st.columns([1, 9])
317
  with col1:
318
+ if st.button("Load/Reset Data", key='reset_data_button'):
319
  st.cache_data.clear()
320
  player_stats, dk_stacks_raw, fd_stacks_raw, dk_roo_raw, fd_roo_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map = init_baselines()
321
  dk_lineups = init_DK_lineups('Regular', 'Main')
 
326
  with st.container():
327
  col1, col2 = st.columns([3, 3])
328
  with col1:
329
+ view_var = st.selectbox("Select view", ["Simple", "Advanced"], key='view_selectbox')
330
  with col2:
331
+ site_var = st.selectbox("What site do you want to view?", ('Draftkings', 'Fanduel'), key='site_selectbox')
332
 
333
  player_stats, dk_stacks_raw, fd_stacks_raw, dk_roo_raw, fd_roo_raw, dk_sd_roo_raw, fd_sd_roo_raw, dk_id_map, fd_id_map, dk_sd_id_map, fd_sd_id_map = init_baselines()
334
 
 
337
  tab1, tab2, tab3, tab4 = st.tabs(["Stacks ROO", "Player ROO", "Optimals", "Handbuilder"])
338
 
339
  with tab1:
340
+ with st.expander("Info and Filters", key='stacks_info_expander'):
341
  st.info(t_stamp)
342
  with st.container():
343
+ slate_var1 = st.radio("Which data are you loading?", ('Main Slate', 'Secondary Slate', 'Late Slate', 'Thurs-Mon Slate'), key='slate_var1_radio')
344
+ split_var1 = st.radio("Would you like to view the whole slate or just specific games?", ('Full Slate Run', 'Specific Games'), key='split_var1_radio')
345
  if site_var == 'Draftkings':
346
  raw_baselines = dk_stacks_raw[dk_stacks_raw['slate'] == str(slate_var1)]
347
  raw_baselines = raw_baselines[raw_baselines['version'] == 'overall']
 
351
  raw_baselines = raw_baselines[raw_baselines['version'] == 'overall']
352
  raw_baselines = raw_baselines.iloc[:,:-2]
353
  if split_var1 == 'Specific Games':
354
+ team_var1 = st.multiselect('Which teams would you like to include in the ROO?', options = raw_baselines['Team'].unique(), key='team_var1_multiselect')
355
  elif split_var1 == 'Full Slate Run':
356
  team_var1 = raw_baselines.Team.values.tolist()
357
 
 
361
  elif view_var == 'Advanced':
362
  final_stacks = final_stacks[['Team', 'QB', 'WR1_TE', 'WR2_TE', 'Total', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish',
363
  'Top_10_finish', '60+%', '2x%', '3x%', '4x%', 'Own', 'LevX']]
364
+ st.dataframe(final_stacks.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), height=750, use_container_width = True, key='stacks_dataframe')
365
  st.download_button(
366
  label="Export Tables",
367
  data=convert_df_to_csv(final_stacks),
368
  file_name='NFL_stacks_export.csv',
369
  mime='text/csv',
370
+ key='stacks_export_button'
371
  )
372
 
373
  with tab2:
374
+ with st.expander("Info and Filters", key='player_info_expander'):
375
  st.info(t_stamp)
376
+ slate_var2 = st.radio("Which data are you loading?", ('Main Slate', 'Secondary Slate', 'Late Slate', 'Thurs-Mon Slate'), key='slate_var2_radio')
377
  if site_var == 'Draftkings':
378
  raw_baselines = dk_roo_raw[dk_roo_raw['slate'] == str(slate_var2)]
379
 
 
381
  elif site_var == 'Fanduel':
382
  raw_baselines = fd_roo_raw[fd_roo_raw['slate'] == str(slate_var2)]
383
  raw_baselines = raw_baselines.iloc[:,:-2]
384
+ split_var2 = st.radio("Would you like to view the whole slate or just specific games?", ('Full Slate Run', 'Specific Games'), key='split_var2_radio')
385
  if split_var2 == 'Specific Games':
386
+ team_var2 = st.multiselect('Which teams would you like to include in the ROO?', options = raw_baselines['Team'].unique(), key='team_var2_multiselect')
387
  elif split_var2 == 'Full Slate Run':
388
  team_var2 = raw_baselines.Team.values.tolist()
389
+ pos_split2 = st.selectbox('What Position table would you like to view?', options = ['Overall', 'QB', 'RB', 'WR', 'TE'], key='pos_split2_selectbox')
390
+ pos_combos2 = st.multiselect('If Overall, specific positions?', options = ['QB', 'RB', 'WR', 'TE', 'DST'], default = ['QB', 'RB', 'WR', 'TE', 'DST'], key='pos_combos2_multiselect')
391
+ sal_var2 = st.slider("Is there a certain price range you want to view?", 2000, 15000, (2000, 15000), key='sal_var2_slider')
392
 
393
  if pos_split2 == 'Overall':
394
  raw_baselines = raw_baselines[raw_baselines['version'] == 'overall']
 
423
  elif view_var == 'Advanced':
424
  final_Proj = final_Proj[['Player', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'Own', 'Small_Field_Own', 'Large_Field_Own', 'Cash_Field_Own', 'CPT_Own', 'LevX']]
425
  disp_proj = final_Proj.set_index('Player')
426
+ st.dataframe(disp_proj.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), height=750, use_container_width = True, key='player_dataframe')
427
  st.download_button(
428
  label="Export Tables",
429
  data=convert_df_to_csv(final_Proj),
430
  file_name='NFL_ROO_export.csv',
431
  mime='text/csv',
432
+ key='player_export_button'
433
  )
434
 
435
  with tab3:
436
  st.header("Optimals")
437
+ with st.expander("Info and Filters", key='optimals_info_expander'):
438
  st.info("These filters will display various optimals in the table below to pick from. 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.")
439
  col1, col2, col3, col4 = st.columns(4)
440
  with col1:
441
+ slate_type_var3 = st.radio("Which slate type are you loading?", ('Regular', 'Showdown'), key='slate_type_var3_radio')
442
  if slate_type_var3 == 'Regular':
443
  if site_var == 'Draftkings':
444
  raw_baselines = dk_roo_raw
 
449
  raw_baselines = dk_sd_roo_raw
450
  elif site_var == 'Fanduel':
451
  raw_baselines = fd_sd_roo_raw
452
+ slate_var3 = st.radio("Which slate data are you loading?", ('Main', 'Secondary', 'Auxiliary'), key='slate_var3_radio')
453
  if slate_type_var3 == 'Regular':
454
  if site_var == 'Draftkings':
455
  dk_lineups = init_DK_lineups(slate_type_var3, slate_var3)
 
461
  elif site_var == 'Fanduel':
462
  fd_lineups = init_FD_lineups(slate_type_var3, slate_var3)
463
  with col2:
464
+ 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')
465
+ player_var1 = st.radio("Do you want a frame with specific Players?", ('Full Slate', 'Specific Players'), key='player_var1_radio')
466
  if player_var1 == 'Specific Players':
467
+ player_var2 = st.multiselect('Which players do you want?', options = raw_baselines['Player'].unique(), key='player_var2_multiselect')
468
  elif player_var1 == 'Full Slate':
469
  player_var2 = raw_baselines.Player.values.tolist()
470
  with col3:
471
  if site_var == 'Draftkings':
472
+ salary_min_var = st.number_input("Minimum salary used", min_value = 0, max_value = 50000, value = 49000, step = 100, key = 'salary_min_var_dk')
473
+ salary_max_var = st.number_input("Maximum salary used", min_value = 0, max_value = 50000, value = 50000, step = 100, key = 'salary_max_var_dk')
474
  elif site_var == 'Fanduel':
475
+ salary_min_var = st.number_input("Minimum salary used", min_value = 0, max_value = 60000, value = 59000, step = 100, key = 'salary_min_var_fd')
476
+ salary_max_var = st.number_input("Maximum salary used", min_value = 0, max_value = 60000, value = 60000, step = 100, key = 'salary_max_var_fd')
477
  with col4:
478
  if site_var == 'Draftkings':
479
+ min_stacks_var = st.number_input("Minimum stacks used", min_value = 0, max_value = 5, value = 1, step = 1, key = 'min_stacks_var_dk')
480
+ max_stacks_var = st.number_input("Maximum stacks used", min_value = 0, max_value = 5, value = 5, step = 1, key = 'max_stacks_var_dk')
481
  elif site_var == 'Fanduel':
482
+ min_stacks_var = st.number_input("Minimum stacks used", min_value = 0, max_value = 4, value = 1, step = 1, key = 'min_stacks_var_fd')
483
+ max_stacks_var = st.number_input("Maximum stacks used", min_value = 0, max_value = 4, value = 4, step = 1, key = 'max_stacks_var_fd')
484
 
485
 
486
  if site_var == 'Draftkings':
 
506
 
507
  reg_dl_col, filtered_dl_col, blank_dl_col = st.columns([2, 2, 6])
508
  with reg_dl_col:
509
+ if st.button("Prepare full data export", key='data_export_button'):
510
  name_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
511
  data_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
512
  if site_var == 'Draftkings':
 
534
  data=convert_df(data_export),
535
  file_name='NFL_optimals_export.csv',
536
  mime='text/csv',
537
+ key='export_optimals_ids_button'
538
  )
539
  st.download_button(
540
  label="Export optimals set (Names)",
541
  data=convert_df(name_export),
542
  file_name='NFL_optimals_export.csv',
543
  mime='text/csv',
544
+ key='export_optimals_names_button'
545
  )
546
  with pm_opt_col:
547
  if site_var == 'Draftkings':
 
559
  data=convert_pm_df(data_export),
560
  file_name='NFL_optimals_export.csv',
561
  mime='text/csv',
562
+ key='export_pm_ids_button'
563
  )
564
 
565
  if site_var == 'Draftkings':
 
577
  data=convert_pm_df(name_export),
578
  file_name='NFL_optimals_export.csv',
579
  mime='text/csv',
580
+ key='export_pm_names_button'
581
  )
582
  with filtered_dl_col:
583
+ if st.button("Prepare full data export (Filtered)", key='data_export_filtered_button'):
584
  name_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
585
  data_export = pd.DataFrame(st.session_state.working_seed.copy(), columns=column_names)
586
  if site_var == 'Draftkings':
 
614
  data=convert_df(data_export),
615
  file_name='NFL_optimals_export.csv',
616
  mime='text/csv',
617
+ key='export_filtered_optimals_ids_button'
618
  )
619
  st.download_button(
620
  label="Export optimals set (Names)",
621
  data=convert_df(name_export),
622
  file_name='NFL_optimals_export.csv',
623
  mime='text/csv',
624
+ key='export_filtered_optimals_names_button'
625
  )
626
  with pm_opt_col:
627
  if site_var == 'Draftkings':
 
639
  data=convert_pm_df(data_export),
640
  file_name='NFL_optimals_export.csv',
641
  mime='text/csv',
642
+ key='export_filtered_pm_ids_button'
643
  )
644
 
645
  if site_var == 'Draftkings':
 
657
  data=convert_pm_df(name_export),
658
  file_name='NFL_optimals_export.csv',
659
  mime='text/csv',
660
+ key='export_filtered_pm_names_button'
661
  )
662
 
663
  if site_var == 'Draftkings':
 
715
  export_file[col_idx] = export_file[col_idx].map(fd_id_map)
716
 
717
  with st.container():
718
+ if st.button("Reset Optimals", key='reset_optimals_button'):
719
  for key in st.session_state.keys():
720
  del st.session_state[key]
721
  if site_var == 'Draftkings':
 
723
  elif site_var == 'Fanduel':
724
  st.session_state.working_seed = fd_lineups.copy()
725
  if 'data_export_display' in st.session_state:
726
+ 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')
727
  st.download_button(
728
  label="Export display optimals (IDs)",
729
  data=convert_df(export_file),
730
  file_name='NFL_display_optimals.csv',
731
  mime='text/csv',
732
+ key='export_display_optimals_ids_button'
733
  )
734
  st.download_button(
735
  label="Export display optimals (Names)",
736
  data=convert_df(name_export),
737
  file_name='NFL_display_optimals.csv',
738
  mime='text/csv',
739
+ key='export_display_optimals_names_button'
740
  )
741
 
742
  with st.container():
 
844
  'Salary': '{:.2f}',
845
  'Proj': '{:.2f}',
846
  'Own': '{:.2f}'
847
+ }).background_gradient(cmap='RdYlGn', axis=0, subset=['Salary', 'Proj', 'Own']), use_container_width=True, key='optimal_stats_dataframe')
848
 
849
  with st.container():
850
  tab1, tab2 = st.tabs(["Display Frequency", "Seed Frame Frequency"])
 
882
 
883
  # Display the table
884
  st.write("Player Frequency Table:")
885
+ st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True, key='player_frequency_dataframe')
886
 
887
  st.download_button(
888
  label="Export player frequency",
889
  data=convert_df_to_csv(summary_df),
890
  file_name='NFL_player_frequency.csv',
891
  mime='text/csv',
892
+ key='export_player_frequency_button'
893
  )
894
  with tab2:
895
  if 'working_seed' in st.session_state:
 
924
 
925
  # Display the table
926
  st.write("Seed Frame Frequency Table:")
927
+ st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True, key='seed_frame_frequency_dataframe')
928
 
929
  st.download_button(
930
  label="Export seed frame frequency",
931
  data=convert_df_to_csv(summary_df),
932
  file_name='NFL_seed_frame_frequency.csv',
933
  mime='text/csv',
934
+ key='export_seed_frame_frequency_button'
935
  )
936
 
937
  with tab4:
 
939
  with col1:
940
  st.header("Handbuilder")
941
  with col2:
942
+ slate_var3 = st.selectbox("Slate Selection", options=['Main', 'Secondary', 'Auxiliary'], key='handbuilder_slate_selectbox')
943
  if site_var == 'Draftkings':
944
  if slate_var3 == 'Main':
945
  handbuild_roo = dk_roo_raw[dk_roo_raw['slate'] == 'Main Slate']
 
992
  slot_counts = lineup['Slot'].value_counts() if not lineup.empty else {}
993
 
994
  # --- PLAYER FILTERS ---
995
+ with st.expander("Player Filters", key='handbuilder_player_filters_expander'):
996
  col1, col2 = st.columns(2)
997
  with col1:
998
+ pos_select3 = st.multiselect("Select your position(s)", options=['QB', 'RB', 'WR', 'TE', 'UTIL', 'DST'], key='pos_select3_multiselect')
999
  with col2:
1000
+ salary_var = st.number_input("Salary Max", min_value = 0, max_value = 20000, value = 20000, step = 100, key='handbuilder_salary_max_input')
1001
 
1002
  # --- TEAM FILTER UI ---
1003
+ with st.expander("Team Filters", key='handbuilder_team_filters_expander'):
1004
  all_teams = sorted(handbuild_roo['Team'].unique())
1005
  st.markdown("**Toggle teams to include:**")
1006
  team_cols = st.columns(len(all_teams) // 2 + 1)
 
1010
  col = team_cols[idx % len(team_cols)]
1011
  if f"handbuilder_team_{team}" not in st.session_state:
1012
  st.session_state[f"handbuilder_team_{team}"] = False
1013
+ checked = col.toggle(team, value=st.session_state[f"handbuilder_team_{team}"], key=f"handbuilder_team_{team}_toggle")
1014
  if checked:
1015
  selected_teams.append(team)
1016
 
 
1032
  player_select_df = player_select_df[player_select_df['Salary'] <= salary_var]
1033
 
1034
 
1035
+ with st.expander("Quick Fill Options", key='handbuilder_quick_fill_expander'):
1036
+ auto_team_var = st.selectbox("Auto Fill Team", options=all_teams, key='auto_team_selectbox')
1037
+ auto_size_var = st.selectbox("Auto Fill Size", options=[3, 4, 5], key='auto_size_selectbox')
1038
+ auto_range_var = st.selectbox("Auto Fill Options", options=['QB/WR', 'RB/WR/TE', 'QB/WR/TE/RB'], key='auto_range_selectbox')
1039
  # --- QUICK FILL LOGIC ---
1040
+ if st.button("Quick Fill", key="quick_fill_button"):
1041
  # 1. Get all eligible players from the selected team, not already in the lineup
1042
  current_players = set(st.session_state['handbuilder_lineup']['Player'])
1043
  team_players = player_select_df[
 
1220
  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),
1221
  on_select="rerun",
1222
  selection_mode=["single-row"],
1223
+ key="lineup_remove_dataframe",
1224
  height=445,
1225
  hide_index=True
1226
  )
 
1299
  # Optionally, add a button to clear the lineup
1300
  clear_col, save_col, export_col, clear_saved_col, blank_col = st.columns([2, 2, 2, 2, 12])
1301
  with clear_col:
1302
+ if st.button("Clear Lineup", key='clear_lineup_button'):
1303
  st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', '2x%', 'Own', 'Slot'])
1304
  st.rerun()
1305
  with save_col:
1306
+ if st.button("Save Lineup", key='save_lineup_button'):
1307
  if 'saved_lineups' in st.session_state:
1308
  st.session_state['saved_lineups'].append(lineup_display_df['Player'].tolist())
1309
  print(st.session_state['saved_lineups'])
 
1320
  data=convert_hb_df(saved_lineups_array, dk_hb_columns if site_var == 'Draftkings' else fd_hb_columns),
1321
  file_name='handbuilds_export.csv',
1322
  mime='text/csv',
1323
+ key='export_handbuilds_button'
1324
  )
1325
  else:
1326
  st.write("No saved lineups to export")
 
1331
  st.write("No saved lineups")
1332
 
1333
  with clear_saved_col:
1334
+ if st.button("Clear Saved", key='clear_saved_button'):
1335
  if 'saved_lineups' in st.session_state:
1336
  del st.session_state['saved_lineups']
1337
  st.rerun()