James McCool commited on
Commit
e32d65b
·
1 Parent(s): 4f82cd3

Refactor player selection logic in Handbuilder tab of app.py to improve eligibility checks based on position limits. Update the DataFrame to include a 'Slot' column for better lineup management and ensure players are only added to available positions, enhancing user experience and data integrity.

Browse files
Files changed (1) hide show
  1. app.py +49 -32
app.py CHANGED
@@ -3,6 +3,7 @@ import numpy as np
3
  import pandas as pd
4
  import gspread
5
  import pymongo
 
6
 
7
  st.set_page_config(layout="wide")
8
 
@@ -802,28 +803,27 @@ with tab3:
802
  with tab4:
803
  st.header("Handbuilder")
804
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  # --- LINEUP STATE ---
806
  if 'handbuilder_lineup' not in st.session_state:
807
  st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', 'Own%'])
808
  if 'handbuilder_select_key' not in st.session_state:
809
  st.session_state['handbuilder_select_key'] = 0
810
 
811
- # --- POSITION LIMITS ---
812
- position_limits = {
813
- 'SP': 2,
814
- # Add other positions and their limits as needed
815
- # e.g. 'C': 1, '1B': 1, '2B': 1, '3B': 1, 'SS': 1, 'OF': 3
816
- }
817
-
818
  # Count positions in the current lineup
819
  lineup = st.session_state['handbuilder_lineup']
820
- position_counts = lineup['Position'].value_counts() if not lineup.empty else {}
821
-
822
- # Build a set of positions that have reached their max
823
- positions_at_max = set()
824
- for pos, max_count in position_limits.items():
825
- if position_counts.get(pos, 0) >= max_count:
826
- positions_at_max.add(pos)
827
 
828
  # --- TEAM FILTER UI ---
829
  all_teams = sorted(dk_roo['Team'].unique())
@@ -847,9 +847,16 @@ with tab4:
847
  else:
848
  player_select_df = dk_roo[['Player', 'Position', 'Team', 'Salary', 'Median', 'Order', 'Hand', 'Own%']].drop_duplicates(subset=['Player', 'Team']).copy()
849
 
850
- # Remove players whose position is at max
851
- if positions_at_max:
852
- player_select_df = player_select_df[~player_select_df['Position'].isin(positions_at_max)]
 
 
 
 
 
 
 
853
 
854
  col1, col2 = st.columns([1, 2])
855
  with col2:
@@ -866,23 +873,32 @@ with tab4:
866
  # If a row is selected, add that player to the lineup and reset selection
867
  if event and "rows" in event.selection and len(event.selection["rows"]) > 0:
868
  idx = event.selection["rows"][0]
869
- player_row = player_select_df.iloc[[idx]][['Player', 'Position', 'Team', 'Salary', 'Median', 'Own%']]
870
- # Avoid duplicates
871
- if not player_row['Player'].iloc[0] in st.session_state['handbuilder_lineup']['Player'].values:
872
- st.session_state['handbuilder_lineup'] = pd.concat(
873
- [st.session_state['handbuilder_lineup'], player_row],
874
- ignore_index=True
875
- )
876
- # Change the key to reset the selection
877
- st.session_state['handbuilder_select_key'] += 1
878
- st.rerun()
 
 
 
 
 
 
 
 
 
879
 
880
  with col1:
881
  st.subheader("Lineup")
882
  st.dataframe(
883
- st.session_state['handbuilder_lineup'],
884
  use_container_width=True,
885
- height=500,
886
  hide_index=True
887
  )
888
 
@@ -896,13 +912,14 @@ with tab4:
896
 
897
  summary_row = pd.DataFrame({
898
  'Player': ['TOTAL'],
899
- 'Position': ['ALL'],
 
900
  'Team': [most_common_team],
901
  'Salary': [total_salary],
902
  'Median': [total_median],
903
  'Own%': [total_own]
904
  })
905
- summary_row = summary_row[lineup.columns]
906
 
