James McCool commited on
Commit
5db8a23
·
1 Parent(s): d04558f

Refactor file upload functionality in `app.py` and `load_file.py`

Browse files

- Replaced portfolio file upload with contest file upload in `app.py`, streamlining the interface for users.
- Updated `load_file.py` to process contest files, extracting relevant player data and ownership information.
- Enhanced data handling by renaming columns and ensuring proper formatting for player positions and ownership percentages.

Files changed (2) hide show
  1. app.py +43 -398
  2. global_func/load_file.py +10 -8
app.py CHANGED
@@ -16,10 +16,6 @@ from global_func.highlight_rows import highlight_changes, highlight_changes_winn
16
  from global_func.load_csv import load_csv
17
  from global_func.find_csv_mismatches import find_csv_mismatches
18
 
19
- freq_format = {'Finish_percentile': '{:.2%}', 'Lineup Edge': '{:.2%}', 'Win%': '{:.2%}'}
20
- player_wrong_names_mlb = ['Enrique Hernandez']
21
- player_right_names_mlb = ['Kike Hernandez']
22
-
23
  tab1, tab2 = st.tabs(["Data Load", "Contest Analysis"])
24
  with tab1:
25
  if st.button('Clear data', key='reset1'):
@@ -58,51 +54,19 @@ with tab1:
58
  st.dataframe(st.session_state['csv_file'].head(10))
59
 
60
  with col2:
61
- st.subheader("Portfolio File")
62
- st.info("Go ahead and upload a portfolio file here. Only include player columns and an optional 'Stack' column if you are playing MLB.")
63
- saber_toggle = st.radio("Are you uploading from SaberSim?", options=['No', 'Yes'])
64
- st.info("If you are uploading from SaberSim, you will need to upload a CSV file for the slate for name matching.")
65
- if saber_toggle == 'Yes':
66
- if csv_file is not None:
67
- portfolio_file = st.file_uploader("Upload Portfolio File (CSV or Excel)", type=['csv', 'xlsx', 'xls'])
68
- if 'portfolio' in st.session_state:
69
- del st.session_state['portfolio']
70
- if 'export_portfolio' in st.session_state:
71
- del st.session_state['export_portfolio']
72
-
73
- else:
74
- portfolio_file = st.file_uploader("Upload Portfolio File (CSV or Excel)", type=['csv', 'xlsx', 'xls'])
75
- if 'portfolio' in st.session_state:
76
- del st.session_state['portfolio']
77
- if 'export_portfolio' in st.session_state:
78
- del st.session_state['export_portfolio']
79
-
80
- if portfolio_file:
81
- if saber_toggle == 'Yes':
82
- st.session_state['export_portfolio'], st.session_state['portfolio'] = load_ss_file(portfolio_file, st.session_state['csv_file'])
83
- st.session_state['export_portfolio'] = st.session_state['export_portfolio'].dropna(how='all')
84
- st.session_state['export_portfolio'] = st.session_state['export_portfolio'].reset_index(drop=True)
85
- st.session_state['portfolio'] = st.session_state['portfolio'].dropna(how='all')
86
- st.session_state['portfolio'] = st.session_state['portfolio'].reset_index(drop=True)
87
- else:
88
- st.session_state['export_portfolio'], st.session_state['portfolio'] = load_file(portfolio_file)
89
- st.session_state['export_portfolio'] = st.session_state['export_portfolio'].dropna(how='all')
90
- st.session_state['export_portfolio'] = st.session_state['export_portfolio'].reset_index(drop=True)
91
- st.session_state['portfolio'] = st.session_state['portfolio'].dropna(how='all')
92
- st.session_state['portfolio'] = st.session_state['portfolio'].reset_index(drop=True)
93
- # Check if Stack column exists in the portfolio
94
- if 'Stack' in st.session_state['portfolio'].columns:
95
- # Create dictionary mapping index to Stack values
96
- stack_dict = dict(zip(st.session_state['portfolio'].index, st.session_state['portfolio']['Stack']))
97
- st.write(f"Found {len(stack_dict)} stack assignments")
98
- st.session_state['portfolio'] = st.session_state['portfolio'].drop(columns=['Stack'])
99
- else:
100
- stack_dict = None
101
- st.info("No Stack column found in portfolio")
102
- if st.session_state['portfolio'] is not None:
103
- st.success('Portfolio file loaded successfully!')
104
- st.session_state['portfolio'] = st.session_state['portfolio'].apply(lambda x: x.replace(player_wrong_names_mlb, player_right_names_mlb))
105
- st.dataframe(st.session_state['portfolio'].head(10))
106
 
