James McCool commited on
Commit
0fb1f15
·
1 Parent(s): a2460c1

Enhance Streamlit app with MongoDB integration and player frequency analysis. Added secret management for MongoDB URI in Dockerfile, updated requirements to include pymongo, and refactored streamlit_app.py to connect to MongoDB and display player statistics. Implemented data export functionality for player frequency and optimal lineups.

Browse files
Files changed (3) hide show
  1. Dockerfile +5 -0
  2. requirements.txt +2 -1
  3. src/streamlit_app.py +479 -37
Dockerfile CHANGED
@@ -14,6 +14,11 @@ COPY src/ ./src/
14
 
15
  RUN pip3 install -r requirements.txt
16
 
 
 
 
 
 
17
  EXPOSE 8501
18
 
19
  HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
 
14
 
15
  RUN pip3 install -r requirements.txt
16
 
17
+ # Expose the secret SECRET_EXAMPLE at buildtime and use its value as git remote URL
18
+ RUN --mount=type=secret,id=mongo_uri,mode=0444,required=true \
19
+ git init && \
20
+ git remote add origin $(cat /run/secrets/mongo_uri)
21
+
22
  EXPOSE 8501
23
 
24
  HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
  altair
2
  pandas
3
- streamlit
 
 
1
  altair
2
  pandas
3
+ streamlit
4
+ pymongo
src/streamlit_app.py CHANGED
@@ -1,40 +1,482 @@
1
- import altair as alt
2
  import numpy as np
3
  import pandas as pd
4
- import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
  import numpy as np
3
  import pandas as pd