907
  st.dataframe(
908
  summary_row,
@@ -913,5 +930,5 @@ with tab4:
913
 
914
  # Optionally, add a button to clear the lineup
915
  if st.button("Clear Lineup", key='clear_lineup'):
916
- st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Team', 'Salary', 'Median', 'Own%'])
917
  st.rerun()
 
3
  import pandas as pd
4
  import gspread
5
  import pymongo
6
+ import re
7
 
8
  st.set_page_config(layout="wide")
9
 
 
803
  with tab4:
804
  st.header("Handbuilder")
805
 
806
+ # --- POSITION LIMITS ---
807
+ position_limits = {
808
+ 'SP': 2,
809
+ 'C': 1,
810
+ '1B': 1,
811
+ '2B': 1,
812
+ '3B': 1,
813
+ 'SS': 1,
814
+ 'OF': 3,
815
+ # Add more as needed
816
+ }
817
+
818
  # --- LINEUP STATE ---
819
  if 'handbuilder_lineup' not in st.session_state:
820
  st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', 'Own%'])
821
  if 'handbuilder_select_key' not in st.session_state:
822
  st.session_state['handbuilder_select_key'] = 0
823
 
 
 
 
 
 
 
 
824
  # Count positions in the current lineup
825
  lineup = st.session_state['handbuilder_lineup']
826
+ slot_counts = lineup['Slot'].value_counts() if not lineup.empty else {}
 
 
 
 
 
 
827
 
828
  # --- TEAM FILTER UI ---
829
  all_teams = sorted(dk_roo['Team'].unique())
 
847
  else:
848
  player_select_df = dk_roo[['Player', 'Position', 'Team', 'Salary', 'Median', 'Order', 'Hand', 'Own%']].drop_duplicates(subset=['Player', 'Team']).copy()
849
 
850
+ # --- FILTER OUT PLAYERS WHOSE ALL ELIGIBLE POSITIONS ARE FILLED ---
851
+ def is_player_eligible(row):
852
+ eligible_positions = re.split(r'[/, ]+', row['Position'])
853
+ # Player is eligible if at least one of their positions is not at max
854
+ for pos in eligible_positions:
855
+ if slot_counts.get(pos, 0) < position_limits.get(pos, 0):
856
+ return True
857
+ return False
858
+
859
+ player_select_df = player_select_df[player_select_df.apply(is_player_eligible, axis=1)]
860
 
861
  col1, col2 = st.columns([1, 2])
862
  with col2:
 
873
  # If a row is selected, add that player to the lineup and reset selection
874
  if event and "rows" in event.selection and len(event.selection["rows"]) > 0:
875
  idx = event.selection["rows"][0]
876
+ player_row = player_select_df.iloc[[idx]]
877
+ eligible_positions = re.split(r'[/, ]+', player_row['Position'].iloc[0])
878
+ # Find the first eligible slot that is not full
879
+ slot_to_fill = None
880
+ for pos in eligible_positions:
881
+ if slot_counts.get(pos, 0) < position_limits.get(pos, 0):
882
+ slot_to_fill = pos
883
+ break
884
+ if slot_to_fill is not None:
885
+ # Avoid duplicates
886
+ if not player_row['Player'].iloc[0] in st.session_state['handbuilder_lineup']['Player'].values:
887
+ # Add the slot info
888
+ player_row = player_row.assign(Slot=slot_to_fill)
889
+ st.session_state['handbuilder_lineup'] = pd.concat(
890
+ [st.session_state['handbuilder_lineup'], player_row[['Player', 'Position', 'Team', 'Salary', 'Median', 'Own%', 'Slot']]],
891
+ ignore_index=True
892
+ )
893
+ st.session_state['handbuilder_select_key'] += 1
894
+ st.rerun()
895
 
896
  with col1:
897
  st.subheader("Lineup")
898
  st.dataframe(
899
+ st.session_state['handbuilder_lineup'][['Player', 'Slot', 'Position', 'Team', 'Salary', 'Median', 'Own%']],
900
  use_container_width=True,
901
+ height=450,
902
  hide_index=True
903
  )
904
 
 
912
 
913
  summary_row = pd.DataFrame({
914
  'Player': ['TOTAL'],
915
+ 'Slot': [''],
916
+ 'Position': [''],
917
  'Team': [most_common_team],
918
  'Salary': [total_salary],
919
  'Median': [total_median],
920
  'Own%': [total_own]
921
  })
922
+ summary_row = summary_row[lineup[['Player', 'Slot', 'Position', 'Team', 'Salary', 'Median', 'Own%']].columns]
923
 
924
  st.dataframe(
925
  summary_row,
 
930
 
931
  # Optionally, add a button to clear the lineup
932
  if st.button("Clear Lineup", key='clear_lineup'):
933
+ st.session_state['handbuilder_lineup'] = pd.DataFrame(columns=['Player', 'Position', 'Team', 'Salary', 'Median', 'Own%', 'Slot'])
934
  st.rerun()