107
  with col3:
108
  st.subheader("Projections File")
@@ -131,361 +95,42 @@ with tab1:
131
  export_projections, projections = load_file(projections_file)
132
  if projections is not None:
133
  st.success('Projections file loaded successfully!')
134
- projections = projections.apply(lambda x: x.replace(player_wrong_names_mlb, player_right_names_mlb))
135
  st.dataframe(projections.head(10))
136
 
137
- if portfolio_file and projections_file:
138
- if st.session_state['portfolio'] is not None and projections is not None:
139
- st.subheader("Name Matching Analysis")
140
- # Initialize projections_df in session state if it doesn't exist
141
- if 'projections_df' not in st.session_state:
142
- st.session_state['projections_df'] = projections.copy()
143
- st.session_state['projections_df']['salary'] = (st.session_state['projections_df']['salary'].astype(str).str.replace(',', '').astype(float).astype(int))
144
 
145
- # Update projections_df with any new matches
146
- st.session_state['projections_df'] = find_name_mismatches(st.session_state['portfolio'], st.session_state['projections_df'])
147
- if csv_file is not None and 'export_dict' not in st.session_state:
148
- # Create a dictionary of Name to Name+ID from csv_file
149
- try:
150
- name_id_map = dict(zip(
151
- st.session_state['csv_file']['Name'],
152
- st.session_state['csv_file']['Name + ID']
153
- ))
154
- except:
155
- name_id_map = dict(zip(
156
- st.session_state['csv_file']['Nickname'],
157
- st.session_state['csv_file']['Id']
158
- ))
159
 
160
- # Function to find best match
161
- def find_best_match(name):
162
- best_match = process.extractOne(name, name_id_map.keys())
163
- if best_match and best_match[1] >= 85: # 85% match threshold
164
- return name_id_map[best_match[0]]
165
- return name # Return original name if no good match found
166
 
167
- # Apply the matching
168
- projections['upload_match'] = projections['player_names'].apply(find_best_match)
169
- st.session_state['export_dict'] = dict(zip(projections['player_names'], projections['upload_match']))
170
 
171
  with tab2:
172
  if st.button('Clear data', key='reset3'):
173
  st.session_state.clear()
