build a dashboard to showcase basketball data
To upload files, please first save the app
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from st_aggrid import AgGrid, GridOptionsBuilder
from datetime import datetime, timedelta
# Set page config
st.set_page_config(
page_title="Basketball Analytics Dashboard",
page_icon="🏀",
layout="wide"
)
# Generate sample basketball data
@st.cache_data
def generate_basketball_data():
np.random.seed(42)
# Teams
teams = ["Lakers", "Warriors", "Celtics", "Bulls", "Heat", "Nets", "Nuggets", "Clippers"]
# Generate player data
players_data = []
for i in range(150):
team = np.random.choice(teams)
position = np.random.choice(["PG", "SG", "SF", "PF", "C"])
# Generate realistic stats based on position
if position in ["PG", "SG"]:
points = np.random.normal(15, 8)
assists = np.random.normal(6, 3)
rebounds = np.random.normal(4, 2)
steals = np.random.normal(1.2, 0.8)
elif position == "SF":
points = np.random.normal(18, 6)
assists = np.random.normal(4, 2)
rebounds = np.random.normal(6, 2)
steals = np.random.normal(1.0, 0.6)
else: # PF, C
points = np.random.normal(12, 5)
assists = np.random.normal(2, 1)
rebounds = np.random.normal(9, 3)
steals = np.random.normal(0.7, 0.4)
# Ensure positive values
points = max(0, points)
assists = max(0, assists)
rebounds = max(0, rebounds)
steals = max(0, steals)
players_data.append({
"Player": f"Player_{i+1}",
"Team": team,
"Position": position,
"Points": round(points, 1),
"Assists": round(assists, 1),
"Rebounds": round(rebounds, 1),
"Steals": round(steals, 1),
"Minutes": round(np.random.normal(28, 8), 1),
"Field_Goal_Pct": round(np.random.normal(0.45, 0.08), 3),
"Age": np.random.randint(19, 38),
"Games_Played": np.random.randint(60, 82)
})
# Generate team stats
team_stats = []
for team in teams:
team_stats.append({
"Team": team,
"Wins": np.random.randint(25, 60),
"Losses": np.random.randint(22, 57),
"Win_Percentage": 0,
"Points_Per_Game": round(np.random.normal(110, 10), 1),
"Points_Allowed": round(np.random.normal(108, 8), 1),
"Rebounds_Per_Game": round(np.random.normal(45, 5), 1),
"Assists_Per_Game": round(np.random.normal(25, 4), 1)
})
# Calculate win percentage
for team in team_stats:
total_games = team["Wins"] + team["Losses"]
team["Win_Percentage"] = round(team["Wins"] / total_games, 3)
return pd.DataFrame(players_data), pd.DataFrame(team_stats)
# Load data
players_df, teams_df = generate_basketball_data()
# Dashboard title
st.title("🏀 Basketball Analytics Dashboard")
st.markdown("---")
# Sidebar for filters
st.sidebar.header("Filters")
selected_teams = st.sidebar.multiselect("Select Teams", teams_df["Team"].unique(), default=teams_df["Team"].unique())
selected_positions = st.sidebar.multiselect("Select Positions", players_df["Position"].unique(), default=players_df["Position"].unique())
# Filter data
filtered_players = players_df[
(players_df["Team"].isin(selected_teams)) &
(players_df["Position"].isin(selected_positions))
]
filtered_teams = teams_df[teams_df["Team"].isin(selected_teams)]
# Key Metrics Row
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Total Players", len(filtered_players))
with col2:
avg_points = filtered_players["Points"].mean()
st.metric("Avg Points/Game", f"{avg_points:.1f}")
with col3:
avg_assists = filtered_players["Assists"].mean()
st.metric("Avg Assists/Game", f"{avg_assists:.1f}")
with col4:
avg_rebounds = filtered_players["Rebounds"].mean()
st.metric("Avg Rebounds/Game", f"{avg_rebounds:.1f}")
st.markdown("---")
# Charts Row
col1, col2 = st.columns(2)
with col1:
st.subheader("Team Performance")
fig_teams = px.bar(
filtered_teams.sort_values("Win_Percentage", ascending=False),
x="Team",
y="Win_Percentage",
title="Team Win Percentage",
color="Win_Percentage",
color_continuous_scale="RdYlGn"
)
fig_teams.update_layout(height=400)
st.plotly_chart(fig_teams, use_container_width=True)
with col2:
st.subheader("Points vs Assists")
fig_scatter = px.scatter(
filtered_players,
x="Points",
y="Assists",
color="Position",
size="Minutes",
hover_data=["Player", "Team"],
title="Player Performance: Points vs Assists"
)
fig_scatter.update_layout(height=400)
st.plotly_chart(fig_scatter, use_container_width=True)
# Second row of charts
col1, col2 = st.columns(2)
with col1:
st.subheader("Position Distribution")
position_counts = filtered_players["Position"].value_counts()
fig_pie = px.pie(
values=position_counts.values,
names=position_counts.index,
title="Players by Position"
)
fig_pie.update_layout(height=400)
st.plotly_chart(fig_pie, use_container_width=True)
with col2:
st.subheader("Team Scoring")
fig_scoring = px.bar(
filtered_teams.sort_values("Points_Per_Game", ascending=False),
x="Team",
y=["Points_Per_Game", "Points_Allowed"],
title="Team Offensive vs Defensive Performance",
barmode="group"
)
fig_scoring.update_layout(height=400)
st.plotly_chart(fig_scoring, use_container_width=True)
st.markdown("---")
# Data Tables
tab1, tab2 = st.tabs(["Player Stats", "Team Stats"])
with tab1:
st.subheader("Player Statistics")
# Configure grid options for players
gb = GridOptionsBuilder.from_dataframe(filtered_players)
gb.configure_pagination(paginationAutoPageSize=True)
gb.configure_side_bar()
gb.configure_selection('multiple', use_checkbox=True)
gb.configure_default_column(groupable=True, value=True, enableRowGroup=True, editable=False)
# Configure specific columns
gb.configure_column("Points", type=["numericColumn", "numberColumnFilter"], precision=1)
gb.configure_column("Assists", type=["numericColumn", "numberColumnFilter"], precision=1)
gb.configure_column("Rebounds", type=["numericColumn", "numberColumnFilter"], precision=1)
gb.configure_column("Field_Goal_Pct", type=["numericColumn", "numberColumnFilter"], precision=3)
gridOptions = gb.build()
grid_response = AgGrid(
filtered_players,
gridOptions=gridOptions,
data_return_mode='FILTERED_AND_SORTED',
update_mode='MODEL_CHANGED',
fit_columns_on_grid_load=True,
enable_enterprise_modules=True,
height=400,
width='100%'
)
with tab2:
st.subheader("Team Statistics")
# Configure grid options for teams
gb_teams = GridOptionsBuilder.from_dataframe(filtered_teams)
gb_teams.configure_pagination(paginationAutoPageSize=True)
gb_teams.configure_selection('single', use_checkbox=True)
gb_teams.configure_default_column(groupable=True, value=True, enableRowGroup=True, editable=False)
# Configure specific columns
gb_teams.configure_column("Win_Percentage", type=["numericColumn", "numberColumnFilter"], precision=3)
gb_teams.configure_column("Points_Per_Game", type=["numericColumn", "numberColumnFilter"], precision=1)
gb_teams.configure_column("Points_Allowed", type=["numericColumn", "numberColumnFilter"], precision=1)
gridOptions_teams = gb_teams.build()
grid_response_teams = AgGrid(
filtered_teams,
gridOptions=gridOptions_teams,
data_return_mode='FILTERED_AND_SORTED',
update_mode='MODEL_CHANGED',
fit_columns_on_grid_load=True,
enable_enterprise_modules=True,
height=300,
width='100%'
)
# Footer
st.markdown("---")
st.markdown("### Dashboard Features")
st.markdown("""
- **Interactive Filtering**: Use the sidebar to filter by teams and positions
- **Dynamic Visualizations**: Charts update based on your filters
- **Sortable Data Tables**: Click column headers to sort, use filters for detailed analysis
- **Multi-select Capability**: Select multiple rows in the player stats table for comparison
- **Responsive Design**: Dashboard adapts to different screen sizes
""")
st.markdown("*Data is simulated for demonstration purposes*")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?