Spaces:
Running
Running
James McCool
commited on
Commit
·
8e39e09
1
Parent(s):
68d9ccc
Add custom styling and segmented control for tab navigation in streamlit_app.py
Browse files- src/streamlit_app.py +57 -10
src/streamlit_app.py
CHANGED
@@ -11,6 +11,43 @@ from database import props_db, dfs_db
|
|
11 |
game_format = {'Win%': '{:.2%}', 'Vegas': '{:.2%}', 'Win% Diff': '{:.2%}'}
|
12 |
american_format = {'First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}'}
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
def calculate_poisson(row):
|
15 |
mean_val = row['Mean_Outcome']
|
16 |
threshold = row['Prop']
|
@@ -88,6 +125,9 @@ def calculate_no_vig(row):
|
|
88 |
|
89 |
return no_vig_prob
|
90 |
|
|
|
|
|
|
|
91 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame, market_props = init_baselines()
|
92 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
93 |
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
@@ -107,10 +147,17 @@ sim_all_hold = pd.DataFrame(columns=['Player', 'Team', 'Book', 'Prop Type', 'Pro
|
|
107 |
|
108 |
tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs(["Game Betting Model", 'Prop Market', "QB Projections", "RB/WR/TE Projections", "Player Prop Trends", "Player Prop Simulations", "Stat Specific Simulations"])
|
109 |
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
st.info(t_stamp)
|
115 |
if st.button("Reset Data", key='reset1'):
|
116 |
st.cache_data.clear()
|
@@ -143,7 +190,7 @@ with tab1:
|
|
143 |
key='team_export',
|
144 |
)
|
145 |
|
146 |
-
with
|
147 |
st.info(t_stamp)
|
148 |
if st.button("Reset Data", key='reset4'):
|
149 |
st.cache_data.clear()
|
@@ -183,7 +230,7 @@ with tab2:
|
|
183 |
mime='text/csv',
|
184 |
)
|
185 |
|
186 |
-
with
|
187 |
st.info(t_stamp)
|
188 |
if st.button("Reset Data", key='reset2'):
|
189 |
st.cache_data.clear()
|
@@ -211,7 +258,7 @@ with tab3:
|
|
211 |
key='NFL_qb_stats_export',
|
212 |
)
|
213 |
|
214 |
-
with
|
215 |
st.info(t_stamp)
|
216 |
if st.button("Reset Data", key='reset3'):
|
217 |
st.cache_data.clear()
|
@@ -239,7 +286,7 @@ with tab4:
|
|
239 |
key='NFL_nonqb_stats_export',
|
240 |
)
|
241 |
|
242 |
-
with
|
243 |
st.info(t_stamp)
|
244 |
if st.button("Reset Data", key='reset5'):
|
245 |
st.cache_data.clear()
|
@@ -270,7 +317,7 @@ with tab5:
|
|
270 |
mime='text/csv',
|
271 |
)
|
272 |
|
273 |
-
with
|
274 |
st.info(t_stamp)
|
275 |
if st.button("Reset Data", key='reset6'):
|
276 |
st.cache_data.clear()
|
@@ -420,7 +467,7 @@ with tab6:
|
|
420 |
plot_hold_container = st.empty()
|
421 |
st.plotly_chart(fig, use_container_width=True)
|
422 |
|
423 |
-
with
|
424 |
st.info(t_stamp)
|
425 |
st.info('The Over and Under percentages are a compositve percentage based on simulations, historical performance, and implied probabilities, and may be different than you would expect based purely on the median projection. Likewise, the Edge of a bet is not the only indicator of if you should make the bet or not as the suggestion is using a base acceptable threshold to determine how much edge you should have for each stat category.')
|
426 |
if st.button("Reset Data/Load Data", key='reset7'):
|
|
|
11 |
game_format = {'Win%': '{:.2%}', 'Vegas': '{:.2%}', 'Win% Diff': '{:.2%}'}
|
12 |
american_format = {'First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}'}
|
13 |
|
14 |
+
st.markdown("""
|
15 |
+
<style>
|
16 |
+
/* Tab styling */
|
17 |
+
.stElementContainer [data-baseweb="button-group"] {
|
18 |
+
gap: 2.000rem;
|
19 |
+
padding: 4px;
|
20 |
+
}
|
21 |
+
.stElementContainer [kind="segmented_control"] {
|
22 |
+
height: 2.000rem;
|
23 |
+
white-space: pre-wrap;
|
24 |
+
background-color: #DAA520;
|
25 |
+
color: white;
|
26 |
+
border-radius: 20px;
|
27 |
+
gap: 1px;
|
28 |
+
padding: 10px 20px;
|
29 |
+
font-weight: bold;
|
30 |
+
transition: all 0.3s ease;
|
31 |
+
}
|
32 |
+
.stElementContainer [kind="segmented_controlActive"] {
|
33 |
+
height: 3.000rem;
|
34 |
+
background-color: #DAA520;
|
35 |
+
border: 3px solid #FFD700;
|
36 |
+
border-radius: 10px;
|
37 |
+
color: black;
|
38 |
+
}
|
39 |
+
.stElementContainer [kind="segmented_control"]:hover {
|
40 |
+
background-color: #FFD700;
|
41 |
+
cursor: pointer;
|
42 |
+
}
|
43 |
+
|
44 |
+
div[data-baseweb="select"] > div {
|
45 |
+
background-color: #DAA520;
|
46 |
+
color: white;
|
47 |
+
}
|
48 |
+
|
49 |
+
</style>""", unsafe_allow_html=True)
|
50 |
+
|
51 |
def calculate_poisson(row):
|
52 |
mean_val = row['Mean_Outcome']
|
53 |
threshold = row['Prop']
|
|
|
125 |
|
126 |
return no_vig_prob
|
127 |
|
128 |
+
def convert_df_to_csv(df):
|
129 |
+
return df.to_csv().encode('utf-8')
|
130 |
+
|
131 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame, market_props = init_baselines()
|
132 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
133 |
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
|
|
147 |
|
148 |
tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs(["Game Betting Model", 'Prop Market', "QB Projections", "RB/WR/TE Projections", "Player Prop Trends", "Player Prop Simulations", "Stat Specific Simulations"])
|
149 |
|
150 |
+
selected_tab = st.segmented_control(
|
151 |
+
"Select Tab",
|
152 |
+
options=["Game Betting Model", 'Prop Market', "QB Projections", "RB/WR/TE Projections", "Player Prop Trends", "Player Prop Simulations", "Stat Specific Simulations"],
|
153 |
+
selection_mode='single',
|
154 |
+
default='Game Betting Model',
|
155 |
+
width='stretch',
|
156 |
+
label_visibility='collapsed',
|
157 |
+
key='tab_selector'
|
158 |
+
)
|
159 |
+
|
160 |
+
with selected_tab == 'Game Betting Model':
|
161 |
st.info(t_stamp)
|
162 |
if st.button("Reset Data", key='reset1'):
|
163 |
st.cache_data.clear()
|
|
|
190 |
key='team_export',
|
191 |
)
|
192 |
|
193 |
+
with selected_tab == 'Prop Market':
|
194 |
st.info(t_stamp)
|
195 |
if st.button("Reset Data", key='reset4'):
|
196 |
st.cache_data.clear()
|
|
|
230 |
mime='text/csv',
|
231 |
)
|
232 |
|
233 |
+
with selected_tab == 'QB Projections':
|
234 |
st.info(t_stamp)
|
235 |
if st.button("Reset Data", key='reset2'):
|
236 |
st.cache_data.clear()
|
|
|
258 |
key='NFL_qb_stats_export',
|
259 |
)
|
260 |
|
261 |
+
with selected_tab == 'RB/WR/TE Projections':
|
262 |
st.info(t_stamp)
|
263 |
if st.button("Reset Data", key='reset3'):
|
264 |
st.cache_data.clear()
|
|
|
286 |
key='NFL_nonqb_stats_export',
|
287 |
)
|
288 |
|
289 |
+
with selected_tab == 'Player Prop Trends':
|
290 |
st.info(t_stamp)
|
291 |
if st.button("Reset Data", key='reset5'):
|
292 |
st.cache_data.clear()
|
|
|
317 |
mime='text/csv',
|
318 |
)
|
319 |
|
320 |
+
with selected_tab == 'Player Prop Simulations':
|
321 |
st.info(t_stamp)
|
322 |
if st.button("Reset Data", key='reset6'):
|
323 |
st.cache_data.clear()
|
|
|
467 |
plot_hold_container = st.empty()
|
468 |
st.plotly_chart(fig, use_container_width=True)
|
469 |
|
470 |
+
with selected_tab == 'Stat Specific Simulations':
|
471 |
st.info(t_stamp)
|
472 |
st.info('The Over and Under percentages are a compositve percentage based on simulations, historical performance, and implied probabilities, and may be different than you would expect based purely on the median projection. Likewise, the Edge of a bet is not the only indicator of if you should make the bet or not as the suggestion is using a base acceptable threshold to determine how much edge you should have for each stat category.')
|
473 |
if st.button("Reset Data/Load Data", key='reset7'):
|