174
- if 'portfolio' in st.session_state and 'projections_df' in st.session_state:
175
- col1, col2, col3 = st.columns([1, 8, 1])
176
- excluded_cols = ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Stack', 'Win%', 'Lineup Edge']
177
- with col1:
178
- site_var = st.selectbox("Select Site", ['Draftkings', 'Fanduel'])
179
- sport_var = st.selectbox("Select Sport", ['NFL', 'MLB', 'NBA', 'NHL', 'MMA'])
180
- st.info("It currently does not matter what sport you select, it may matter in the future.")
181
- type_var = st.selectbox("Select Game Type", ['Classic', 'Showdown'])
182
- Contest_Size = st.number_input("Enter Contest Size", value=25000, min_value=1, step=1)
183
- strength_var = st.selectbox("Select field strength", ['Average', 'Sharp', 'Weak'])
184
- if site_var == 'Draftkings':
185
- if type_var == 'Classic':
186
- map_dict = {
187
- 'pos_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['position'])),
188
- 'team_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['team'])),
189
- 'salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'])),
190
- 'proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'])),
191
- 'own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'])),
192
- 'own_percent_rank':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'].rank(pct=True))),
193
- 'cpt_salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'])),
194
- 'cpt_proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'] * 1.5)),
195
- 'cpt_own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['captain ownership']))
196
- }
197
- elif type_var == 'Showdown':
198
- if sport_var == 'NFL':
199
- map_dict = {
200
- 'pos_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['position'])),
201
- 'team_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['team'])),
202
- 'salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'])),
203
- 'proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'])),
204
- 'own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'])),
205
- 'own_percent_rank':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'].rank(pct=True))),
206
- 'cpt_salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'] * 1.5)),
207
- 'cpt_proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'] * 1.5)),
208
- 'cpt_own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['captain ownership']))
209
- }
210
- elif sport_var != 'NFL':
211
- map_dict = {
212
- 'pos_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['position'])),
213
- 'team_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['team'])),
214
- 'salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'] / 1.5)),
215
- 'proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'])),
216
- 'own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'])),
217
- 'own_percent_rank':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'].rank(pct=True))),
218
- 'cpt_salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'])),
219
- 'cpt_proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'] * 1.5)),
220
- 'cpt_own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['captain ownership']))
221
- }
222
- elif site_var == 'Fanduel':
223
- map_dict = {
224
- 'pos_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['position'])),
225
- 'team_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['team'])),
226
- 'salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'])),
227
- 'proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'])),
228
- 'own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'])),
229
- 'own_percent_rank':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['ownership'].rank(pct=True))),
230
- 'cpt_salary_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['salary'])),
231
- 'cpt_proj_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['median'] * 1.5)),
232
- 'cpt_own_map':dict(zip(st.session_state['projections_df']['player_names'], st.session_state['projections_df']['captain ownership']))
233
- }
234
-
235
- if type_var == 'Classic':
236
- st.session_state['portfolio']['salary'] = st.session_state['portfolio'].apply(lambda row: sum(map_dict['salary_map'].get(player, 0) for player in row), axis=1)
237
- st.session_state['portfolio']['median'] = st.session_state['portfolio'].apply(lambda row: sum(map_dict['proj_map'].get(player, 0) for player in row), axis=1)
238
- st.session_state['portfolio']['Own'] = st.session_state['portfolio'].apply(lambda row: sum(map_dict['own_map'].get(player, 0) for player in row), axis=1)
239
- if stack_dict is not None:
240
- st.session_state['portfolio']['Stack'] = st.session_state['portfolio'].index.map(stack_dict)
241
- elif type_var == 'Showdown':
242
- # Calculate salary (CPT uses cpt_salary_map, others use salary_map)
243
- st.session_state['portfolio']['salary'] = st.session_state['portfolio'].apply(
244
- lambda row: map_dict['cpt_salary_map'].get(row.iloc[0], 0) +
245
- sum(map_dict['salary_map'].get(player, 0) for player in row.iloc[1:]),
246
- axis=1
247
- )
248
-
249
- # Calculate median (CPT uses cpt_proj_map, others use proj_map)
250
- st.session_state['portfolio']['median'] = st.session_state['portfolio'].apply(
251
- lambda row: map_dict['cpt_proj_map'].get(row.iloc[0], 0) +
252
- sum(map_dict['proj_map'].get(player, 0) for player in row.iloc[1:]),
253
- axis=1
254
- )
255
-
256
- # Calculate ownership (CPT uses cpt_own_map, others use own_map)
257
- st.session_state['portfolio']['Own'] = st.session_state['portfolio'].apply(
258
- lambda row: map_dict['cpt_own_map'].get(row.iloc[0], 0) +
259
- sum(map_dict['own_map'].get(player, 0) for player in row.iloc[1:]),
260
- axis=1
261
- )
262
- with col3:
263
- with st.form(key='filter_form'):
264
- max_dupes = st.number_input("Max acceptable dupes?", value=1000, min_value=1, step=1)
265
- min_salary = st.number_input("Min acceptable salary?", value=1000, min_value=1000, step=100)
266
- max_salary = st.number_input("Max acceptable salary?", value=60000, min_value=1000, step=100)
267
- max_finish_percentile = st.number_input("Max acceptable finish percentile?", value=.50, min_value=0.005, step=.001)
268
- player_names = set()
269
- for col in st.session_state['portfolio'].columns:
270
- if col not in excluded_cols:
271
- player_names.update(st.session_state['portfolio'][col].unique())
272
- player_lock = st.multiselect("Lock players?", options=sorted(list(player_names)), default=[])
273
- player_remove = st.multiselect("Remove players?", options=sorted(list(player_names)), default=[])
274
- if stack_dict is not None:
275
- stack_toggle = st.selectbox("Include specific stacks?", options=['All Stacks', 'Specific Stacks'], index=0)
276
- stack_selections = st.multiselect("If Specific Stacks, Which to include?", options=sorted(list(set(stack_dict.values()))), default=[])
277
- stack_remove = st.multiselect("If Specific Stacks, Which to remove?", options=sorted(list(set(stack_dict.values()))), default=[])
278
-
279
- submitted = st.form_submit_button("Submit")
280
-
281
- with col2:
282
- st.session_state['portfolio'] = predict_dupes(st.session_state['portfolio'], map_dict, site_var, type_var, Contest_Size, strength_var)
283
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Dupes'] <= max_dupes]
284
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['salary'] >= min_salary]
285
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['salary'] <= max_salary]
286
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Finish_percentile'] <= max_finish_percentile]
287
- if stack_dict is not None:
288
- if stack_toggle == 'All Stacks':
289
- st.session_state['portfolio'] = st.session_state['portfolio']
290
- st.session_state['portfolio'] = st.session_state['portfolio'][~st.session_state['portfolio']['Stack'].isin(stack_remove)]
291
- else:
292
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Stack'].isin(stack_selections)]
293
- st.session_state['portfolio'] = st.session_state['portfolio'][~st.session_state['portfolio']['Stack'].isin(stack_remove)]
294
- if player_remove:
295
- # Create mask for lineups that contain any of the removed players
296
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
297
- remove_mask = st.session_state['portfolio'][player_columns].apply(
298
- lambda row: not any(player in list(row) for player in player_remove), axis=1
299
- )
300
- st.session_state['portfolio'] = st.session_state['portfolio'][remove_mask]
301
-
302
- if player_lock:
303
- # Create mask for lineups that contain all locked players
304
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
305
-
306
- lock_mask = st.session_state['portfolio'][player_columns].apply(
307
- lambda row: all(player in list(row) for player in player_lock), axis=1
308
- )
309
- st.session_state['portfolio'] = st.session_state['portfolio'][lock_mask]
310
- export_file = st.session_state['portfolio'].copy()
311
- st.session_state['portfolio'] = st.session_state['portfolio'].sort_values(by='median', ascending=False)
312
- if csv_file is not None:
313
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
314
- for col in player_columns:
315
- export_file[col] = export_file[col].map(st.session_state['export_dict'])
316
- with st.expander("Download options"):
317
- if stack_dict is not None:
318
- with st.form(key='stack_form'):
319
- st.subheader("Stack Count Adjustments")
320
- st.info("This allows you to fine tune the stacks that you wish to export. If you want to make sure you don't export any of a specific stack you can 0 it out.")
321
- # Create a container for stack value inputs
322
- sort_container = st.container()
323
- with sort_container:
324
- sort_var = st.selectbox("Sort export portfolio by:", options=['median', 'Lineup Edge', 'Own'])
325
-
326
- # Get unique stack values
327
- unique_stacks = sorted(list(set(stack_dict.values())))
328
-
329
- # Create a dictionary to store stack multipliers
330
- if 'stack_multipliers' not in st.session_state:
331
- st.session_state.stack_multipliers = {stack: 0.0 for stack in unique_stacks}
332
-
333
- # Create columns for the stack inputs
334
- num_cols = 6 # Number of columns to display
335
- for i in range(0, len(unique_stacks), num_cols):
336
- cols = st.columns(num_cols)
337
- for j, stack in enumerate(unique_stacks[i:i+num_cols]):
338
- with cols[j]:
339
- # Create a unique key for each number input
340
- key = f"stack_count_{stack}"
341
- # Get the current count of this stack in the portfolio
342
- current_stack_count = len(st.session_state['portfolio'][st.session_state['portfolio']['Stack'] == stack])
343
- # Create number input with current value and max value based on actual count
344
- st.session_state.stack_multipliers[stack] = st.number_input(
345
- f"{stack} count",
346
- min_value=0.0,
347
- max_value=float(current_stack_count),
348
- value=float(current_stack_count),
349
- step=1.0,
350
- key=key
351
- )
352
-
353
- # Create a copy of the portfolio
354
- portfolio_copy = st.session_state['portfolio'].copy()
355
-
356
- # Create a list to store selected rows
357
- selected_rows = []
358
-
359
- # For each stack, select the top N rows based on the count value
360
- for stack in unique_stacks:
361
- if stack in st.session_state.stack_multipliers:
362
- count = int(st.session_state.stack_multipliers[stack])
363
- # Get rows for this stack
364
- stack_rows = portfolio_copy[portfolio_copy['Stack'] == stack]
365
- # Sort by median and take top N rows
366
- top_rows = stack_rows.nlargest(count, sort_var)
367
- selected_rows.append(top_rows)
368
-
369
- # Combine all selected rows
370
- portfolio_copy = pd.concat(selected_rows)
371
-
372
- # Update export_file with filtered data
373
- export_file = portfolio_copy.copy()
374
-
375
- submitted = st.form_submit_button("Submit")
376
- if submitted:
377
- st.write('Export portfolio updated!')
378
-
379
- st.download_button(label="Download Portfolio", data=export_file.to_csv(index=False), file_name="portfolio.csv", mime="text/csv")
380
- # Display the paginated dataframe first
381
- st.dataframe(
382
- st.session_state['portfolio'].style
383
- .background_gradient(axis=0)
384
- .background_gradient(cmap='RdYlGn')
385
- .background_gradient(cmap='RdYlGn_r', subset=['Finish_percentile', 'Own', 'Dupes'])
386
- .format(freq_format, precision=2),
387
- height=1000,
388
- use_container_width=True
389
- )
390
-
391
- # Add pagination controls below the dataframe
392
- total_rows = len(st.session_state['portfolio'])
393
- rows_per_page = 500
394
- total_pages = (total_rows + rows_per_page - 1) // rows_per_page # Ceiling division
395
-
396
- # Initialize page number in session state if not exists
397
- if 'current_page' not in st.session_state:
398
- st.session_state.current_page = 1
399
-
400
- # Display current page range info and pagination control in a single line
401
- st.write(
402
- f"Showing rows {(st.session_state.current_page - 1) * rows_per_page + 1} "
403
- f"to {min(st.session_state.current_page * rows_per_page, total_rows)} of {total_rows}"
404
- )
405
-
406
- # Add page number input
407
- st.session_state.current_page = st.number_input(
408
- f"Page (1-{total_pages})",
409
- min_value=1,
410
- max_value=total_pages,
411
- value=st.session_state.current_page
412
- )
413
-
414
- # Calculate start and end indices for current page
415
- start_idx = (st.session_state.current_page - 1) * rows_per_page
416
- end_idx = min(start_idx + rows_per_page, total_rows)
417
-
418
- # Get the subset of data for the current page
419
- current_page_data = st.session_state['portfolio'].iloc[start_idx:end_idx]
420
-
421
- # Create player summary dataframe
422
- player_stats = []
423
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
424
-
425
- if type_var == 'Showdown':
426
- # Handle Captain positions
427
- for player in player_names:
428
- # Create mask for lineups where this player is Captain (first column)
429
- cpt_mask = st.session_state['portfolio'][player_columns[0]] == player
430
-
431
- if cpt_mask.any():
432
- player_stats.append({
433
- 'Player': f"{player} (CPT)",
434
- 'Lineup Count': cpt_mask.sum(),
435
- 'Avg Median': st.session_state['portfolio'][cpt_mask]['median'].mean(),
436
- 'Avg Own': st.session_state['portfolio'][cpt_mask]['Own'].mean(),
437
- 'Avg Dupes': st.session_state['portfolio'][cpt_mask]['Dupes'].mean(),
438
- 'Avg Finish %': st.session_state['portfolio'][cpt_mask]['Finish_percentile'].mean(),
439
- 'Avg Lineup Edge': st.session_state['portfolio'][cpt_mask]['Lineup Edge'].mean(),
440
- })
441
-
442
- # Create mask for lineups where this player is FLEX (other columns)
443
- flex_mask = st.session_state['portfolio'][player_columns[1:]].apply(
444
- lambda row: player in list(row), axis=1
445
- )
446
-
447
- if flex_mask.any():
448
- player_stats.append({
449
- 'Player': f"{player} (FLEX)",
450
- 'Lineup Count': flex_mask.sum(),
451
- 'Avg Median': st.session_state['portfolio'][flex_mask]['median'].mean(),
452
- 'Avg Own': st.session_state['portfolio'][flex_mask]['Own'].mean(),
453
- 'Avg Dupes': st.session_state['portfolio'][flex_mask]['Dupes'].mean(),
454
- 'Avg Finish %': st.session_state['portfolio'][flex_mask]['Finish_percentile'].mean(),
455
- 'Avg Lineup Edge': st.session_state['portfolio'][flex_mask]['Lineup Edge'].mean(),
456
- })
457
- else:
458
- # Original Classic format processing
459
- for player in player_names:
460
- player_mask = st.session_state['portfolio'][player_columns].apply(
461
- lambda row: player in list(row), axis=1
462
- )
463
-
464
- if player_mask.any():
465
- player_stats.append({
466
- 'Player': player,
467
- 'Lineup Count': player_mask.sum(),
468
- 'Avg Median': st.session_state['portfolio'][player_mask]['median'].mean(),
469
- 'Avg Own': st.session_state['portfolio'][player_mask]['Own'].mean(),
470
- 'Avg Dupes': st.session_state['portfolio'][player_mask]['Dupes'].mean(),
471
- 'Avg Finish %': st.session_state['portfolio'][player_mask]['Finish_percentile'].mean(),
472
- 'Avg Lineup Edge': st.session_state['portfolio'][player_mask]['Lineup Edge'].mean(),
473
- })
474
-
475
- player_summary = pd.DataFrame(player_stats)
476
- player_summary = player_summary.sort_values('Lineup Count', ascending=False)
477
-
478
- st.subheader("Player Summary")
479
- st.dataframe(
480
- player_summary.style
481
- .background_gradient(axis=0).background_gradient(cmap='RdYlGn').background_gradient(cmap='RdYlGn_r', subset=['Avg Finish %', 'Avg Own', 'Avg Dupes'])
482
- .format({
483
- 'Avg Median': '{:.2f}',
484
- 'Avg Own': '{:.2f}',
485
- 'Avg Dupes': '{:.2f}',
486
- 'Avg Finish %': '{:.2%}',
487
- 'Avg Lineup Edge': '{:.2%}'
488
- }),
489
- height=400,
490
- use_container_width=True
491
- )
 