4
+ import pymongo
5
+ import os
6
+
7
+ st.set_page_config(layout="wide")
8
+
9
+ @st.cache_resource
10
+ def init_conn():
11
+ uri = os.getenv('mongo_uri')
12
+ client = pymongo.MongoClient(uri, retryWrites=True, serverSelectionTimeoutMS=500000)
13
+ db = client["MLB_Database"]
14
+
15
+ return db
16
+
17
+ db = init_conn()
18
+
19
+ dk_player_url = 'https://docs.google.com/spreadsheets/d/1lMLxWdvCnOFBtG9dhM0zv2USuxZbkogI_2jnxFfQVVs/edit#gid=1828092624'
20
+ CSV_URL = 'https://docs.google.com/spreadsheets/d/1lMLxWdvCnOFBtG9dhM0zv2USuxZbkogI_2jnxFfQVVs/edit#gid=1828092624'
21
+
22
+ player_roo_format = {'Cut_Odds': '{:.2%}', 'Top_finish': '{:.2%}','Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '100+%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', '7x%': '{:.2%}', '10x%': '{:.2%}', '11x%': '{:.2%}',
23
+ '12x%': '{:.2%}','LevX': '{:.2%}'}
24
+ dk_columns = ['FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'FLEX6', 'salary', 'proj', 'Own']
25
+ fd_columns = ['FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'FLEX6', 'salary', 'proj', 'Own']
26
+
27
+ st.markdown("""
28
+ <style>
29
+ /* Tab styling */
30
+ .stTabs [data-baseweb="tab-list"] {
31
+ gap: 8px;
32
+ padding: 4px;
33
+ }
34
+
35
+ .stTabs [data-baseweb="tab"] {
36
+ height: 50px;
37
+ white-space: pre-wrap;
38
+ background-color: #DAA520;
39
+ color: white;
40
+ border-radius: 10px;
41
+ gap: 1px;
42
+ padding: 10px 20px;
43
+ font-weight: bold;
44
+ transition: all 0.3s ease;
45
+ }
46
+
47
+ .stTabs [aria-selected="true"] {
48
+ background-color: #DAA520;
49
+ border: 3px solid #FFD700;
50
+ color: white;
51
+ }
52
+
53
+ .stTabs [data-baseweb="tab"]:hover {
54
+ background-color: #FFD700;
55
+ cursor: pointer;
56
+ }
57
+ </style>""", unsafe_allow_html=True)
58
+
59
+ @st.cache_resource(ttl = 60)
60
+ def init_baselines():
61
+
62
+ collection = db["PGA_Placement_Rates"]
63
+ cursor = collection.find()
64
+ placement_frame = pd.DataFrame(cursor)
65
+
66
+ collection = db["PGA_Range_of_Outcomes"]
67
+ cursor = collection.find()
68
+ player_frame = pd.DataFrame(cursor)
69
+
70
+ player_frame['Cut_Odds'] = player_frame['Player'].map(placement_frame.set_index('Player')['Cut_Odds'])
71
+ player_frame = player_frame[['Player', 'Cut_Odds'] + [col for col in player_frame.columns if col not in ['Player', 'Cut_Odds']]]
72
+
73
+ timestamp = player_frame['Timestamp'][0]
74
+
75
+ roo_data = player_frame.drop(columns=['_id', 'index', 'Timestamp'])
76
+ roo_data['Salary'] = roo_data['Salary'].astype(int)
77
+
78
+ collection = db["PGA_SD_ROO"]
79
+ cursor = collection.find()
80
+ player_frame = pd.DataFrame(cursor)
81
+
82
+ sd_roo_data = player_frame.drop(columns=['_id', 'index'])
83
+ sd_roo_data['Salary'] = sd_roo_data['Salary'].astype(int)
84
+
85
+ sd_roo_data = player_frame.drop(columns=['_id', 'index'])
86
+ sd_roo_data['Salary'] = sd_roo_data['Salary'].astype(int)
87
+
88
+ return roo_data, sd_roo_data, timestamp
89
+
90
+ @st.cache_data(ttl = 60)
91
+ def init_DK_lineups(type):
92
+
93
+ if type == 'Regular':
94
+ collection = db['PGA_DK_Seed_Frame_Name_Map']
95
+ elif type == 'Showdown':
96
+ collection = db['PGA_DK_SD_Seed_Frame_Name_Map']
97
+ cursor = collection.find()
98
+ raw_data = pd.DataFrame(list(cursor))
99
+ names_dict = dict(zip(raw_data['key'], raw_data['value']))
100
+
101
+ if type == 'Regular':
102
+ collection = db["PGA_DK_Seed_Frame"]
103
+ elif type == 'Showdown':
104
+ collection = db["PGA_DK_SD_Seed_Frame"]
105
+ cursor = collection.find().limit(10000)
106
+
107
+ raw_display = pd.DataFrame(list(cursor))
108
+ raw_display = raw_display[['FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'FLEX6', 'salary', 'proj', 'Own']]
109
+ dict_columns = ['FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'FLEX6']
110
+ for col in dict_columns:
111
+ raw_display[col] = raw_display[col].map(names_dict)
112
+ DK_seed = raw_display.to_numpy()
113
+
114
+ return DK_seed
115
+
116
+ @st.cache_data(ttl = 60)
117
+ def init_FD_lineups(type):
118
+
119
+ if type == 'Regular':
120
+ collection = db['PGA_FD_Seed_Frame_Name_Map']
121
+ elif type == 'Showdown':
122
+ collection = db['PGA_DK_SD_Seed_Frame_Name_Map']
123
+ cursor = collection.find()
124
+ raw_data = pd.DataFrame(list(cursor))
125
+ names_dict = dict(zip(raw_data['key'], raw_data['value']))
126
+
127
+ if type == 'Regular':
128
+ collection = db["PGA_FD_Seed_Frame"]
129
+ elif type == 'Showdown':
130
+ collection = db["PGA_DK_SD_Seed_Frame"]
131
+ cursor = collection.find().limit(10000)
132
+
133
+ raw_display = pd.DataFrame(list(cursor))
134
+ raw_display = raw_display[['FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'FLEX6', 'salary', 'proj', 'Own']]
135
+ dict_columns = ['FLEX1', 'FLEX2', 'FLEX3', 'FLEX4', 'FLEX5', 'FLEX6']
136
+ for col in dict_columns:
137
+ raw_display[col] = raw_display[col].map(names_dict)
138
+ FD_seed = raw_display.to_numpy()
139
+
140
+ return FD_seed
141
+
142
+ def convert_df_to_csv(df):
143
+ return df.to_csv().encode('utf-8')
144
+
145
+ @st.cache_data
146
+ def convert_df(array):
147
+ array = pd.DataFrame(array, columns=column_names)
148
+ return array.to_csv().encode('utf-8')
149
+
150
+ roo_data, sd_roo_data, timestamp = init_baselines()
151
+ hold_display = roo_data
152
+ lineup_display = []
153
+ check_list = []
154
+ rand_player = 0
155
+ boost_player = 0
156
+ salaryCut = 0
157
+
158
+ tab1, tab2 = st.tabs(["Player Overall Projections", "Optimals and Exposures"])
159
+
160
+ with tab1:
161
+ with st.expander("Info and Filters"):
162
+ if st.button("Reset Data", key='reset1'):
163
+ # Clear values from *all* all in-memory and on-disk data caches:
164
+ # i.e. clear values from both square and cube
165
+ st.cache_data.clear()
166
+ roo_data, sd_roo_data, timestamp = init_baselines()
167
+ dk_lineups = init_DK_lineups('Regular')
168
+ fd_lineups = init_FD_lineups('Regular')
169
+ hold_display = roo_data
170
+ for key in st.session_state.keys():
171
+ del st.session_state[key]
172
+
173
+ st.write(timestamp)
174
+
175
+ col1, col2, col3 = st.columns(3)
176
+ with col1:
177
+ view_var = st.radio("Select a View", ["Simple", "Advanced"])
178
+ with col2:
179
+ site_var = st.radio("Select a Site", ["Draftkings", "FanDuel"])
180
+ with col3:
181
+ type_var = st.radio("Select a Type", ["Full Slate", "Showdown"])
182
+
183
+ with st.container():
184
+ if type_var == "Full Slate":
185
+ display = hold_display[hold_display['Site'] == site_var]
186
+ display = display.drop_duplicates(subset=['Player'])
187
+ elif type_var == "Showdown":
188
+ display = sd_roo_data
189
+ display = display.drop_duplicates(subset=['Player'])
190
+
191
+ if view_var == "Simple":
192
+ if type_var == "Full Slate":
193
+ display = display[['Player', 'Cut_Odds', 'Salary', 'Median', '10x%', 'Own']]
194
+ display = display.set_index('Player')
195
+ elif type_var == "Showdown":
196
+ display = display[['Player', 'Salary', 'Median', '5x%', 'Own']]
197
+ display = display.set_index('Player')
198
+ st.dataframe(display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), height=750, use_container_width = True)
199
+ elif view_var == "Advanced":
200
+ display = display
201
+ display = display.set_index('Player')
202
+ st.dataframe(display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), height=750, use_container_width = True)
203
+
204
+ st.download_button(
205
+ label="Export Projections",
206
+ data=convert_df_to_csv(display),
207
+ file_name='PGA_DFS_export.csv',
208
+ mime='text/csv',
209
+ )
210
+
211
+ with tab2:
212
+ with st.expander("Info and Filters"):
213
+ if st.button("Load/Reset Data", key='reset2'):
214
+ st.cache_data.clear()
215
+ roo_data, sd_roo_data, timestamp = init_baselines()
216
+ hold_display = roo_data
217
+ dk_lineups = init_DK_lineups('Regular')
218
+ fd_lineups = init_FD_lineups('Regular')
219
+ t_stamp = f"Last Update: " + str(timestamp) + f" CST"
220
+ for key in st.session_state.keys():
221
+ del st.session_state[key]
222
+
223
+ slate_var1 = st.radio("Which data are you loading?", ('Regular', 'Showdown'))
224
+
225
+ site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'))
226
+ if slate_var1 == 'Regular':
227
+ if site_var1 == 'Draftkings':
228
+ dk_lineups = init_DK_lineups('Regular')
229
+ elif site_var1 == 'Fanduel':
230
+ fd_lineups = init_FD_lineups('Regular')
231
+ elif slate_var1 == 'Showdown':
232
+ if site_var1 == 'Draftkings':
233
+ dk_lineups = init_DK_lineups('Showdown')
234
+ elif site_var1 == 'Fanduel':
235
+ fd_lineups = init_FD_lineups('Showdown')
236
+ lineup_num_var = st.number_input("How many lineups do you want to display?", min_value=1, max_value=1000, value=150, step=1)
237
+
238
+ if slate_var1 == 'Regular':
239
+ raw_baselines = roo_data
240
+ elif slate_var1 == 'Showdown':
241
+ raw_baselines = sd_roo_data
242
+
243
+ if site_var1 == 'Draftkings':
244
+ if slate_var1 == 'Regular':
245
+ ROO_slice = raw_baselines[raw_baselines['Site'] == 'Draftkings']
246
+ player_salaries = dict(zip(ROO_slice['Player'], ROO_slice['Salary']))
247
+ elif slate_var1 == 'Showdown':
248
+ player_salaries = dict(zip(raw_baselines['Player'], raw_baselines['Salary']))
249
+ # Get the minimum and maximum ownership values from dk_lineups
250
+ min_own = np.min(dk_lineups[:,8])
251
+ max_own = np.max(dk_lineups[:,8])
252
+ column_names = dk_columns
253
+
254
+ player_var1 = st.radio("Do you want a frame with specific Players?", ('Full Slate', 'Specific Players'), key='player_var1')
255
+ if player_var1 == 'Specific Players':
256
+ player_var2 = st.multiselect('Which players do you want?', options = raw_baselines['Player'].unique())
257
+ elif player_var1 == 'Full Slate':
258
+ player_var2 = raw_baselines.Player.values.tolist()
259
+
260
+ elif site_var1 == 'Fanduel':
261
+ raw_baselines = hold_display
262
+ if slate_var1 == 'Regular':
263
+ ROO_slice = raw_baselines[raw_baselines['Site'] == 'Fanduel']
264
+ player_salaries = dict(zip(ROO_slice['Player'], ROO_slice['Salary']))
265
+ elif slate_var1 == 'Showdown':
266
+ player_salaries = dict(zip(raw_baselines['Player'], raw_baselines['Salary']))
267
+ min_own = np.min(fd_lineups[:,8])
268
+ max_own = np.max(fd_lineups[:,8])
269
+ column_names = fd_columns
270
+
271
+ player_var1 = st.radio("Do you want a frame with specific Players?", ('Full Slate', 'Specific Players'), key='player_var1')
272
+ if player_var1 == 'Specific Players':
273
+ player_var2 = st.multiselect('Which players do you want?', options = raw_baselines['Player'].unique())
274
+ elif player_var1 == 'Full Slate':
275
+ player_var2 = raw_baselines.Player.values.tolist()
276
+
277
+ if st.button("Prepare data export", key='data_export'):
278
+ data_export = st.session_state.working_seed.copy()
279
+ # if site_var1 == 'Draftkings':
280
+ # for col_idx in range(6):
281
+ # data_export[:, col_idx] = np.array([id_dict.get(player, player) for player in data_export[:, col_idx]])
282
+ # elif site_var1 == 'Fanduel':
283
+ # for col_idx in range(6):
284
+ # data_export[:, col_idx] = np.array([id_dict.get(player, player) for player in data_export[:, col_idx]])
285
+ st.download_button(
286
+ label="Export optimals set",
287
+ data=convert_df(data_export),
288
+ file_name='NBA_optimals_export.csv',
289
+ mime='text/csv',
290
+ )
291
+
292
+ if site_var1 == 'Draftkings':
293
+ if 'working_seed' in st.session_state:
294
+ st.session_state.working_seed = st.session_state.working_seed
295
+ if player_var1 == 'Specific Players':
296
+ st.session_state.working_seed = st.session_state.working_seed[np.equal.outer(st.session_state.working_seed, player_var2).any(axis=1).all(axis=1)]
297
+ elif player_var1 == 'Full Slate':
298
+ st.session_state.working_seed = dk_lineups.copy()
299
+ st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:lineup_num_var], columns=column_names)
300
+ elif 'working_seed' not in st.session_state:
301
+ st.session_state.working_seed = dk_lineups.copy()
302
+ st.session_state.working_seed = st.session_state.working_seed
303
+ if player_var1 == 'Specific Players':
304
+ st.session_state.working_seed = st.session_state.working_seed[np.equal.outer(st.session_state.working_seed, player_var2).any(axis=1).all(axis=1)]
305
+ elif player_var1 == 'Full Slate':
306
+ st.session_state.working_seed = dk_lineups.copy()
307
+ st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:lineup_num_var], columns=column_names)
308
+
309
+ elif site_var1 == 'Fanduel':
310
+ if 'working_seed' in st.session_state:
311
+ st.session_state.working_seed = st.session_state.working_seed
312
+ if player_var1 == 'Specific Players':
313
+ st.session_state.working_seed = st.session_state.working_seed[np.equal.outer(st.session_state.working_seed, player_var2).any(axis=1).all(axis=1)]
314
+ elif player_var1 == 'Full Slate':
315
+ st.session_state.working_seed = fd_lineups.copy()
316
+ st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:lineup_num_var], columns=column_names)
317
+ elif 'working_seed' not in st.session_state:
318
+ st.session_state.working_seed = fd_lineups.copy()
319
+ st.session_state.working_seed = st.session_state.working_seed
320
+ if player_var1 == 'Specific Players':
321
+ st.session_state.working_seed = st.session_state.working_seed[np.equal.outer(st.session_state.working_seed, player_var2).any(axis=1).all(axis=1)]
322
+ elif player_var1 == 'Full Slate':
323
+ st.session_state.working_seed = fd_lineups.copy()
324
+ st.session_state.data_export_display = pd.DataFrame(st.session_state.working_seed[0:lineup_num_var], columns=column_names)
325
+
326
+ export_file = st.session_state.data_export_display.copy()
327
+ # if site_var1 == 'Draftkings':
328
+ # for col_idx in range(6):
329
+ # export_file.iloc[:, col_idx] = export_file.iloc[:, col_idx].map(id_dict)
330
+ # elif site_var1 == 'Fanduel':
331
+ # for col_idx in range(6):
332
+ # export_file.iloc[:, col_idx] = export_file.iloc[:, col_idx].map(id_dict)
333
+
334
+ with st.container():
335
+ if st.button("Reset Optimals", key='reset3'):
336
+ for key in st.session_state.keys():
337
+ del st.session_state[key]
338
+ if site_var1 == 'Draftkings':
339
+ st.session_state.working_seed = dk_lineups.copy()
340
+ elif site_var1 == 'Fanduel':
341
+ st.session_state.working_seed = fd_lineups.copy()
342
+ if 'data_export_display' in st.session_state:
343
+ 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)
344
+ st.download_button(
345
+ label="Export display optimals",
346
+ data=convert_df(export_file),
347
+ file_name='NBA_display_optimals.csv',
348
+ mime='text/csv',
349
+ )
350
+
351
+ with st.container():
352
+ if 'working_seed' in st.session_state:
353
+ # Create a new dataframe with summary statistics
354
+ if site_var1 == 'Draftkings':
355
+ summary_df = pd.DataFrame({
356
+ 'Metric': ['Min', 'Average', 'Max', 'STDdev'],
357
+ 'Salary': [
358
+ np.min(st.session_state.working_seed[:,6]),
359
+ np.mean(st.session_state.working_seed[:,6]),
360
+ np.max(st.session_state.working_seed[:,6]),
361
+ np.std(st.session_state.working_seed[:,6])
362
+ ],
363
+ 'Proj': [
364
+ np.min(st.session_state.working_seed[:,7]),
365
+ np.mean(st.session_state.working_seed[:,7]),
366
+ np.max(st.session_state.working_seed[:,7]),
367
+ np.std(st.session_state.working_seed[:,7])
368
+ ],
369
+ 'Own': [
370
+ np.min(st.session_state.working_seed[:,8]),
371
+ np.mean(st.session_state.working_seed[:,8]),
372
+ np.max(st.session_state.working_seed[:,8]),
373
+ np.std(st.session_state.working_seed[:,8])
374
+ ]
375
+ })
376
+ elif site_var1 == 'Fanduel':
377
+ summary_df = pd.DataFrame({
378
+ 'Metric': ['Min', 'Average', 'Max', 'STDdev'],
379
+ 'Salary': [
380
+ np.min(st.session_state.working_seed[:,6]),
381
+ np.mean(st.session_state.working_seed[:,6]),
382
+ np.max(st.session_state.working_seed[:,6]),
383
+ np.std(st.session_state.working_seed[:,6])
384
+ ],
385
+ 'Proj': [
386
+ np.min(st.session_state.working_seed[:,7]),
387
+ np.mean(st.session_state.working_seed[:,7]),
388
+ np.max(st.session_state.working_seed[:,7]),
389
+ np.std(st.session_state.working_seed[:,7])
390
+ ],
391
+ 'Own': [
392
+ np.min(st.session_state.working_seed[:,8]),
393
+ np.mean(st.session_state.working_seed[:,8]),
394
+ np.max(st.session_state.working_seed[:,8]),
395
+ np.std(st.session_state.working_seed[:,8])
396
+ ]
397
+ })
398
+
399
+ # Set the index of the summary dataframe as the "Metric" column
400
+ summary_df = summary_df.set_index('Metric')
401
+
402
+ # Display the summary dataframe
403
+ st.subheader("Optimal Statistics")
404
+ st.dataframe(summary_df.style.format({
405
+ 'Salary': '{:.2f}',
406
+ 'Proj': '{:.2f}',
407
+ 'Own': '{:.2f}'
408
+ }).background_gradient(cmap='RdYlGn', axis=0, subset=['Salary', 'Proj', 'Own']), use_container_width=True)
409
 
