mona / pages /dashboard.py
mrradix's picture
Update pages/dashboard.py
b84426c verified
"""
Dashboard page for the application
"""
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime, timedelta
from utils.storage import load_data, save_data, load_dataframe, save_dataframe
from utils.error_handling import handle_data_exceptions, log_error, display_error
@handle_data_exceptions
def create_dashboard_page():
"""
Create the main dashboard page
"""
st.title("πŸ“Š Dashboard")
st.markdown("---")
# Initialize session state
if 'dashboard_data' not in st.session_state:
st.session_state.dashboard_data = generate_sample_data()
# Sidebar controls
with st.sidebar:
st.header("Dashboard Controls")
# Data refresh button
if st.button("πŸ”„ Refresh Data"):
st.session_state.dashboard_data = generate_sample_data()
st.success("Data refreshed!")
# Date range selector
st.subheader("Date Range")
start_date = st.date_input("Start Date", value=datetime.now() - timedelta(days=30))
end_date = st.date_input("End Date", value=datetime.now())
# Chart type selector
chart_type = st.selectbox(
"Chart Type",
["Line Chart", "Bar Chart", "Area Chart", "Scatter Plot"]
)
# Main dashboard content
create_metrics_section()
create_charts_section(chart_type)
create_data_table_section()
def generate_sample_data():
"""
Generate sample data for the dashboard
"""
import random
import numpy as np
# Generate date range
dates = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')
# Generate sample metrics
data = {
'date': dates,
'sales': [random.randint(1000, 5000) + random.randint(-500, 500) for _ in dates],
'users': [random.randint(100, 1000) + random.randint(-100, 100) for _ in dates],
'revenue': [random.randint(5000, 25000) + random.randint(-2000, 2000) for _ in dates],
'conversion_rate': [round(random.uniform(0.02, 0.08), 4) for _ in dates]
}
return pd.DataFrame(data)
def create_metrics_section():
"""
Create metrics cards section
"""
st.subheader("πŸ“ˆ Key Metrics")
data = st.session_state.dashboard_data
# Calculate metrics
total_sales = data['sales'].sum()
total_users = data['users'].sum()
total_revenue = data['revenue'].sum()
avg_conversion = data['conversion_rate'].mean()
# Previous period comparison (last 30 days vs previous 30 days)
recent_data = data.tail(30)
previous_data = data.iloc[-60:-30] if len(data) >= 60 else data.head(30)
sales_change = ((recent_data['sales'].sum() - previous_data['sales'].sum()) / previous_data['sales'].sum()) * 100
users_change = ((recent_data['users'].sum() - previous_data['users'].sum()) / previous_data['users'].sum()) * 100
revenue_change = ((recent_data['revenue'].sum() - previous_data['revenue'].sum()) / previous_data['revenue'].sum()) * 100
conversion_change = ((recent_data['conversion_rate'].mean() - previous_data['conversion_rate'].mean()) / previous_data['conversion_rate'].mean()) * 100
# Display metrics in columns
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric(
label="Total Sales",
value=f"{total_sales:,}",
delta=f"{sales_change:.1f}%"
)
with col2:
st.metric(
label="Total Users",
value=f"{total_users:,}",
delta=f"{users_change:.1f}%"
)
with col3:
st.metric(
label="Total Revenue",
value=f"${total_revenue:,}",
delta=f"{revenue_change:.1f}%"
)
with col4:
st.metric(
label="Avg Conversion Rate",
value=f"{avg_conversion:.2%}",
delta=f"{conversion_change:.1f}%"
)
def create_charts_section(chart_type):
"""
Create charts section
"""
st.subheader("πŸ“Š Analytics Charts")
data = st.session_state.dashboard_data
# Create two columns for charts
col1, col2 = st.columns(2)
with col1:
st.write("**Sales Over Time**")
if chart_type == "Line Chart":
fig = px.line(data, x='date', y='sales', title='Daily Sales')
elif chart_type == "Bar Chart":
# Group by month for bar chart
monthly_data = data.groupby(data['date'].dt.to_period('M'))['sales'].sum().reset_index()
monthly_data['date'] = monthly_data['date'].astype(str)
fig = px.bar(monthly_data, x='date', y='sales', title='Monthly Sales')
elif chart_type == "Area Chart":
fig = px.area(data, x='date', y='sales', title='Sales Area Chart')
else: # Scatter Plot
fig = px.scatter(data, x='date', y='sales', title='Sales Scatter Plot')
fig.update_layout(height=400)
st.plotly_chart(fig, use_container_width=True)
with col2:
st.write("**Revenue vs Users**")
fig2 = px.scatter(
data,
x='users',
y='revenue',
size='sales',
color='conversion_rate',
title='Revenue vs Users (sized by Sales)',
color_continuous_scale='Viridis'
)
fig2.update_layout(height=400)
st.plotly_chart(fig2, use_container_width=True)
# Full width chart
st.write("**Multi-Metric Trend Analysis**")
# Normalize data for comparison
normalized_data = data.copy()
for col in ['sales', 'users', 'revenue']:
normalized_data[f'{col}_normalized'] = (normalized_data[col] - normalized_data[col].min()) / (normalized_data[col].max() - normalized_data[col].min())
fig3 = go.Figure()
fig3.add_trace(go.Scatter(x=normalized_data['date'], y=normalized_data['sales_normalized'], name='Sales (Normalized)'))
fig3.add_trace(go.Scatter(x=normalized_data['date'], y=normalized_data['users_normalized'], name='Users (Normalized)'))
fig3.add_trace(go.Scatter(x=normalized_data['date'], y=normalized_data['revenue_normalized'], name='Revenue (Normalized)'))
fig3.update_layout(
title='Normalized Trends Comparison',
xaxis_title='Date',
yaxis_title='Normalized Value (0-1)',
height=400
)
st.plotly_chart(fig3, use_container_width=True)
def create_data_table_section():
"""
Create data table section
"""
st.subheader("πŸ“‹ Data Table")
data = st.session_state.dashboard_data
# Add filters
col1, col2, col3 = st.columns(3)
with col1:
min_sales = st.number_input("Min Sales", value=0, max_value=int(data['sales'].max()))
with col2:
min_users = st.number_input("Min Users", value=0, max_value=int(data['users'].max()))
with col3:
min_revenue = st.number_input("Min Revenue", value=0, max_value=int(data['revenue'].max()))
# Filter data
filtered_data = data[
(data['sales'] >= min_sales) &
(data['users'] >= min_users) &
(data['revenue'] >= min_revenue)
]
# Display filtered data
st.write(f"Showing {len(filtered_data)} of {len(data)} records")
# Format data for display
display_data = filtered_data.copy()
display_data['date'] = display_data['date'].dt.strftime('%Y-%m-%d')
display_data['revenue'] = display_data['revenue'].apply(lambda x: f"${x:,}")
display_data['conversion_rate'] = display_data['conversion_rate'].apply(lambda x: f"{x:.2%}")
st.dataframe(
display_data,
use_container_width=True,
hide_index=True,
column_config={
"date": "Date",
"sales": st.column_config.NumberColumn("Sales", format="%d"),
"users": st.column_config.NumberColumn("Users", format="%d"),
"revenue": "Revenue",
"conversion_rate": "Conversion Rate"
}
)
# Download button
csv = data.to_csv(index=False)
st.download_button(
label="πŸ“₯ Download Data as CSV",
data=csv,
file_name=f"dashboard_data_{datetime.now().strftime('%Y%m%d')}.csv",
mime="text/csv"
)
def create_summary_statistics():
"""
Create summary statistics section
"""
data = st.session_state.dashboard_data
st.subheader("πŸ“Š Summary Statistics")
# Calculate statistics
stats = data[['sales', 'users', 'revenue', 'conversion_rate']].describe()
# Display statistics table
st.dataframe(
stats,
use_container_width=True,
column_config={
"sales": st.column_config.NumberColumn("Sales", format="%.0f"),
"users": st.column_config.NumberColumn("Users", format="%.0f"),
"revenue": st.column_config.NumberColumn("Revenue", format="%.0f"),
"conversion_rate": st.column_config.NumberColumn("Conversion Rate", format="%.4f")
}
)
# Additional utility functions
@handle_data_exceptions
def export_dashboard_data(format_type='csv'):
"""
Export dashboard data in specified format
"""
data = st.session_state.dashboard_data
if format_type == 'csv':
return data.to_csv(index=False)
elif format_type == 'json':
return data.to_json(orient='records', date_format='iso')
elif format_type == 'excel':
# This would require openpyxl
return data.to_excel(index=False)
else:
raise ValueError(f"Unsupported format: {format_type}")
@handle_data_exceptions
def load_dashboard_config():
"""
Load dashboard configuration
"""
try:
config = load_data('dashboard_config.json')
return config if config else get_default_config()
except:
return get_default_config()
def get_default_config():
"""
Get default dashboard configuration
"""
return {
'theme': 'light',
'default_chart_type': 'Line Chart',
'refresh_interval': 300, # 5 minutes
'show_metrics': True,
'show_charts': True,
'show_table': True
}
@handle_data_exceptions
def save_dashboard_config(config):
"""
Save dashboard configuration
"""
return save_data(config, 'dashboard_config.json')