16
  from global_func.load_csv import load_csv
17
  from global_func.find_csv_mismatches import find_csv_mismatches
18
 
 
 
 
 
19
  tab1, tab2 = st.tabs(["Data Load", "Contest Analysis"])
20
  with tab1:
21
  if st.button('Clear data', key='reset1'):
 
54
  st.dataframe(st.session_state['csv_file'].head(10))
55
 
56
  with col2:
57
+ st.subheader("Contest File")
58
+ st.info("Go ahead and upload a Contest file here. Only include player columns and an optional 'Stack' column if you are playing MLB.")
59
+ Contest_file = st.file_uploader("Upload Contest File (CSV or Excel)", type=['csv', 'xlsx', 'xls'])
60
+ if 'Contest' in st.session_state:
61
+ del st.session_state['Contest']
62
+
63
+ if Contest_file:
64
+ st.session_state['Contest'], st.session_state['position_dict'], st.session_state['ownership_dict'] = load_file(Contest_file)
65
+ st.session_state['Contest'] = st.session_state['Contest'].dropna(how='all')
66
+ st.session_state['Contest'] = st.session_state['Contest'].reset_index(drop=True)
67
+ if st.session_state['Contest'] is not None:
68
+ st.success('Contest file loaded successfully!')
69
+ st.dataframe(st.session_state['Contest'].head(10))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  with col3:
72
  st.subheader("Projections File")
 
