James McCool commited on
Commit
78ac3ba
·
1 Parent(s): 5bb8e91

Refactor UI layout and add custom tab styling in app.py

Browse files

Simplified the tab layout by removing unnecessary column divisions and introducing an expandable section for filters. Added custom CSS styling for tabs to improve visual appearance and user experience.

Files changed (1) hide show
  1. app.py +85 -60
app.py CHANGED
@@ -26,6 +26,37 @@ db = init_conn()
26
  player_roo_format = {'Top_finish': '{:.2%}','Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '2x%': '{:.2%}', '3x%': '{:.2%}',
27
  '4x%': '{:.2%}'}
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  @st.cache_resource(ttl=200)
30
  def player_stat_table():
31
  collection = db["Player_Level_ROO"]
@@ -58,13 +89,12 @@ t_stamp = f"Last Update: " + str(timestamp) + f" CST"
58
  tab1, tab2, tab3 = st.tabs(["Player Range of Outcomes", "Line Combo Range of Outcomes", "Power Play Range of Outcomes"])
59
 
60
  with tab1:
61
- col1, col2 = st.columns([1, 7])
62
- with col1:
63
  st.info(t_stamp)
64
  if st.button("Load/Reset Data", key='reset1'):
65
- st.cache_data.clear()
66
- player_frame, line_frame, pp_frame, timestamp = player_stat_table()
67
- t_stamp = f"Last Update: " + str(timestamp) + f" CST"
68
  site_var1 = st.radio("What table would you like to display?", ('Draftkings', 'Fanduel'), key='site_var1')
69
  main_var1 = st.radio("Main slate or secondary slate?", ('Main Slate', 'Secondary Slate'), key='main_var1')
70
  split_var1 = st.radio("Would you like to view the whole slate or just specific games?", ('Full Slate Run', 'Specific Games'), key='split_var1')
@@ -78,30 +108,28 @@ with tab1:
78
  elif pos_split1 == 'All Positions':
79
  pos_var1 = 'All'
80
  sal_var1 = st.slider("Is there a certain price range you want to view?", 2000, 10000, (2000, 20000), key='sal_var1')
81
-
82
- with col2:
83
- final_Proj = player_frame[player_frame['Site'] == str(site_var1)]
84
- final_Proj = final_Proj[final_Proj['Type'] == 'Basic']
85
- final_Proj = final_Proj[final_Proj['Slate'] == main_var1]
86
- final_Proj = final_Proj[player_frame['Team'].isin(team_var1)]
87
- final_Proj = final_Proj[final_Proj['Salary'] >= sal_var1[0]]
88
- final_Proj = final_Proj[final_Proj['Salary'] <= sal_var1[1]]
89
- if pos_var1 != 'All':
90
- final_Proj = final_Proj[final_Proj['Position'].str.contains('|'.join(pos_var1))]
91
- final_Proj = final_Proj.sort_values(by='Median', ascending=False)
92
- if pos_var1 == 'All':
93
- final_Proj = final_Proj.sort_values(by='Median', ascending=False)
94
- st.dataframe(final_Proj.iloc[:, :-3].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), use_container_width = True)
95
- st.download_button(
96
- label="Export Tables",
97
- data=convert_df_to_csv(final_Proj),
98
- file_name='NHL_player_export.csv',
99
- mime='text/csv',
100
- )
101
 
102
  with tab2:
103
- col1, col2 = st.columns([1, 7])
104
- with col1:
105
  st.info(t_stamp)
106
  if st.button("Load/Reset Data", key='reset2'):
107
  st.cache_data.clear()
@@ -110,26 +138,24 @@ with tab2:
110
  site_var2 = st.radio("What table would you like to display?", ('Draftkings', 'Fanduel'), key='site_var2')
111
  main_var2 = st.radio("Main slate or secondary slate?", ('Main Slate', 'Secondary Slate'), key='main_var2')
112
  sal_var2 = st.slider("Is there a certain price range you want to view?", 5000, 40000, (5000, 40000), key='sal_var2')
