|
""" |
|
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("---") |
|
|
|
|
|
if 'dashboard_data' not in st.session_state: |
|
st.session_state.dashboard_data = generate_sample_data() |
|
|
|
|
|
with st.sidebar: |
|
st.header("Dashboard Controls") |
|
|
|
|
|
if st.button("π Refresh Data"): |
|
st.session_state.dashboard_data = generate_sample_data() |
|
st.success("Data refreshed!") |
|
|
|
|
|
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 = st.selectbox( |
|
"Chart Type", |
|
["Line Chart", "Bar Chart", "Area Chart", "Scatter Plot"] |
|
) |
|
|
|
|
|
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 |
|
|
|
|
|
dates = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D') |
|
|
|
|
|
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 |
|
|
|
|
|
total_sales = data['sales'].sum() |
|
total_users = data['users'].sum() |
|
total_revenue = data['revenue'].sum() |
|
avg_conversion = data['conversion_rate'].mean() |
|
|
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
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": |
|
|
|
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: |
|
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) |
|
|
|
|
|
st.write("**Multi-Metric Trend Analysis**") |
|
|
|
|
|
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 |
|
|
|
|
|
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())) |
|
|
|
|
|
filtered_data = data[ |
|
(data['sales'] >= min_sales) & |
|
(data['users'] >= min_users) & |
|
(data['revenue'] >= min_revenue) |
|
] |
|
|
|
|
|
st.write(f"Showing {len(filtered_data)} of {len(data)} records") |
|
|
|
|
|
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" |
|
} |
|
) |
|
|
|
|
|
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") |
|
|
|
|
|
stats = data[['sales', 'users', 'revenue', 'conversion_rate']].describe() |
|
|
|
|
|
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") |
|
} |
|
) |
|
|
|
|
|
|
|
@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': |
|
|
|
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, |
|
'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') |