95
  export_projections, projections = load_file(projections_file)
96
  if projections is not None:
97
  st.success('Projections file loaded successfully!')
 
98
  st.dataframe(projections.head(10))
99
 
100
+ # if Contest_file and projections_file:
101
+ # if st.session_state['Contest'] is not None and projections is not None:
102
+ # st.subheader("Name Matching Analysis")
103
+ # # Initialize projections_df in session state if it doesn't exist
104
+ # if 'projections_df' not in st.session_state:
105
+ # st.session_state['projections_df'] = projections.copy()
106
+ # st.session_state['projections_df']['salary'] = (st.session_state['projections_df']['salary'].astype(str).str.replace(',', '').astype(float).astype(int))
107
 
108
+ # # Update projections_df with any new matches
109
+ # st.session_state['projections_df'] = find_name_mismatches(st.session_state['Contest'], st.session_state['projections_df'])
110
+ # if csv_file is not None and 'export_dict' not in st.session_state:
111
+ # # Create a dictionary of Name to Name+ID from csv_file
112
+ # try:
113
+ # name_id_map = dict(zip(
114
+ # st.session_state['csv_file']['Name'],
115
+ # st.session_state['csv_file']['Name + ID']
116
+ # ))
117
+ # except:
118
+ # name_id_map = dict(zip(
119
+ # st.session_state['csv_file']['Nickname'],
120
+ # st.session_state['csv_file']['Id']
121
+ # ))
122
 
