Multichem commited on
Commit
69b5aee
·
1 Parent(s): 0ec1a3b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +670 -0
app.py ADDED
@@ -0,0 +1,670 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pulp
2
+ import numpy as np
3
+ import pandas as pd
4
+ import streamlit as st
5
+ import gspread
6
+ from itertools import combinations
7
+ import time
8
+
9
+ @st.cache_resource
10
+ def init_conn():
11
+ scope = ['https://www.googleapis.com/auth/spreadsheets',
12
+ "https://www.googleapis.com/auth/drive"]
13
+
14
+ credentials = {
15
+ "type": "service_account",
16
+ "project_id": "sheets-api-connect-378620",
17
+ "private_key_id": "1005124050c80d085e2c5b344345715978dd9cc9",
18
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtKa01beXwc88R\nnPZVQTNPVQuBnbwoOfc66gW3547ja/UEyIGAF112dt/VqHprRafkKGmlg55jqJNt\na4zceLKV+wTm7vBu7lDISTJfGzCf2TrxQYNqwMKE2LOjI69dBM8u4Dcb4k0wcp9v\ntW1ZzLVVuwTvmrg7JBHjiSaB+x5wxm/r3FOiJDXdlAgFlytzqgcyeZMJVKKBQHyJ\njEGg/1720A0numuOCt71w/2G0bDmijuj1e6tH32MwRWcvRNZ19K9ssyDz2S9p68s\nYDhIxX69OWxwScTIHLY6J2t8txf/XMivL/636fPlDADvBEVTdlT606n8CcKUVQeq\npUVdG+lfAgMBAAECggEAP38SUA7B69eTfRpo658ycOs3Amr0JW4H/bb1rNeAul0K\nZhwd/HnU4E07y81xQmey5kN5ZeNrD5EvqkZvSyMJHV0EEahZStwhjCfnDB/cxyix\nZ+kFhv4y9eK+kFpUAhBy5nX6T0O+2T6WvzAwbmbVsZ+X8kJyPuF9m8ldcPlD0sce\ntj8NwVq1ys52eosqs7zi2vjt+eMcaY393l4ls+vNq8Yf27cfyFw45W45CH/97/Nu\n5AmuzlCOAfFF+z4OC5g4rei4E/Qgpxa7/uom+BVfv9G0DIGW/tU6Sne0+37uoGKt\nW6DzhgtebUtoYkG7ZJ05BTXGp2lwgVcNRoPwnKJDxQKBgQDT5wYPUBDW+FHbvZSp\nd1m1UQuXyerqOTA9smFaM8sr/UraeH85DJPEIEk8qsntMBVMhvD3Pw8uIUeFNMYj\naLmZFObsL+WctepXrVo5NB6RtLB/jZYxiKMatMLUJIYtcKIp+2z/YtKiWcLnwotB\nWdCjVnPTxpkurmF2fWP/eewZ+wKBgQDRMtJg7etjvKyjYNQ5fARnCc+XsI3gkBe1\nX9oeXfhyfZFeBXWnZzN1ITgFHplDznmBdxAyYGiQdbbkdKQSghviUQ0igBvoDMYy\n1rWcy+a17Mj98uyNEfmb3X2cC6WpvOZaGHwg9+GY67BThwI3FqHIbyk6Ko09WlTX\nQpRQjMzU7QKBgAfi1iflu+q0LR+3a3vvFCiaToskmZiD7latd9AKk2ocsBd3Woy9\n+hXXecJHPOKV4oUJlJgvAZqe5HGBqEoTEK0wyPNLSQlO/9ypd+0fEnArwFHO7CMF\nycQprAKHJXM1eOOFFuZeQCaInqdPZy1UcV5Szla4UmUZWkk1m24blHzXAoGBAMcA\nyH4qdbxX9AYrC1dvsSRvgcnzytMvX05LU0uF6tzGtG0zVlub4ahvpEHCfNuy44UT\nxRWW/oFFaWjjyFxO5sWggpUqNuHEnRopg3QXx22SRRTGbN45li/+QAocTkgsiRh1\nqEcYZsO4mPCsQqAy6E2p6RcK+Xa+omxvSnVhq0x1AoGAKr8GdkCl4CF6rieLMAQ7\nLNBuuoYGaHoh8l5E2uOQpzwxVy/nMBcAv+2+KqHEzHryUv1owOi6pMLv7A9mTFoS\n18B0QRLuz5fSOsVnmldfC9fpUc6H8cH1SINZpzajqQA74bPwELJjnzrCnH79TnHG\nJuElxA33rFEjbgbzdyrE768=\n-----END PRIVATE KEY-----\n",
19
+ "client_email": "gspread-connection@sheets-api-connect-378620.iam.gserviceaccount.com",
20
+ "client_id": "106625872877651920064",
21
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
22
+ "token_uri": "https://oauth2.googleapis.com/token",
23
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
24
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/gspread-connection%40sheets-api-connect-378620.iam.gserviceaccount.com"
25
+ }
26
+
27
+ gc = gspread.service_account_from_dict(credentials)
28
+ return gc
29
+
30
+ st.set_page_config(layout="wide")
31
+
32
+ gc = init_conn()
33
+
34
+ game_format = {'Win Percentage': '{:.2%}','First Inning Lead Percentage': '{:.2%}',
35
+ 'Fifth Inning Lead Percentage': '{:.2%}', '8+ runs': '{:.2%}', 'DK LevX': '{:.2%}', 'FD LevX': '{:.2%}'}
36
+
37
+ team_roo_format = {'Top Score%': '{:.2%}','0 Runs': '{:.2%}', '1 Run': '{:.2%}', '2 Runs': '{:.2%}', '3 Runs': '{:.2%}', '4 Runs': '{:.2%}',
38
+ '5 Runs': '{:.2%}','6 Runs': '{:.2%}', '7 Runs': '{:.2%}', '8 Runs': '{:.2%}', '9 Runs': '{:.2%}', '10 Runs': '{:.2%}'}
39
+
40
+ player_roo_format = {'Top_finish': '{:.2%}','Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '2x%': '{:.2%}', '3x%': '{:.2%}',
41
+ '4x%': '{:.2%}','GPP%': '{:.2%}'}
42
+
43
+ expose_format = {'Proj Own': '{:.2%}','Exposure': '{:.2%}'}
44
+
45
+ all_dk_player_projections = 'https://docs.google.com/spreadsheets/d/1Yq0vGriWK-bS79e-bD6_u9pqrYE6Yrlbb_wEkmH-ot0/edit#gid=269599640'
46
+
47
+ @st.cache_resource(ttl=30)
48
+ def init_load():
49
+ sh = gc.open_by_url(all_dk_player_projections)
50
+ worksheet = sh.worksheet('DK_SD_Build')
51
+ load_display = pd.DataFrame(worksheet.get_all_records())
52
+ load_display.replace('', np.nan, inplace=True)
53
+ raw_display = load_display.dropna(subset=['PPR'])
54
+ raw_display.rename(columns={"Name": "Player", "Fantasy": "Median"}, inplace = True)
55
+ raw_display = raw_display[['Player', 'Salary', 'Position', 'Team', 'Opp', 'Minutes', 'Median', 'Own']]
56
+ dk_roo_raw = raw_display.loc[raw_display['Median'] > 0]
57
+
58
+ worksheet = sh.worksheet('FD_SD_Build')
59
+ load_display = pd.DataFrame(worksheet.get_all_records())
60
+ load_display.replace('', np.nan, inplace=True)
61
+ raw_display = load_display.dropna(subset=['Half_PPR'])
62
+ raw_display.rename(columns={"Name": "Player", "Fantasy": "Median"}, inplace = True)
63
+ raw_display = raw_display[['Player', 'Salary', 'Position', 'Team', 'Opp', 'Minutes', 'Median', 'Own']]
64
+ fd_roo_raw = raw_display.loc[raw_display['Median'] > 0]
65
+
66
+ worksheet = sh.worksheet('DK_SD2_Build')
67
+ load_display = pd.DataFrame(worksheet.get_all_records())
68
+ load_display.replace('', np.nan, inplace=True)
69
+ raw_display = load_display.dropna(subset=['PPR'])
70
+ raw_display.rename(columns={"Name": "Player", "Fantasy": "Median"}, inplace = True)
71
+ raw_display = raw_display[['Player', 'Salary', 'Position', 'Team', 'Opp', 'Minutes', 'Median', 'Own']]
72
+ dk_roo_raw_2 = raw_display.loc[raw_display['Median'] > 0]
73
+
74
+ worksheet = sh.worksheet('FD_SD2_Build')
75
+ load_display = pd.DataFrame(worksheet.get_all_records())
76
+ load_display.replace('', np.nan, inplace=True)
77
+ raw_display = load_display.dropna(subset=['Half_PPR'])
78
+ raw_display.rename(columns={"Name": "Player", "Fantasy": "Median"}, inplace = True)
79
+ raw_display = raw_display[['Player', 'Salary', 'Position', 'Team', 'Opp', 'Median', 'Own', 'Minutes']]
80
+ fd_roo_raw_2 = raw_display.loc[raw_display['Median'] > 0]
81
+
82
+ worksheet = sh.worksheet('DK_SD_Build')
83
+ load_display = pd.DataFrame(worksheet.get_all_records())
84
+ load_display.replace('', np.nan, inplace=True)
85
+ load_display.rename(columns={"PPR": "Median", "name": "Player"}, inplace = True)
86
+ raw_display = load_display.dropna(subset=['Median'])
87
+ dk_ids = dict(zip(raw_display['Player'], raw_display['player_id']))
88
+
89
+ worksheet = sh.worksheet('FD_SD_Build')
90
+ load_display = pd.DataFrame(worksheet.get_all_records())
91
+ load_display.replace('', np.nan, inplace=True)
92
+ load_display.rename(columns={"Half_PPR": "Median", "name": "Player"}, inplace = True)
93
+ raw_display = load_display.dropna(subset=['Median'])
94
+ fd_ids = dict(zip(raw_display['Player'], raw_display['player_id']))
95
+
96
+ return dk_roo_raw, dk_roo_raw_2, fd_roo_raw, fd_roo_raw_2, dk_ids, fd_ids
97
+
98
+ dk_roo_raw, dk_roo_raw_2, fd_roo_raw, fd_roo_raw_2, dk_ids, fd_ids = init_load()
99
+
100
+ @st.cache_data
101
+ def convert_df_to_csv(df):
102
+ return df.to_csv().encode('utf-8')
103
+
104
+ tab1, tab2, tab3 = st.tabs(['Uploads and Info', 'Range of Outcomes', 'Optimizer'])
105
+
106
+ with tab1:
107
+ st.info("The Projections file can have any columns in any order, but must contain columns explicitly named: 'Player', 'Salary', 'Position', 'Team', 'Opp', 'rush_yards', 'rec', 'Median', and 'Own'. For the purposes of this showdown optimizer, only include FLEX positions, salaries, and medians. The optimizer logic will handle the rest!")
108
+ col1, col2 = st.columns([1, 5])
109
+
110
+ with col1:
111
+ proj_file = st.file_uploader("Upload Projections File", key = 'proj_uploader')
112
+
113
+ if proj_file is not None:
114
+ try:
115
+ proj_dataframe = pd.read_csv(proj_file)
116
+ proj_dataframe = proj_dataframe.loc[proj_dataframe['Median'] > 0]
117
+ try:
118
+ proj_dataframe['Own'] = proj_dataframe['Own'].str.replace('%', '').astype(float)
119
+ except:
120
+ pass
121
+ except:
122
+ proj_dataframe = pd.read_excel(proj_file)
123
+ proj_dataframe = proj_dataframe.loc[proj_dataframe['Median'] > 0]
124
+ try:
125
+ proj_dataframe['Own'] = proj_dataframe['Own'].str.replace('%', '').astype(float)
126
+ except:
127
+ pass
128
+ with col2:
129
+ if proj_file is not None:
130
+ st.dataframe(proj_dataframe.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
131
+
132
+ with tab2:
133
+ col1, col2 = st.columns([1, 5])
134
+ with col1:
135
+ if st.button("Load/Reset Data", key='reset2'):
136
+ st.cache_data.clear()
137
+ dk_roo_raw, dk_roo_raw_2, fd_roo_raw, fd_roo_raw_2, dk_ids, fd_ids = init_load()
138
+ slate_var2 = st.radio("Which data are you loading?", ('Paydirt (Main)', 'Paydirt (Secondary)', 'User'), key='slate_var2')
139
+ site_var2 = st.radio("What table would you like to display?", ('Draftkings', 'Fanduel'), key='site_var2')
140
+ if slate_var2 == 'User':
141
+ raw_baselines = proj_dataframe
142
+ elif slate_var2 != 'User':
143
+ if site_var2 == 'Draftkings':
144
+ if slate_var2 == 'Paydirt (Main)':
145
+ raw_baselines = dk_roo_raw
146
+ elif slate_var2 == 'Paydirt (Secondary)':
147
+ raw_baselines = dk_roo_raw_2
148
+ elif site_var2 == 'Fanduel':
149
+ if slate_var2 == 'Paydirt (Main)':
150
+ raw_baselines = fd_roo_raw
151
+ elif slate_var2 == 'Paydirt (Secondary)':
152
+ raw_baselines = fd_roo_raw_2
153
+
154
+ with col2:
155
+ hold_container = st.empty()
156
+ if st.button('Create Range of Outcomes for Slate'):
157
+ with hold_container:
158
+ working_roo = raw_baselines
159
+ own_dict = dict(zip(working_roo.Player, working_roo.Own))
160
+ min_dict = dict(zip(working_roo.Player, working_roo.Minutes))
161
+ opp_dict = dict(zip(working_roo.Player, working_roo.Opp))
162
+ team_dict = dict(zip(working_roo.Player, working_roo.Team))
163
+ total_sims = 1000
164
+
165
+ flex_file = working_roo[['Player', 'Position', 'Salary', 'Median', 'Minutes']]
166
+ flex_file.rename(columns={"Agg": "Median"}, inplace = True)
167
+ flex_file['Floor'] = (flex_file['Median'] * .25) + (flex_file['Minutes'] * .25)
168
+ flex_file['Ceiling'] = flex_file['Median'] + 10 + (flex_file['Minutes'] * .25)
169
+ flex_file['STD'] = (flex_file['Median']/4)
170
+ flex_file = flex_file[['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD']]
171
+ hold_file = flex_file
172
+ overall_file = flex_file
173
+ salary_file = flex_file
174
+
175
+ overall_players = overall_file[['Player']]
176
+
177
+ for x in range(0,total_sims):
178
+ salary_file[x] = salary_file['Salary']
179
+
180
+ salary_file=salary_file.drop(['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
181
+ salary_file.astype('int').dtypes
182
+
183
+ salary_file = salary_file.div(1000)
184
+
185
+ for x in range(0,total_sims):
186
+ overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
187
+
188
+ overall_file=overall_file.drop(['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
189
+ overall_file.astype('int').dtypes
190
+
191
+ players_only = hold_file[['Player']]
192
+ raw_lineups_file = players_only
193
+
194
+ for x in range(0,total_sims):
195
+ maps_dict = {'proj_map':dict(zip(hold_file.Player,hold_file[x]))}
196
+ raw_lineups_file[x] = sum([raw_lineups_file['Player'].map(maps_dict['proj_map'])])
197
+ players_only[x] = raw_lineups_file[x].rank(ascending=False)
198
+
199
+ players_only=players_only.drop(['Player'], axis=1)
200
+ players_only.astype('int').dtypes
201
+
202
+ salary_2x_check = (overall_file - (salary_file*2))
203
+ salary_3x_check = (overall_file - (salary_file*3))
204
+ salary_4x_check = (overall_file - (salary_file*4))
205
+
206
+ players_only['Average_Rank'] = players_only.mean(axis=1)
207
+ players_only['Top_finish'] = players_only[players_only == 1].count(axis=1)/total_sims
208
+ players_only['Top_5_finish'] = players_only[players_only <= 5].count(axis=1)/total_sims
209
+ players_only['Top_10_finish'] = players_only[players_only <= 10].count(axis=1)/total_sims
210
+ players_only['20+%'] = overall_file[overall_file >= 20].count(axis=1)/float(total_sims)
211
+ players_only['2x%'] = salary_2x_check[salary_2x_check >= 1].count(axis=1)/float(total_sims)
212
+ players_only['3x%'] = salary_3x_check[salary_3x_check >= 1].count(axis=1)/float(total_sims)
213
+ players_only['4x%'] = salary_4x_check[salary_4x_check >= 1].count(axis=1)/float(total_sims)
214
+
215
+ players_only['Player'] = hold_file[['Player']]
216
+
217
+ final_outcomes = players_only[['Player', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%']]
218
+
219
+ final_Proj = pd.merge(hold_file, final_outcomes, on="Player")
220
+ final_Proj = final_Proj[['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%']]
221
+ final_Proj['Own'] = final_Proj['Player'].map(own_dict)
222
+ final_Proj['Team'] = final_Proj['Player'].map(team_dict)
223
+ final_Proj['Opp'] = final_Proj['Player'].map(opp_dict)
224
+ 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']]
225
+ final_Proj['Projection Rank'] = final_Proj.Median.rank(pct = True)
226
+ final_Proj['Own Rank'] = final_Proj.Own.rank(pct = True)
227
+ final_Proj['LevX'] = 0
228
+ final_Proj['LevX'] = final_Proj[['Projection Rank', 'Top_5_finish']].mean(axis=1) + final_Proj['4x%'] - final_Proj['Own Rank']
229
+ final_Proj['CPT_Own'] = final_Proj['Own'] / 4
230
+ final_Proj['CPT_Proj'] = final_Proj['Median'] * 1.5
231
+ final_Proj['CPT_Salary'] = final_Proj['Salary'] * 1.5
232
+
233
+ display_Proj = final_Proj[['Player', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'Own', 'CPT_Own', 'LevX']]
234
+ display_Proj = display_Proj.set_index('Player')
235
+ display_Proj = display_Proj.sort_values(by='Median', ascending=False)
236
+
237
+ with hold_container:
238
+ hold_container = st.empty()
239
+ display_Proj = display_Proj
240
+ st.dataframe(display_Proj.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), use_container_width = True)
241
+
242
+ st.download_button(
243
+ label="Export Tables",
244
+ data=convert_df_to_csv(final_Proj),
245
+ file_name='Custom_NFL_overall_export.csv',
246
+ mime='text/csv',
247
+ )
248
+
249
+ with tab3:
250
+ col1, col2 = st.columns([1, 5])
251
+ with col1:
252
+ if st.button("Load/Reset Data", key='reset1'):
253
+ st.cache_data.clear()
254
+ dk_roo_raw, dk_roo_raw_2, fd_roo_raw, fd_roo_raw_2, dk_ids, fd_ids = init_load()
255
+ for key in st.session_state.keys():
256
+ del st.session_state[key]
257
+ slate_var1 = st.radio("Which data are you loading?", ('Paydirt (Main)', 'Paydirt (Secondary)', 'User'), key='slate_var1')
258
+ site_var1 = st.selectbox("What site is the showdown on?", ('Draftkings', 'Fanduel'), key='site_var1')
259
+ if site_var1 == 'Draftkings':
260
+ if slate_var1 == 'User':
261
+ raw_baselines = proj_dataframe
262
+ elif slate_var1 == 'Paydirt (Main)':
263
+ raw_baselines = dk_roo_raw
264
+ elif slate_var1 == 'Paydirt (Secondary)':
265
+ raw_baselines = dk_roo_raw_2
266
+ elif site_var1 == 'Fanduel':
267
+ if slate_var1 == 'User':
268
+ st.info("Showdown on Fanduel sucks, you should not do that, but I understand degen's gotta degen")
269
+ raw_baselines = proj_dataframe
270
+ elif slate_var1 == 'Paydirt (Main)':
271
+ st.info("Showdown on Fanduel sucks, you should not do that, but I understand degen's gotta degen")
272
+ raw_baselines = fd_roo_raw
273
+ elif slate_var1 == 'Paydirt (Secondary)':
274
+ st.info("Showdown on Fanduel sucks, you should not do that, but I understand degen's gotta degen")
275
+ raw_baselines = fd_roo_raw_2
276
+ contest_var1 = st.selectbox("What contest type are you optimizing for?", ('Cash', 'Small Field GPP', 'Large Field GPP'), key='contest_var1')
277
+ lock_var1 = st.multiselect("Are there any players you want to use in all lineups in the CAPTAIN (Lock Button)?", options = raw_baselines['Player'].unique(), key='lock_var1')
278
+ lock_var2 = st.multiselect("Are there any players you want to use in all lineups in the FLEX (Lock Button)?", options = raw_baselines['Player'].unique(), key='lock_var2')
279
+ avoid_var1 = st.multiselect("Are there any players you want to remove from the pool (Drop Button)?", options = raw_baselines['Player'].unique(), key='avoid_var1')
280
+ trim_choice1 = st.selectbox("Allow overowned lineups?", options = ['Yes', 'No'])
281
+ linenum_var1 = st.number_input("How many lineups would you like to produce?", min_value = 1, max_value = 300, value = 20, step = 1, key='linenum_var1')
282
+ if trim_choice1 == 'Yes':
283
+ trim_var1 = 0
284
+ elif trim_choice1 == 'No':
285
+ trim_var1 = 1
286
+ if site_var1 == 'Draftkings':
287
+ min_sal1 = st.number_input('Min Salary', min_value = 35000, max_value = 49900, value = 49000, step = 100, key='min_sal1')
288
+ max_sal1 = st.number_input('Max Salary', min_value = 35000, max_value = 50000, value = 50000, step = 100, key='max_sal1')
289
+ elif site_var1 == 'Fanduel':
290
+ min_sal1 = st.number_input('Min Salary', min_value = 45000, max_value = 59900, value = 59000, step = 100, key='min_sal1')
291
+ max_sal1 = st.number_input('Max Salary', min_value = 45000, max_value = 60000, value = 60000, step = 100, key='max_sal1')
292
+
293
+ if site_var1 == 'Draftkings':
294
+ ownframe = raw_baselines.copy()
295
+ ownframe['Own'] = ownframe['Own'] * (500 / ownframe['Own%'].sum())
296
+ elif site_var1 == 'Fanduel':
297
+ ownframe = raw_baselines.copy()
298
+ ownframe['Own'] = ownframe['Own'] * (400 / ownframe['Own%'].sum())
299
+
300
+ export_baselines = ownframe[['Player', 'Salary', 'Position', 'Team', 'Opp', 'Median', 'Own']]
301
+ export_baselines['CPT_Proj'] = export_baselines['Median'] * 1.5
302
+ export_baselines['CPT_Salary'] = export_baselines['Salary'] * 1.5
303
+ display_baselines = ownframe[['Player', 'Salary', 'Position', 'Team', 'Opp', 'Median', 'Own']]
304
+ display_baselines['CPT Own'] = display_baselines['Own'] / 4
305
+ display_baselines = display_baselines.sort_values(by='Median', ascending=False)
306
+ display_baselines['cpt_lock'] = np.where(display_baselines['Player'].isin(lock_var1), 1, 0)
307
+ display_baselines['lock'] = np.where(display_baselines['Player'].isin(lock_var2), 1, 0)
308
+
309
+ st.session_state.display_baselines = display_baselines.copy()
310
+ st.session_state.export_baselines = export_baselines.copy()
311
+
312
+ index_check = pd.DataFrame()
313
+ flex_proj = pd.DataFrame()
314
+ cpt_proj = pd.DataFrame()
315
+
316
+ if site_var1 == 'Draftkings':
317
+ cpt_proj['Player'] = display_baselines['Player']
318
+ cpt_proj['Salary'] = display_baselines['Salary'] * 1.5
319
+ cpt_proj['Position'] = display_baselines['Position']
320
+ cpt_proj['Team'] = display_baselines['Team']
321
+ cpt_proj['Opp'] = display_baselines['Opp']
322
+ cpt_proj['Median'] = display_baselines['Median'] * 1.5
323
+ cpt_proj['Own'] = display_baselines['CPT Own']
324
+ cpt_proj['lock'] = display_baselines['cpt_lock']
325
+ cpt_proj['roster'] = 'CPT'
326
+ if len(lock_var1) > 0:
327
+ cpt_proj = cpt_proj[cpt_proj['lock'] == 1]
328
+ if len(lock_var2) > 0:
329
+ cpt_proj = cpt_proj[~cpt_proj['Player'].isin(lock_var2)]
330
+
331
+ flex_proj['Player'] = display_baselines['Player']
332
+ flex_proj['Salary'] = display_baselines['Salary']
333
+ flex_proj['Position'] = display_baselines['Position']
334
+ flex_proj['Team'] = display_baselines['Team']
335
+ flex_proj['Opp'] = display_baselines['Opp']
336
+ flex_proj['Median'] = display_baselines['Median']
337
+ flex_proj['Own'] = display_baselines['Own']
338
+ flex_proj['lock'] = display_baselines['lock']
339
+ flex_proj['roster'] = 'FLEX'
340
+ elif site_var1 == 'Fanduel':
341
+ cpt_proj['Player'] = display_baselines['Player']
342
+ cpt_proj['Salary'] = display_baselines['Salary']
343
+ cpt_proj['Position'] = display_baselines['Position']
344
+ cpt_proj['Team'] = display_baselines['Team']
345
+ cpt_proj['Opp'] = display_baselines['Opp']
346
+ cpt_proj['Median'] = display_baselines['Median'] * 1.5
347
+ cpt_proj['Own'] = display_baselines['CPT Own'] *.75
348
+ cpt_proj['lock'] = display_baselines['cpt_lock']
349
+ cpt_proj['roster'] = 'CPT'
350
+
351
+ flex_proj['Player'] = display_baselines['Player']
352
+ flex_proj['Salary'] = display_baselines['Salary']
353
+ flex_proj['Position'] = display_baselines['Position']
354
+ flex_proj['Team'] = display_baselines['Team']
355
+ flex_proj['Opp'] = display_baselines['Opp']
356
+ flex_proj['Median'] = display_baselines['Median']
357
+ flex_proj['Own'] = display_baselines['Own']
358
+ flex_proj['lock'] = display_baselines['lock']
359
+ flex_proj['roster'] = 'FLEX'
360
+
361
+ combo_file = pd.concat([cpt_proj, flex_proj], ignore_index=True)
362
+
363
+ with col2:
364
+ display_container = st.empty()
365
+ display_dl_container = st.empty()
366
+ optimize_container = st.empty()
367
+ download_container = st.empty()
368
+ freq_container = st.empty()
369
+ if st.button('Optimize'):
370
+ for key in st.session_state.keys():
371
+ del st.session_state[key]
372
+ max_proj = 1000
373
+ max_own = 1000
374
+ total_proj = 0
375
+ total_own = 0
376
+ display_container = st.empty()
377
+ display_dl_container = st.empty()
378
+ optimize_container = st.empty()
379
+ download_container = st.empty()
380
+ freq_container = st.empty()
381
+ lineup_display = []
382
+ check_list = []
383
+ lineups = []
384
+ portfolio = pd.DataFrame()
385
+ x = 1
386
+
387
+ with st.spinner('Wait for it...'):
388
+ with optimize_container:
389
+
390
+ while x <= linenum_var1:
391
+ sorted_lineup = []
392
+ p_used = []
393
+
394
+ raw_proj_file = combo_file
395
+ raw_flex_file = raw_proj_file.dropna(how='all')
396
+ raw_flex_file = raw_flex_file.loc[raw_flex_file['Median'] > 0]
397
+ flex_file = raw_flex_file
398
+ flex_file.rename(columns={"Own": "Proj DK Own%"}, inplace = True)
399
+ flex_file['name_var'] = flex_file['Player']
400
+ flex_file['lock'] = np.where(flex_file['Player'].isin(lock_var2), 1, 0)
401
+ flex_file = flex_file[~flex_file['Player'].isin(avoid_var1)]
402
+ flex_file['Player'] = np.where(flex_file['roster'] == 'CPT', flex_file['Player'] + ' - CPT', flex_file['Player'] + ' - FLEX')
403
+ player_ids = flex_file.index
404
+
405
+ overall_players = flex_file[['Player']]
406
+ overall_players['player_var_add'] = flex_file.index
407
+ overall_players['player_var'] = 'player_vars_' + overall_players['player_var_add'].astype(str)
408
+
409
+ player_vars = pulp.LpVariable.dicts("player_vars", flex_file.index, 0, 1, pulp.LpInteger)
410
+ total_score = pulp.LpProblem("Fantasy_Points_Problem", pulp.LpMaximize)
411
+ player_match = dict(zip(overall_players['player_var'], overall_players['Player']))
412
+ player_index_match = dict(zip(overall_players['player_var'], overall_players['player_var_add']))
413
+
414
+ player_own = dict(zip(flex_file['Player'], flex_file['Proj DK Own%']))
415
+ player_team = dict(zip(flex_file['Player'], flex_file['Team']))
416
+ player_pos = dict(zip(flex_file['Player'], flex_file['Position']))
417
+ player_sal = dict(zip(flex_file['Player'], flex_file['Salary']))
418
+ player_proj = dict(zip(flex_file['Player'], flex_file['Median']))
419
+
420
+ obj_points = {idx: (flex_file['Median'][idx]) for idx in flex_file.index}
421
+ total_score += sum([player_vars[idx]*obj_points[idx] for idx in flex_file.index])
422
+
423
+ obj_points_max = {idx: (flex_file['Median'][idx]) for idx in flex_file.index}
424
+ obj_own_max = {idx: (flex_file['Proj DK Own%'][idx]) for idx in flex_file.index}
425
+
426
+ obj_salary = {idx: (flex_file['Salary'][idx]) for idx in flex_file.index}
427
+ total_score += pulp.lpSum([player_vars[idx]*obj_salary[idx] for idx in flex_file.index]) <= max_sal1
428
+ total_score += pulp.lpSum([player_vars[idx]*obj_salary[idx] for idx in flex_file.index]) >= min_sal1
429
+
430
+ if site_var1 == 'Draftkings':
431
+
432
+ for flex in flex_file['lock'].unique():
433
+ sub_idx = flex_file[flex_file['lock'] == 1].index
434
+ total_score += pulp.lpSum([player_vars[idx] for idx in sub_idx]) == len(lock_var2)
435
+
436
+ for flex in flex_file['roster'].unique():
437
+ sub_idx = flex_file[flex_file['roster'] == "CPT"].index
438
+ total_score += pulp.lpSum([player_vars[idx] for idx in sub_idx]) == 1
439
+
440
+ for flex in flex_file['roster'].unique():
441
+ sub_idx = flex_file[flex_file['roster'] == "FLEX"].index
442
+ total_score += pulp.lpSum([player_vars[idx] for idx in sub_idx]) == 5
443
+
444
+ for playerid in player_ids:
445
+ total_score += pulp.lpSum([player_vars[i] for i in player_ids if
446
+ (flex_file['name_var'][i] == flex_file['name_var'][playerid])]) <= 1
447
+
448
+ elif site_var1 == 'Fanduel':
449
+
450
+ for flex in flex_file['lock'].unique():
451
+ sub_idx = flex_file[flex_file['lock'] == 1].index
452
+ total_score += pulp.lpSum([player_vars[idx] for idx in sub_idx]) == len(lock_var2)
453
+
454
+ for flex in flex_file['Position'].unique():
455
+ sub_idx = flex_file[flex_file['Position'] != "Var"].index
456
+ total_score += pulp.lpSum([player_vars[idx] for idx in sub_idx]) == 5
457
+
458
+ for flex in flex_file['roster'].unique():
459
+ sub_idx = flex_file[flex_file['roster'] == "CPT"].index
460
+ total_score += pulp.lpSum([player_vars[idx] for idx in sub_idx]) == 1
461
+
462
+ for playerid in player_ids:
463
+ total_score += pulp.lpSum([player_vars[i] for i in player_ids if
464
+ (flex_file['name_var'][i] == flex_file['name_var'][playerid])]) <= 1
465
+
466
+ player_count = []
467
+ player_trim = []
468
+ lineup_list = []
469
+
470
+ if contest_var1 == 'Cash':
471
+ obj_points = {idx: (flex_file['Proj DK Own%'][idx]) for idx in flex_file.index}
472
+ total_score += sum([player_vars[idx]*obj_points[idx] for idx in flex_file.index])
473
+ total_score += pulp.lpSum([player_vars[idx]*obj_points[idx] for idx in flex_file.index]) <= max_own - .001
474
+ elif contest_var1 != 'Cash':
475
+ obj_points = {idx: (flex_file['Median'][idx]) for idx in flex_file.index}
476
+ total_score += sum([player_vars[idx]*obj_points[idx] for idx in flex_file.index])
477
+ total_score += pulp.lpSum([player_vars[idx]*obj_points[idx] for idx in flex_file.index]) <= max_proj - .01
478
+ if trim_var1 == 1:
479
+ total_score += pulp.lpSum([player_vars[idx]*obj_own_max[idx] for idx in flex_file.index]) <= max_own - .001
480
+
481
+ total_score.solve()
482
+ for v in total_score.variables():
483
+ if v.varValue > 0:
484
+ lineup_list.append(v.name)
485
+ df = pd.DataFrame(lineup_list)
486
+ df['Names'] = df[0].map(player_match)
487
+ df['Cost'] = df['Names'].map(player_sal)
488
+ df['Proj'] = df['Names'].map(player_proj)
489
+ df['Own'] = df['Names'].map(player_own)
490
+ total_cost = sum(df['Cost'])
491
+ total_own = sum(df['Own'])
492
+ total_proj = sum(df['Proj'])
493
+ lineup_raw = pd.DataFrame(lineup_list)
494
+ lineup_raw['Names'] = lineup_raw[0].map(player_match)
495
+ lineup_raw['value'] = lineup_raw[0].map(player_index_match)
496
+ lineup_final = lineup_raw.sort_values(by=['value'])
497
+ del lineup_final[lineup_final.columns[0]]
498
+ del lineup_final[lineup_final.columns[1]]
499
+ lineup_final['Team'] = lineup_final['Names'].map(player_team)
500
+ lineup_final['Position'] = lineup_final['Names'].map(player_pos)
501
+ lineup_final['Salary'] = lineup_final['Names'].map(player_sal)
502
+ lineup_final['Proj'] = lineup_final['Names'].map(player_proj)
503
+ lineup_final['Own'] = lineup_final['Names'].map(player_own)
504
+ lineup_final.loc['Column_Total'] = lineup_final.sum(numeric_only=True, axis=0)
505
+ lineup_final = lineup_final.reset_index(drop=True)
506
+
507
+ max_proj = total_proj
508
+ max_own = total_own
509
+
510
+ if site_var1 == 'Draftkings':
511
+ if len(lineup_final) == 7:
512
+ port_display = pd.DataFrame(lineup_final['Names'][:-1].values.reshape(1, -1))
513
+
514
+ port_display['Cost'] = total_cost
515
+ port_display['Proj'] = total_proj
516
+ port_display['Own'] = total_own
517
+ st.table(port_display)
518
+
519
+ portfolio = pd.concat([portfolio, port_display], ignore_index = True)
520
+ elif site_var1 == 'Fanduel':
521
+ if len(lineup_final) == 6:
522
+ port_display = pd.DataFrame(lineup_final['Names'][:-1].values.reshape(1, -1))
523
+
524
+ port_display['Cost'] = total_cost
525
+ port_display['Proj'] = total_proj
526
+ port_display['Own'] = total_own
527
+ st.table(port_display)
528
+
529
+ portfolio = pd.concat([portfolio, port_display], ignore_index = True)
530
+
531
+ x += 1
532
+
533
+ if site_var1 == 'Draftkings':
534
+ portfolio.rename(columns={0: "CPT", 1: "FLEX1", 2: "FLEX2", 3: "FLEX3", 4: "FLEX4", 5: "FLEX5"}, inplace = True)
535
+ elif site_var1 == 'Fanduel':
536
+ portfolio.rename(columns={0: "MVP", 1: "FLEX1", 2: "FLEX2", 3: "FLEX3", 4: "FLEX4"}, inplace = True)
537
+ portfolio = portfolio.dropna()
538
+ portfolio = portfolio.reset_index()
539
+ portfolio['Lineup_num'] = portfolio['index'] + 1
540
+ portfolio.rename(columns={'Lineup_num': "Lineup"}, inplace = True)
541
+ portfolio = portfolio.set_index('Lineup')
542
+ portfolio = portfolio.drop(columns=['index'])
543
+ st.session_state.portfolio = portfolio.drop_duplicates()
544
+
545
+ final_outcomes = portfolio
546
+ st.session_state.final_outcomes = portfolio
547
+
548
+ player_freq = pd.DataFrame(np.column_stack(np.unique(st.session_state.portfolio.iloc[:,0:5].values, return_counts=True)),
549
+ columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
550
+ player_freq['Freq'] = player_freq['Freq'].astype(int)
551
+ player_freq['Position'] = player_freq['Player'].map(player_pos)
552
+ player_freq['Salary'] = player_freq['Player'].map(player_sal)
553
+ player_freq['Proj Own'] = player_freq['Player'].map(player_own) / 100
554
+ player_freq['Exposure'] = player_freq['Freq']/(linenum_var1)
555
+ player_freq['Team'] = player_freq['Player'].map(player_team)
556
+
557
+ final_outcomes_export = pd.DataFrame()
558
+ split_portfolio = pd.DataFrame()
559
+
560
+ if site_var1 == 'Draftkings':
561
+
562
+ # split_portfolio[['CPT', 'CPT_ID']] = final_outcomes.CPT.str.split("-", n=1, expand = True)
563
+ # split_portfolio[['FLEX1', 'FLEX1_ID']] = final_outcomes.FLEX1.str.split("-", n=1, expand = True)
564
+ # split_portfolio[['FLEX2', 'FLEX2_ID']] = final_outcomes.FLEX2.str.split("-", n=1, expand = True)
565
+ # split_portfolio[['FLEX3', 'FLEX3_ID']] = final_outcomes.FLEX3.str.split("-", n=1, expand = True)
566
+ # split_portfolio[['FLEX4', 'FLEX4_ID']] = final_outcomes.FLEX4.str.split("-", n=1, expand = True)
567
+ # split_portfolio[['FLEX5', 'FLEX5_ID']] = final_outcomes.FLEX5.str.split("-", n=1, expand = True)
568
+
569
+ # split_portfolio['CPT'] = split_portfolio['CPT'].str.strip()
570
+ # split_portfolio['FLEX1'] = split_portfolio['FLEX1'].str.strip()
571
+ # split_portfolio['FLEX2'] = split_portfolio['FLEX2'].str.strip()
572
+ # split_portfolio['FLEX3'] = split_portfolio['FLEX3'].str.strip()
573
+ # split_portfolio['FLEX4'] = split_portfolio['FLEX4'].str.strip()
574
+ # split_portfolio['FLEX5'] = split_portfolio['FLEX5'].str.strip()
575
+
576
+ # final_outcomes_export['CPT'] = split_portfolio['CPT']
577
+ # final_outcomes_export['FLEX1'] = split_portfolio['FLEX1']
578
+ # final_outcomes_export['FLEX2'] = split_portfolio['FLEX2']
579
+ # final_outcomes_export['FLEX3'] = split_portfolio['FLEX3']
580
+ # final_outcomes_export['FLEX4'] = split_portfolio['FLEX4']
581
+ # final_outcomes_export['FLEX5'] = split_portfolio['FLEX5']
582
+
583
+ # final_outcomes_export['CPT'].replace(dkid_dict, inplace=True)
584
+ # final_outcomes_export['FLEX1'].replace(dkid_dict, inplace=True)
585
+ # final_outcomes_export['FLEX2'].replace(dkid_dict, inplace=True)
586
+ # final_outcomes_export['FLEX3'].replace(dkid_dict, inplace=True)
587
+ # final_outcomes_export['FLEX4'].replace(dkid_dict, inplace=True)
588
+ # final_outcomes_export['FLEX5'].replace(dkid_dict, inplace=True)
589
+ # final_outcomes_export['Salary'] = final_outcomes['Cost']
590
+ # final_outcomes_export['Own'] = final_outcomes['Own']
591
+ # final_outcomes_export['Proj'] = final_outcomes['Proj']
592
+
593
+ st.session_state.final_outcomes_export = final_outcomes_export.copy()
594
+
595
+ elif site_var1 == 'Fanduel':
596
+
597
+ # split_portfolio[['MVP', 'CPT_ID']] = final_outcomes.MVP.str.split("-", n=1, expand = True)
598
+ # split_portfolio[['FLEX1', 'FLEX1_ID']] = final_outcomes.FLEX1.str.split("-", n=1, expand = True)
599
+ # split_portfolio[['FLEX2', 'FLEX2_ID']] = final_outcomes.FLEX2.str.split("-", n=1, expand = True)
600
+ # split_portfolio[['FLEX3', 'FLEX3_ID']] = final_outcomes.FLEX3.str.split("-", n=1, expand = True)
601
+ # split_portfolio[['FLEX4', 'FLEX4_ID']] = final_outcomes.FLEX4.str.split("-", n=1, expand = True)
602
+
603
+ # split_portfolio['MVP'] = split_portfolio['MVP'].str.strip()
604
+ # split_portfolio['FLEX1'] = split_portfolio['FLEX1'].str.strip()
605
+ # split_portfolio['FLEX2'] = split_portfolio['FLEX2'].str.strip()
606
+ # split_portfolio['FLEX3'] = split_portfolio['FLEX3'].str.strip()
607
+ # split_portfolio['FLEX4'] = split_portfolio['FLEX4'].str.strip()
608
+
609
+ # final_outcomes_export['MVP'] = split_portfolio['MVP']
610
+ # final_outcomes_export['FLEX1'] = split_portfolio['FLEX1']
611
+ # final_outcomes_export['FLEX2'] = split_portfolio['FLEX2']
612
+ # final_outcomes_export['FLEX3'] = split_portfolio['FLEX3']
613
+ # final_outcomes_export['FLEX4'] = split_portfolio['FLEX4']
614
+
615
+ # final_outcomes_export['MVP'].replace(fdid_dict, inplace=True)
616
+ # final_outcomes_export['FLEX1'].replace(fdid_dict, inplace=True)
617
+ # final_outcomes_export['FLEX2'].replace(fdid_dict, inplace=True)
618
+ # final_outcomes_export['FLEX3'].replace(fdid_dict, inplace=True)
619
+ # final_outcomes_export['FLEX4'].replace(fdid_dict, inplace=True)
620
+ # final_outcomes_export['Salary'] = final_outcomes['Cost']
621
+ # final_outcomes_export['Own'] = final_outcomes['Own']
622
+ # final_outcomes_export['Proj'] = final_outcomes['Proj']
623
+
624
+ st.session_state.FD_final_outcomes_export = final_outcomes_export.copy()
625
+
626
+ st.session_state.player_freq = player_freq[['Player', 'Position', 'Team', 'Salary', 'Proj Own', 'Exposure']]
627
+ with display_container:
628
+ display_container = st.empty()
629
+ if 'display_baselines' in st.session_state:
630
+ st.dataframe(st.session_state.display_baselines.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
631
+
632
+ with display_dl_container:
633
+ display_dl_container = st.empty()
634
+ if 'export_baselines' in st.session_state:
635
+ st.download_button(
636
+ label="Export Projections",
637
+ data=convert_df_to_csv(st.session_state.export_baselines),
638
+ file_name='showdown_proj_export.csv',
639
+ mime='text/csv',
640
+ )
641
+
642
+ with optimize_container:
643
+ optimize_container = st.empty()
644
+ if 'final_outcomes' in st.session_state:
645
+ st.dataframe(st.session_state.final_outcomes.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
646
+
647
+ with download_container:
648
+ download_container = st.empty()
649
+ if site_var1 == 'Draftkings':
650
+ if 'final_outcomes_export' in st.session_state:
651
+ st.download_button(
652
+ label="Export Optimals",
653
+ data=convert_df_to_csv(st.session_state.final_outcomes_export),
654
+ file_name='NBA_optimals_export.csv',
655
+ mime='text/csv',
656
+ )
657
+ elif site_var1 == 'Fanduel':
658
+ if 'FD_final_outcomes_export' in st.session_state:
659
+ st.download_button(
660
+ label="Export Optimals",
661
+ data=convert_df_to_csv(st.session_state.FD_final_outcomes_export),
662
+ file_name='FD_NBA_optimals_export.csv',
663
+ mime='text/csv',
664
+ )
665
+
666
+ with freq_container:
667
+ freq_container = st.empty()
668
+ if 'player_freq' in st.session_state:
669
+ st.dataframe(st.session_state.player_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(expose_format, precision=2), use_container_width = True)
670
+