Update src/streamlit_app.py
Browse files- src/streamlit_app.py +38 -21
src/streamlit_app.py
CHANGED
|
@@ -243,6 +243,20 @@ def player_vs_player():
|
|
| 243 |
seasons = get_available_seasons()
|
| 244 |
selected_seasons = st.multiselect("Select Seasons", seasons, default=[seasons[0]] if seasons else [])
|
| 245 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
if st.button("Run Comparison"):
|
| 247 |
if not selected_players:
|
| 248 |
st.warning("Please select at least one player.")
|
|
@@ -251,14 +265,18 @@ def player_vs_player():
|
|
| 251 |
all_data, no_data = [], []
|
| 252 |
with st.spinner("Fetching player data..."):
|
| 253 |
for p in selected_players:
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
|
|
|
|
|
|
|
|
|
| 259 |
else:
|
| 260 |
no_data.append(p)
|
| 261 |
-
|
|
|
|
| 262 |
no_data.append(p)
|
| 263 |
|
| 264 |
if no_data:
|
|
@@ -272,7 +290,7 @@ def player_vs_player():
|
|
| 272 |
|
| 273 |
with tabs[0]:
|
| 274 |
st.subheader("Basic Statistics")
|
| 275 |
-
if len(selected_seasons)>1:
|
| 276 |
df_b = comp_df.groupby('Player').mean(numeric_only=True).reset_index()
|
| 277 |
cols = ['Player','GP','MIN','PTS','REB','AST','STL','BLK','FG_PCT','FT_PCT','FG3_PCT']
|
| 278 |
else:
|
|
@@ -283,19 +301,19 @@ def player_vs_player():
|
|
| 283 |
with tabs[1]:
|
| 284 |
st.subheader("Advanced Statistics")
|
| 285 |
df_a = comp_df.copy()
|
| 286 |
-
df_a['FGA'] = pd.to_numeric(df_a.get('FGA',0), errors='coerce').fillna(0)
|
| 287 |
-
df_a['FTA'] = pd.to_numeric(df_a.get('FTA',0), errors='coerce').fillna(0)
|
| 288 |
-
df_a['PTS'] = pd.to_numeric(df_a.get('PTS',0), errors='coerce').fillna(0)
|
| 289 |
df_a['TS_PCT'] = df_a.apply(
|
| 290 |
-
lambda r: r['PTS']/(2*(r['FGA']+0.44*r['FTA'])) if (r['FGA']+0.44*r['FTA']) else 0,
|
| 291 |
axis=1
|
| 292 |
)
|
| 293 |
-
if len(selected_seasons)>1:
|
| 294 |
df_adv = df_a.groupby('Player').mean(numeric_only=True).reset_index()
|
| 295 |
-
cols = ['Player','PTS','REB','AST','FG_PCT','TS_PCT']
|
| 296 |
else:
|
| 297 |
df_adv = df_a.copy()
|
| 298 |
-
cols = ['Player','Season','PTS','REB','AST','FG_PCT','TS_PCT']
|
| 299 |
st.dataframe(df_adv[[c for c in cols if c in df_adv.columns]].round(3), use_container_width=True)
|
| 300 |
|
| 301 |
with tabs[2]:
|
|
@@ -303,8 +321,8 @@ def player_vs_player():
|
|
| 303 |
metrics = [m for m in ['PTS','REB','AST','FG_PCT','FG3_PCT','FT_PCT','STL','BLK'] if m in comp_df.columns]
|
| 304 |
if metrics:
|
| 305 |
m = st.selectbox("Select Metric", metrics)
|
| 306 |
-
if len(selected_players)==1 and len(selected_seasons)>1:
|
| 307 |
-
trend = comp_df[comp_df['Player']==selected_players[0]].sort_values('Season')
|
| 308 |
fig = px.line(trend, x='Season', y=m, markers=True,
|
| 309 |
title=f"{selected_players[0]} β {m} Trend")
|
| 310 |
else:
|
|
@@ -312,16 +330,15 @@ def player_vs_player():
|
|
| 312 |
fig = px.bar(avg, x='Player', y=m, title=f"Average {m} Comparison")
|
| 313 |
st.plotly_chart(fig, use_container_width=True)
|
| 314 |
|
| 315 |
-
# Radar
|
| 316 |
cats = [c for c in ['PTS','REB','AST','STL','BLK'] if c in comp_df.columns]
|
| 317 |
-
if len(cats)>=3:
|
| 318 |
src = (comp_df.groupby('Player')[cats].mean(numeric_only=True).reset_index()
|
| 319 |
-
if len(selected_seasons)>1 else comp_df.copy())
|
| 320 |
scaled = src.copy()
|
| 321 |
for c in cats:
|
| 322 |
mn, mx = scaled[c].min(), scaled[c].max()
|
| 323 |
-
scaled[c] = ((scaled[c]-mn)/(mx-mn)*100) if mx>mn else 0
|
| 324 |
-
radar = {r['Player']:{c:r[c] for c in cats} for _,r in scaled.iterrows()}
|
| 325 |
st.plotly_chart(create_radar_chart(radar, cats), use_container_width=True)
|
| 326 |
else:
|
| 327 |
st.info("Need β₯3 metrics for radar chart.")
|
|
|
|
| 243 |
seasons = get_available_seasons()
|
| 244 |
selected_seasons = st.multiselect("Select Seasons", seasons, default=[seasons[0]] if seasons else [])
|
| 245 |
|
| 246 |
+
# βββ DEBUG PREVIEW ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 247 |
+
if selected_players:
|
| 248 |
+
st.markdown("### π§ͺ Raw Data Preview (Before Filtering)")
|
| 249 |
+
for player in selected_players:
|
| 250 |
+
try:
|
| 251 |
+
raw_df = get_player_career_stats_brscraper(player)
|
| 252 |
+
st.subheader(f"{player} β Raw Data")
|
| 253 |
+
st.write("Columns:", raw_df.columns.tolist())
|
| 254 |
+
st.dataframe(raw_df, use_container_width=True)
|
| 255 |
+
except Exception as e:
|
| 256 |
+
st.error(f"β Error fetching data for {player}: {e}")
|
| 257 |
+
st.markdown("---")
|
| 258 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 259 |
+
|
| 260 |
if st.button("Run Comparison"):
|
| 261 |
if not selected_players:
|
| 262 |
st.warning("Please select at least one player.")
|
|
|
|
| 265 |
all_data, no_data = [], []
|
| 266 |
with st.spinner("Fetching player data..."):
|
| 267 |
for p in selected_players:
|
| 268 |
+
try:
|
| 269 |
+
df = get_player_career_stats_brscraper(p)
|
| 270 |
+
if not df.empty:
|
| 271 |
+
filt = df[df['Season'].isin(selected_seasons)]
|
| 272 |
+
if not filt.empty:
|
| 273 |
+
all_data.append(filt)
|
| 274 |
+
else:
|
| 275 |
+
no_data.append(p)
|
| 276 |
else:
|
| 277 |
no_data.append(p)
|
| 278 |
+
except Exception as e:
|
| 279 |
+
st.error(f"Error fetching stats for {p}: {e}")
|
| 280 |
no_data.append(p)
|
| 281 |
|
| 282 |
if no_data:
|
|
|
|
| 290 |
|
| 291 |
with tabs[0]:
|
| 292 |
st.subheader("Basic Statistics")
|
| 293 |
+
if len(selected_seasons) > 1:
|
| 294 |
df_b = comp_df.groupby('Player').mean(numeric_only=True).reset_index()
|
| 295 |
cols = ['Player','GP','MIN','PTS','REB','AST','STL','BLK','FG_PCT','FT_PCT','FG3_PCT']
|
| 296 |
else:
|
|
|
|
| 301 |
with tabs[1]:
|
| 302 |
st.subheader("Advanced Statistics")
|
| 303 |
df_a = comp_df.copy()
|
| 304 |
+
df_a['FGA'] = pd.to_numeric(df_a.get('FGA', 0), errors='coerce').fillna(0)
|
| 305 |
+
df_a['FTA'] = pd.to_numeric(df_a.get('FTA', 0), errors='coerce').fillna(0)
|
| 306 |
+
df_a['PTS'] = pd.to_numeric(df_a.get('PTS', 0), errors='coerce').fillna(0)
|
| 307 |
df_a['TS_PCT'] = df_a.apply(
|
| 308 |
+
lambda r: r['PTS'] / (2 * (r['FGA'] + 0.44 * r['FTA'])) if (r['FGA'] + 0.44 * r['FTA']) else 0,
|
| 309 |
axis=1
|
| 310 |
)
|
| 311 |
+
if len(selected_seasons) > 1:
|
| 312 |
df_adv = df_a.groupby('Player').mean(numeric_only=True).reset_index()
|
| 313 |
+
cols = ['Player', 'PTS', 'REB', 'AST', 'FG_PCT', 'TS_PCT']
|
| 314 |
else:
|
| 315 |
df_adv = df_a.copy()
|
| 316 |
+
cols = ['Player', 'Season', 'PTS', 'REB', 'AST', 'FG_PCT', 'TS_PCT']
|
| 317 |
st.dataframe(df_adv[[c for c in cols if c in df_adv.columns]].round(3), use_container_width=True)
|
| 318 |
|
| 319 |
with tabs[2]:
|
|
|
|
| 321 |
metrics = [m for m in ['PTS','REB','AST','FG_PCT','FG3_PCT','FT_PCT','STL','BLK'] if m in comp_df.columns]
|
| 322 |
if metrics:
|
| 323 |
m = st.selectbox("Select Metric", metrics)
|
| 324 |
+
if len(selected_players) == 1 and len(selected_seasons) > 1:
|
| 325 |
+
trend = comp_df[comp_df['Player'] == selected_players[0]].sort_values('Season')
|
| 326 |
fig = px.line(trend, x='Season', y=m, markers=True,
|
| 327 |
title=f"{selected_players[0]} β {m} Trend")
|
| 328 |
else:
|
|
|
|
| 330 |
fig = px.bar(avg, x='Player', y=m, title=f"Average {m} Comparison")
|
| 331 |
st.plotly_chart(fig, use_container_width=True)
|
| 332 |
|
|
|
|
| 333 |
cats = [c for c in ['PTS','REB','AST','STL','BLK'] if c in comp_df.columns]
|
| 334 |
+
if len(cats) >= 3:
|
| 335 |
src = (comp_df.groupby('Player')[cats].mean(numeric_only=True).reset_index()
|
| 336 |
+
if len(selected_seasons) > 1 else comp_df.copy())
|
| 337 |
scaled = src.copy()
|
| 338 |
for c in cats:
|
| 339 |
mn, mx = scaled[c].min(), scaled[c].max()
|
| 340 |
+
scaled[c] = ((scaled[c] - mn) / (mx - mn) * 100) if mx > mn else 0
|
| 341 |
+
radar = {r['Player']: {c: r[c] for c in cats} for _, r in scaled.iterrows()}
|
| 342 |
st.plotly_chart(create_radar_chart(radar, cats), use_container_width=True)
|
| 343 |
else:
|
| 344 |
st.info("Need β₯3 metrics for radar chart.")
|