123
+ # # Function to find best match
124
+ # def find_best_match(name):
125
+ # best_match = process.extractOne(name, name_id_map.keys())
126
+ # if best_match and best_match[1] >= 85: # 85% match threshold
127
+ # return name_id_map[best_match[0]]
128
+ # return name # Return original name if no good match found
129
 
130
+ # # Apply the matching
131
+ # projections['upload_match'] = projections['player_names'].apply(find_best_match)
132
+ # st.session_state['export_dict'] = dict(zip(projections['player_names'], projections['upload_match']))
133
 
134
  with tab2:
135
  if st.button('Clear data', key='reset3'):
136
  st.session_state.clear()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
global_func/load_file.py CHANGED
@@ -8,23 +8,25 @@ from fuzzywuzzy import process
8
  from global_func.clean_player_name import clean_player_name
9
 
10
  def load_file(upload):
 
11
  if upload is not None:
12
  try:
13
  if upload.name.endswith('.csv'):
14
- df = pd.read_csv(upload)
15
  elif upload.name.endswith(('.xls', '.xlsx')):
16
- df = pd.read_excel(upload)
17
  else:
18
  st.error('Please upload either a CSV or Excel file')
19
  return None
20
 
21
- export_df = df.copy()
 
 
 
 
 
22
 