410
+ with st.container():
411
+ tab1, tab2 = st.tabs(["Display Frequency", "Seed Frame Frequency"])
412
+ with tab1:
413
+ if 'data_export_display' in st.session_state:
414
+ if site_var1 == 'Draftkings':
415
+ player_columns = st.session_state.data_export_display.iloc[:, :6]
416
+ elif site_var1 == 'Fanduel':
417
+ player_columns = st.session_state.data_export_display.iloc[:, :6]
418
+
419
+ # Flatten the DataFrame and count unique values
420
+ value_counts = player_columns.values.flatten().tolist()
421
+ value_counts = pd.Series(value_counts).value_counts()
422
+
423
+ percentages = (value_counts / lineup_num_var * 100).round(2)
424
+
425
+ # Create a DataFrame with the results
426
+ summary_df = pd.DataFrame({
427
+ 'Player': value_counts.index,
428
+ 'Frequency': value_counts.values,
429
+ 'Percentage': percentages.values
430
+ })
431
+
432
+ # Sort by frequency in descending order
433
+ summary_df['Salary'] = summary_df['Player'].map(player_salaries)
434
+ summary_df = summary_df[['Player', 'Salary', 'Frequency', 'Percentage']]
435
+ summary_df = summary_df.sort_values('Frequency', ascending=False)
436
+ summary_df = summary_df.set_index('Player')
437
+
438
+ # Display the table
439
+ st.write("Player Frequency Table:")
440
+ st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True)
441
+
442
+ st.download_button(
443
+ label="Export player frequency",
444
+ data=convert_df_to_csv(summary_df),
445
+ file_name='PGA_player_frequency.csv',
446
+ mime='text/csv',
447
+ )
448
+ with tab2:
449
+ if 'working_seed' in st.session_state:
450
+ if site_var1 == 'Draftkings':
451
+ player_columns = st.session_state.working_seed[:, :6]
452
+ elif site_var1 == 'Fanduel':
453
+ player_columns = st.session_state.working_seed[:, :6]
454
+
455
+ # Flatten the DataFrame and count unique values
456
+ value_counts = player_columns.flatten().tolist()
457
+ value_counts = pd.Series(value_counts).value_counts()
458
+
459
+ percentages = (value_counts / len(st.session_state.working_seed) * 100).round(2)
460
+ # Create a DataFrame with the results
461
+ summary_df = pd.DataFrame({
462
+ 'Player': value_counts.index,
463
+ 'Frequency': value_counts.values,
464
+ 'Percentage': percentages.values
465
+ })
466
+
467
+ # Sort by frequency in descending order
468
+ summary_df['Salary'] = summary_df['Player'].map(player_salaries)
469
+ summary_df = summary_df[['Player', 'Salary', 'Frequency', 'Percentage']]
470
+ summary_df = summary_df.sort_values('Frequency', ascending=False)
471
+ summary_df = summary_df.set_index('Player')
472
+
473
+ # Display the table
474
+ st.write("Seed Frame Frequency Table:")
475
+ st.dataframe(summary_df.style.format({'Percentage': '{:.2f}%'}), height=500, use_container_width=True)
476
+
477
+ st.download_button(
478
+ label="Export seed frame frequency",
479
+ data=convert_df_to_csv(summary_df),
480
+ file_name='PGA_seed_frame_frequency.csv',
481
+ mime='text/csv',
482
+ )