############ Imports ##############
import vizro.plotly.express as px
import vizro.tables as vt
import vizro.models as vm
from vizro.models.types import capture
from vizro import Vizro
import pandas as pd
from vizro.managers import data_manager
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import vizro.plotly.express as px
from vizro.models.types import capture
####### Function definitions ######
@capture("graph")
def customer_segment_chart(data_frame):
# Aggregate by customer segment and product category
segment_data = (
data_frame.groupby(["Customer Segment", "Product Category"])
.agg({"Sales": "sum", "Profit": "sum"})
.reset_index()
)
# Create sunburst
fig = go.Figure(
go.Sunburst(
labels=segment_data["Product Category"],
parents=segment_data["Customer Segment"],
values=segment_data["Sales"],
hovertemplate="<b>%{label}</b><br>"
+ "Customer Segment: %{parent}<br>"
+ "Sales: $%{value:,.0f}<br>"
+ "Profit: $%{customdata:,.0f}<br>"
+ "<extra></extra>",
customdata=segment_data["Profit"],
maxdepth=2,
insidetextorientation="radial",
)
)
# Update layout
fig.update_layout(margin=dict(t=20, l=0, r=0, b=0))
return fig
@capture("graph")
def geographic_sales_chart(data_frame):
# Aggregate by continent and region
geo_data = (
data_frame.groupby(["Continent", "Region"])
.agg({"Sales": "sum", "Profit": "sum"})
.reset_index()
)
# Create treemap
fig = go.Figure(
go.Treemap(
labels=geo_data["Region"],
parents=geo_data["Continent"],
values=geo_data["Sales"],
text=geo_data["Region"],
textinfo="label+value",
hovertemplate="<b>%{label}</b><br>"
+ "Continent: %{parent}<br>"
+ "Sales: $%{value:,.0f}<br>"
+ "Profit: $%{customdata:,.0f}<br>"
+ "<extra></extra>",
customdata=geo_data["Profit"],
textfont_size=12,
pathbar_visible=False,
)
)
# Update layout
fig.update_layout(margin=dict(t=20, l=0, r=0, b=0))
return fig
@capture("graph")
def sales_profit_timeline(data_frame):
# Convert Order Date to datetime and extract year-month
df = data_frame.copy()
df["Order Date"] = pd.to_datetime(df["Order Date"])
df["Year_Month"] = df["Order Date"].dt.to_period("M")
# Aggregate by month
monthly_data = (
df.groupby("Year_Month").agg({"Sales": "sum", "Profit": "sum"}).reset_index()
)
# Convert Period to string for plotting
monthly_data["Year_Month"] = monthly_data["Year_Month"].astype(str)
# Create subplot with secondary y-axis
fig = make_subplots(
specs=[[{"secondary_y": True}]],
subplot_titles=["Sales and Profit Trends Over Time"],
)
# Add Sales trace
fig.add_trace(
go.Scatter(
x=monthly_data["Year_Month"],
y=monthly_data["Sales"],
mode="lines+markers",
name="Sales",
line=dict(color="#1f77b4", width=2),
hovertemplate="<b>Sales</b><br>"
+ "Month: %{x}<br>"
+ "Sales: $%{y:,.0f}<br>"
+ "<extra></extra>",
),
secondary_y=False,
)
# Add Profit trace
fig.add_trace(
go.Scatter(
x=monthly_data["Year_Month"],
y=monthly_data["Profit"],
mode="lines+markers",
name="Profit",
line=dict(color="#ff7f0e", width=2),
hovertemplate="<b>Profit</b><br>"
+ "Month: %{x}<br>"
+ "Profit: $%{y:,.0f}<br>"
+ "<extra></extra>",
),
secondary_y=True,
)
# Update layout
fig.update_layout(
xaxis_title="Time Period",
hovermode="x unified",
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
)
# Update y-axes
fig.update_yaxes(title_text="Sales ($)", secondary_y=False)
fig.update_yaxes(title_text="Profit ($)", secondary_y=True)
return fig
@capture("graph")
def category_performance_chart(data_frame):
# Aggregate by product category
category_data = (
data_frame.groupby("Product Category")
.agg({"Sales": "sum", "Profit": "sum", "Order Quantity": "sum"})
.reset_index()
)
# Create figure
fig = go.Figure()
# Add Sales bars
fig.add_trace(
go.Bar(
name="Sales",
x=category_data["Product Category"],
y=category_data["Sales"],
marker_color="#1f77b4",
hovertemplate="<b>%{x}</b><br>"
+ "Sales: $%{y:,.0f}<br>"
+ "<extra></extra>",
)
)
# Add Profit bars
fig.add_trace(
go.Bar(
name="Profit",
x=category_data["Product Category"],
y=category_data["Profit"],
marker_color="#ff7f0e",
hovertemplate="<b>%{x}</b><br>"
+ "Profit: $%{y:,.0f}<br>"
+ "<extra></extra>",
)
)
# Update layout
fig.update_layout(
barmode="group",
xaxis_title="Product Category",
yaxis_title="Amount ($)",
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
)
return fig
####### Data Manager Settings #####
data_manager["megastore_data"] = pd.read_excel(
"https://raw.githubusercontent.com/stichbury/vizro_projects/main/Megastore/MegastoreData.xlsx"
)
########### Model code ############
model = vm.Dashboard(
pages=[
vm.Page(
id="home",
components=[
vm.Card(
type="card",
text="## Overview\nExplore the complete MegaStore dataset with summary statistics and raw data.",
href="/overview",
),
vm.Card(
type="card",
text="## Distribution Analysis\nAnalyze the distribution of numeric columns with interactive histograms.",
href="/distribution",
),
vm.Card(
type="card",
text="## Advanced Analysis\nDeep dive into business insights with custom visualizations.",
href="/advanced",
),
],
title="Home",
),
vm.Page(
id="overview",
components=[
vm.Text(
type="text",
text="## MegaStore Dataset Summary\n\nThis dataset contains **16,798 records** of sales data from a global retail store with the following key characteristics:\n\n- **Geographic Coverage**: Sales across North America, Europe, and Asia\n- **Product Categories**: Office Supplies, Furniture, and Technology\n- **Customer Segments**: Corporate, Consumer, and Small Business\n- **Time Period**: Sales data spanning multiple years\n- **Key Metrics**: Sales, Profit, Discount, Shipping Cost, and more\n\nThe dataset includes both transactional details and customer information, making it ideal for comprehensive business analysis.",
),
vm.AgGrid(
type="ag_grid",
figure=vt.dash_ag_grid(
data_frame="megastore_data",
dashGridOptions={"pagination": True, "paginationPageSize": 20},
),
title="Raw Data",
),
],
title="Overview",
),
vm.Page(
id="distribution",
components=[
vm.Graph(
id="hist_chart",
type="graph",
figure=px.histogram(
data_frame="megastore_data", x="Sales", nbins=50
),
title="Distribution Analysis",
)
],
title="Distribution Analysis",
controls=[
vm.Parameter(
type="parameter",
targets=["hist_chart.x"],
selector=vm.Dropdown(
type="dropdown",
options=[
"Sales",
"Profit",
"Discount",
"Order Quantity",
"Unit Price",
"Shipping Cost",
"Product Base Margin",
],
value="Sales",
),
),
vm.Filter(
type="filter",
column="Product Category",
targets=["hist_chart"],
selector=vm.Dropdown(type="dropdown", multi=True),
),
vm.Filter(
type="filter",
column="Customer Segment",
targets=["hist_chart"],
selector=vm.Dropdown(type="dropdown", multi=True),
),
vm.Filter(
type="filter",
column="Continent",
targets=["hist_chart"],
selector=vm.Dropdown(type="dropdown", multi=True),
),
vm.Filter(
type="filter",
column="Order Priority",
targets=["hist_chart"],
selector=vm.Dropdown(type="dropdown", multi=True),
),
],
),
vm.Page(
id="advanced",
components=[
vm.Graph(
id="sales_profit_time",
type="graph",
figure=sales_profit_timeline(data_frame="megastore_data"),
title="Sales and Profit Trends Over Time",
),
vm.Graph(
id="category_performance",
type="graph",
figure=category_performance_chart(data_frame="megastore_data"),
title="Product Category Performance",
),
vm.Graph(
id="geographic_sales",
type="graph",
figure=geographic_sales_chart(data_frame="megastore_data"),
title="Geographic Sales Distribution",
),
vm.Graph(
id="customer_segment",
type="graph",
figure=customer_segment_chart(data_frame="megastore_data"),
title="Customer Segment Analysis",
),
],
title="Advanced Analysis",
layout=vm.Grid(type="grid", grid=[[0, 1], [2, 3]]),
),
],
theme="vizro_dark",
navigation=vm.Navigation(
pages=["home", "overview", "distribution", "advanced"],
nav_selector=vm.NavBar(
type="nav_bar",
items=[
vm.NavLink(pages=["home"], label="Home", icon="home"),
vm.NavLink(pages=["overview"], label="Overview", icon="info"),
vm.NavLink(
pages=["distribution"], label="Distribution", icon="bar_chart"
),
vm.NavLink(pages=["advanced"], label="Advanced", icon="trending_up"),
],
),
),
title="MegaStore Analytics Dashboard",
)
Vizro().build(model).run()