23
- for col in df.columns:
24
- if df[col].dtype == 'object':
25
- df[col] = df[col].apply(lambda x: clean_player_name(x) if isinstance(x, str) else x)
26
-
27
- return export_df, df
28
  except Exception as e:
29
  st.error(f'Error loading file: {str(e)}')
30
  return None
 
8
  from global_func.clean_player_name import clean_player_name
9
 
10
  def load_file(upload):
11
+ pos_values = ['P', 'C', '1B', '2B', '3B', 'SS', 'OF']
12
  if upload is not None:
13
  try:
14
  if upload.name.endswith('.csv'):
15
+ raw_df = pd.read_csv(upload)
16
  elif upload.name.endswith(('.xls', '.xlsx')):
17
+ raw_df = pd.read_excel(upload)
18
  else:
19
  st.error('Please upload either a CSV or Excel file')
20
  return None
21
 
22
+ df = raw_df[['EntryId', 'EntryName', 'TimeRemaining', 'Points', 'Lineup', 'Player', 'Roster Position', '%Drafted', 'FPTS']]
23
+ df = df.rename(columns={'Roster Position': 'Pos', '%Drafted': 'Own'})
24
+ df['Lineup'] = df['Lineup'].replace(pos_values, ',')
25
+ df['Lineup'] = df['Lineup'].str.split(',')
26
+ position_dict = dict(zip(df['Player'], df['Pos']))
27
+ ownership_dict = dict(zip(df['Player'], df['Own']))
28
 
29
+ return df, position_dict, ownership_dict
 
 
 
 
30
  except Exception as e:
31
  st.error(f'Error loading file: {str(e)}')
32
  return None