import dash
from dash import Input, Output, html, dcc
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
import numpy as np
# Sample sales dataset
data = {
'Transaction_ID': range(1, 101),
'Date': pd.date_range(start='2023-01-01', periods=100, freq='D'),
'Product_Category': ['Loan', 'Savings', 'Insurance'] * 33 + ['Loan'],
'Region': ['North', 'South', 'East', 'West'] * 25,
'Sale_Amount': [round(abs(x), 2) for x in pd.Series(np.random.randn(100) * 1000 + 5000)]
}
df = pd.DataFrame(data)
# Initialize Dash app
app = dash.Dash(__name__)
# Custom CSS style (moved here from html.Style)
card_style = {
'border': '1px solid #ddd',
'borderRadius': '10px',
'padding': '20px',
'margin': '10px',
'textAlign': 'center',
'boxShadow': '2px 2px 12px #aaa',
'flex': '1'
}
# App layout
app.layout = html.Div([
html.H1("Microfinance Sales Dashboard", style={'textAlign': 'center', 'color': 'blue'}),
# Filters
html.Div([
html.Div([
html.Label("Select Region:"),
dcc.Dropdown(
id='region-filter',
options=[{'label': region, 'value': region} for region in df['Region'].unique()],
multi=True,
value=df['Region'].unique().tolist()
),
], style={'flex': '1'}),
html.Div([
html.Label("Select Product Category:"),
dcc.Dropdown(
id='category-filter',
options=[{'label': category, 'value': category} for category in df['Product_Category'].unique()],
multi=True,
value=df['Product_Category'].unique().tolist()
),
], style={'flex': '1'}),
html.Div([
html.Label("Select Date Range:"),
dcc.DatePickerRange(
id='date-filter',
start_date=df['Date'].min(),
end_date=df['Date'].max(),
display_format='YYYY-MM-DD'
),
], style={'flex': '1'}),
], style={'display': 'flex', 'gap': '20px', 'margin': '20px'}),
# Metrics Cards
html.Div([
html.Div([
html.H3("Total Sales"),
html.P(id='total-sales')
], style=card_style),
html.Div([
html.H3("Average Sale Amount"),
html.P(id='avg-sales')
], style=card_style),
html.Div([
html.H3("Total Transactions"),
html.P(id='transaction-count')
], style=card_style),
], style={'display': 'flex', 'justifyContent': 'space-around'}),
# Visualizations with full-screen support
html.Div([
dcc.Graph(id='sales-trend', config={'displayModeBar': True, 'displaylogo': False}),
dcc.Graph(id='sales-category', config={'displayModeBar': True, 'displaylogo': False}),
dcc.Graph(id='sales-region', config={'displayModeBar': True, 'displaylogo': False}),
]),
])
# Callback to update charts and metrics
@app.callback(
[Output('sales-trend', 'figure'),
Output('sales-category', 'figure'),
Output('sales-region', 'figure'),
Output('total-sales', 'children'),
Output('avg-sales', 'children'),
Output('transaction-count', 'children')],
[Input('region-filter', 'value'),
Input('category-filter', 'value'),
Input('date-filter', 'start_date'),
Input('date-filter', 'end_date')]
)
def update_dashboard(selected_regions, selected_categories, start_date, end_date):
# Filter data
filtered_df = df[
(df['Region'].isin(selected_regions)) &
(df['Product_Category'].isin(selected_categories)) &
(df['Date'] >= pd.to_datetime(start_date)) &
(df['Date'] <= pd.to_datetime(end_date))
]
# Metrics
total_sales = filtered_df['Sale_Amount'].sum()
avg_sales = filtered_df['Sale_Amount'].mean()
transaction_count = filtered_df.shape[0]
# Sales trend over time
fig_trend = px.line(filtered_df, x='Date', y='Sale_Amount', title='Sales Trend Over Time')
# Sales by product category
fig_category = px.bar(filtered_df, x='Product_Category', y='Sale_Amount', title='Sales by Product Category',
color='Product_Category')
# Sales by region (pie chart)
fig_region = px.pie(filtered_df, names='Region', values='Sale_Amount', title='Sales by Region')
# Metric card content
total_sales_text = f"${total_sales:,.2f}"
avg_sales_text = f"${avg_sales:,.2f}" if transaction_count > 0 else "$0.00"
transaction_count_text = f"{transaction_count}"
return fig_trend, fig_category, fig_region, total_sales_text, avg_sales_text, transaction_count_text
# Run app
if __name__ == '__main__':
app.run_server(debug=False)