""" 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')