113
-
114
- with col2:
115
- final_line_combos = line_frame[line_frame['Site'] == str(site_var2)]
116
- final_line_combos = final_line_combos[final_line_combos['Type'] == 'Basic']
117
- final_line_combos = final_line_combos[final_line_combos['Slate'] == main_var2]
118
- final_line_combos = final_line_combos[final_line_combos['Salary'] >= sal_var2[0]]
119
- final_line_combos = final_line_combos[final_line_combos['Salary'] <= sal_var2[1]]
120
- final_line_combos = final_line_combos.drop_duplicates(subset=['Player'])
121
- final_line_combos = final_line_combos.sort_values(by='Median', ascending=False)
122
- st.dataframe(final_line_combos.iloc[:, :-3].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
123
- st.download_button(
124
- label="Export Tables",
125
- data=convert_df_to_csv(final_line_combos),
126
- file_name='NHL_linecombos_export.csv',
127
- mime='text/csv',
128
- )
129
 
130
  with tab3:
131
- col1, col2 = st.columns([1, 7])
132
- with col1:
133
  st.info(t_stamp)
134
  if st.button("Load/Reset Data", key='reset3'):
135
  st.cache_data.clear()
@@ -139,18 +165,17 @@ with tab3:
139
  main_var3 = st.radio("Main slate or secondary slate?", ('Main Slate', 'Secondary Slate'), key='main_var3')
140
  sal_var3 = st.slider("Is there a certain price range you want to view?", 5000, 40000, (5000, 40000), key='sal_var3')
141
 
142
- with col2:
143
- final_pp_combos = pp_frame[pp_frame['Site'] == str(site_var3)]
144
- final_pp_combos = final_pp_combos[final_pp_combos['Type'] == 'Basic']
145
- final_pp_combos = final_pp_combos[final_pp_combos['Slate'] == main_var3]
146
- final_pp_combos = final_pp_combos[final_pp_combos['Salary'] >= sal_var3[0]]
147
- final_pp_combos = final_pp_combos[final_pp_combos['Salary'] <= sal_var3[1]]
148
- final_pp_combos = final_pp_combos.drop_duplicates(subset=['Player'])
149
- final_pp_combos = final_pp_combos.sort_values(by='Median', ascending=False)
150
- st.dataframe(final_pp_combos.iloc[:, :-3].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
151
- st.download_button(
152
- label="Export Tables",
153
- data=convert_df_to_csv(final_pp_combos),
154
- file_name='NHL_powerplay_export.csv',
155
- mime='text/csv',
156
- )
 
26
  player_roo_format = {'Top_finish': '{:.2%}','Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '2x%': '{:.2%}', '3x%': '{:.2%}',
27
  '4x%': '{:.2%}'}
28
 
29
+ st.markdown("""
30
+ <style>
31
+ /* Tab styling */
32
+ .stTabs [data-baseweb="tab-list"] {
33
+ gap: 8px;
34
+ padding: 4px;
35
+ }
36
+
37
+ .stTabs [data-baseweb="tab"] {
38
+ height: 50px;
39
+ white-space: pre-wrap;
40
+ background-color: #FFD700;
41
+ color: white;
42
+ border-radius: 10px;
43
+ gap: 1px;
44
+ padding: 10px 20px;
45
+ font-weight: bold;
46
+ transition: all 0.3s ease;
47
+ }
48
+
49
+ .stTabs [aria-selected="true"] {
50
+ background-color: #DAA520;
51
+ color: white;
52
+ }
53
+
54
+ .stTabs [data-baseweb="tab"]:hover {
55
+ background-color: #DAA520;
56
+ cursor: pointer;
57
+ }
58
+ </style>""", unsafe_allow_html=True)
59
+
60
  @st.cache_resource(ttl=200)
61
  def player_stat_table():
62
  collection = db["Player_Level_ROO"]
 
89
  tab1, tab2, tab3 = st.tabs(["Player Range of Outcomes", "Line Combo Range of Outcomes", "Power Play Range of Outcomes"])
90
 
91
  with tab1:
92
+ with st.expander("Info and Filters"):
 
93
  st.info(t_stamp)
94
  if st.button("Load/Reset Data", key='reset1'):
95
+ st.cache_data.clear()
96
+ player_frame, line_frame, pp_frame, timestamp = player_stat_table()
97
+ t_stamp = f"Last Update: " + str(timestamp) + f" CST"
98
  site_var1 = st.radio("What table would you like to display?", ('Draftkings', 'Fanduel'), key='site_var1')
99
  main_var1 = st.radio("Main slate or secondary slate?", ('Main Slate', 'Secondary Slate'), key='main_var1')
100
  split_var1 = st.radio("Would you like to view the whole slate or just specific games?", ('Full Slate Run', 'Specific Games'), key='split_var1')
 
108
  elif pos_split1 == 'All Positions':
109
  pos_var1 = 'All'
110
  sal_var1 = st.slider("Is there a certain price range you want to view?", 2000, 10000, (2000, 20000), key='sal_var1')
111
+
112
+ final_Proj = player_frame[player_frame['Site'] == str(site_var1)]
113
+ final_Proj = final_Proj[final_Proj['Type'] == 'Basic']
114
+ final_Proj = final_Proj[final_Proj['Slate'] == main_var1]
115
+ final_Proj = final_Proj[player_frame['Team'].isin(team_var1)]
116
+ final_Proj = final_Proj[final_Proj['Salary'] >= sal_var1[0]]
117
+ final_Proj = final_Proj[final_Proj['Salary'] <= sal_var1[1]]
118
+ if pos_var1 != 'All':
119
+ final_Proj = final_Proj[final_Proj['Position'].str.contains('|'.join(pos_var1))]
120
+ final_Proj = final_Proj.sort_values(by='Median', ascending=False)
121
+ if pos_var1 == 'All':
122
+ final_Proj = final_Proj.sort_values(by='Median', ascending=False)
123
+ st.dataframe(final_Proj.iloc[:, :-3].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(player_roo_format, precision=2), use_container_width = True)
124
+ st.download_button(
125
+ label="Export Tables",
126
+ data=convert_df_to_csv(final_Proj),
127
+ file_name='NHL_player_export.csv',
128
+ mime='text/csv',
129
+ )
 
130
 
131
  with tab2:
132
+ with st.expander("Info and Filters"):
 
133
  st.info(t_stamp)
134
  if st.button("Load/Reset Data", key='reset2'):
135
  st.cache_data.clear()
 
138
  site_var2 = st.radio("What table would you like to display?", ('Draftkings', 'Fanduel'), key='site_var2')
139
  main_var2 = st.radio("Main slate or secondary slate?", ('Main Slate', 'Secondary Slate'), key='main_var2')
140
  sal_var2 = st.slider("Is there a certain price range you want to view?", 5000, 40000, (5000, 40000), key='sal_var2')
141
+
142
+ final_line_combos = line_frame[line_frame['Site'] == str(site_var2)]
143
+ final_line_combos = final_line_combos[final_line_combos['Type'] == 'Basic']
144
+ final_line_combos = final_line_combos[final_line_combos['Slate'] == main_var2]
145
+ final_line_combos = final_line_combos[final_line_combos['Salary'] >= sal_var2[0]]
146
+ final_line_combos = final_line_combos[final_line_combos['Salary'] <= sal_var2[1]]
147
+ final_line_combos = final_line_combos.drop_duplicates(subset=['Player'])
148
+ final_line_combos = final_line_combos.sort_values(by='Median', ascending=False)
149
+ st.dataframe(final_line_combos.iloc[:, :-3].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
150
+ st.download_button(
151
+ label="Export Tables",
152
+ data=convert_df_to_csv(final_line_combos),
153
+ file_name='NHL_linecombos_export.csv',
154
+ mime='text/csv',
155
+ )
 
156
 
157
  with tab3:
158
+ with st.expander("Info and Filters"):
 
159
  st.info(t_stamp)
160
  if st.button("Load/Reset Data", key='reset3'):
161
  st.cache_data.clear()
 
165
  main_var3 = st.radio("Main slate or secondary slate?", ('Main Slate', 'Secondary Slate'), key='main_var3')
166
  sal_var3 = st.slider("Is there a certain price range you want to view?", 5000, 40000, (5000, 40000), key='sal_var3')
167
 
168
+ final_pp_combos = pp_frame[pp_frame['Site'] == str(site_var3)]
169
+ final_pp_combos = final_pp_combos[final_pp_combos['Type'] == 'Basic']
170
+ final_pp_combos = final_pp_combos[final_pp_combos['Slate'] == main_var3]
171
+ final_pp_combos = final_pp_combos[final_pp_combos['Salary'] >= sal_var3[0]]
172
+ final_pp_combos = final_pp_combos[final_pp_combos['Salary'] <= sal_var3[1]]
173
+ final_pp_combos = final_pp_combos.drop_duplicates(subset=['Player'])
174
+ final_pp_combos = final_pp_combos.sort_values(by='Median', ascending=False)
175
+ st.dataframe(final_pp_combos.iloc[:, :-3].style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
176
+ st.download_button(
177
+ label="Export Tables",
178
+ data=convert_df_to_csv(final_pp_combos),
179
+ file_name='NHL_powerplay_export.csv',
180
+ mime='text/csv',
181
+ )