"""Dev app to try things out."""
import vizro.actions as va
import vizro.models as vm
from charts import (
bar_chart_by_category,
overview_by_customer_segment,
overview_by_month,
overview_by_order_status,
overview_by_product_category,
overview_by_region,
pareto_customers_chart,
regions_map_chart,
regions_top_n_chart,
scatter_with_quadrants,
)
from data_processing import (
COLUMN_TO_AGGFUNC,
COLUMN_TO_METRIC,
LAST_YEAR,
THIS_YEAR,
make_superstore_df,
make_superstore_profit_df,
)
from tables import COLUMN_DEFS_PRODUCT, customers_ag_grid, orders_ag_grid
from vizro import Vizro
from vizro.figures import kpi_card_reference
from vizro.tables import dash_ag_grid
###############################################################################
# Dataframes and utility functions
###############################################################################
df = make_superstore_df()
profit_df = make_superstore_profit_df(df)
def create_filled_container(**kwargs):
return vm.Container(**kwargs, variant="filled")
###############################################################################
# Overview page
###############################################################################
def create_kpi_card_with_action(data_frame, column, icon, prefix=""):
"""Create a KPI card figure that updates the metric control when clicked."""
# Pivot and aggregate to produce dataframe with column for each year for specified metric.
data_frame = data_frame.pivot_table(values=column, columns="Year", aggfunc=COLUMN_TO_AGGFUNC[column])
return vm.Figure(
figure=kpi_card_reference(
data_frame=data_frame,
value_column=THIS_YEAR, # This year
reference_column=LAST_YEAR, # Last year
value_format=f"{prefix}{{value:,.0f}}",
reference_format=f"{{delta_relative:+.1%}} vs. last year ({prefix}{{reference:,.0f}})",
title=COLUMN_TO_METRIC[column],
icon=icon,
),
actions=va.set_control(control="metric", value=column),
)
def create_chart_container_with_nav(graph, nav_href):
"""Create a container with a chart and optional navigation button."""
components = [graph, vm.Button(text="View Deep Dive", icon="Jump to Element", variant="outlined", href=nav_href)]
return create_filled_container(components=components, layout=vm.Grid(grid=[[0]] * 5 + [[1]], row_gap="8px"))
# TODO: chart title spacing, use container.title?
kpi_card_container = vm.Container(
id="kpi-cards",
title="π‘ Click on a KPI card to update the charts below.",
layout=vm.Grid(grid=[[0, 1, 2, 3]]),
components=[
create_kpi_card_with_action(df, column="Sales", icon="Bar Chart", prefix="$"),
create_kpi_card_with_action(df, column="Profit", icon="Money Bag", prefix="$"),
create_kpi_card_with_action(df, column="Order ID", icon="Orders"),
create_kpi_card_with_action(df, column="Customer ID", icon="Group"),
],
)
overview_page = vm.Page(
title="Overview",
# Grid that consists of rows with height ratio 3:5:5.
layout=vm.Grid(grid=[[0, 0, 0]] * 3 + [[1, 1, 2]] * 5 + [[3, 4, 5]] * 5),
components=[
kpi_card_container,
create_filled_container(
components=[vm.Graph(id="month_line_chart", figure=overview_by_month(df, column="Sales"))]
),
create_chart_container_with_nav(
graph=vm.Graph(id="order_status_pie_chart", figure=overview_by_order_status(df, column="Sales")),
nav_href="/orders",
),
create_chart_container_with_nav(
graph=vm.Graph(id="region_bar_chart", figure=overview_by_region(df, column="Sales")),
nav_href="/regions",
),
create_chart_container_with_nav(
graph=vm.Graph(id="segment_bar_chart", figure=overview_by_customer_segment(df, column="Sales")),
nav_href="/customers",
),
create_chart_container_with_nav(
graph=vm.Graph(id="category_bar_chart", figure=overview_by_product_category(df, column="Sales")),
nav_href="/products",
),
],
controls=[
vm.Parameter(
id="metric",
selector=vm.RadioItems(options=["Sales", "Profit", "Order ID", "Customer ID"]),
targets=[
"region_bar_chart.column",
"category_bar_chart.column",
"order_status_pie_chart.column",
"month_line_chart.column",
"segment_bar_chart.column",
],
visible=False,
)
],
)
###############################################################################
# Regions page
###############################################################################
map_container = create_filled_container(
components=[
vm.Graph(
id="usa_map",
header="π‘ Click on a state to filter ranked bars on the right.",
figure=regions_map_chart(df, column="Sales", custom_data=["State Code"]),
actions=va.set_control(control="state_filter", value="State Code"),
)
],
)
regions_top_n_chart_container = create_filled_container(
components=[vm.Graph(id="regions_top_n_chart", figure=regions_top_n_chart(df, x="Sales", y="City", n=20))],
controls=[
vm.Parameter(
targets=["regions_top_n_chart.n"], selector=vm.Slider(min=5, max=30, step=5, value=20, title="Choose top N")
),
vm.Parameter(
targets=["regions_top_n_chart.y"],
selector=vm.RadioItems(options=["City", "Customer Name", "Sub-Category"], title="Choose y-axis"),
),
],
)
regions_page = vm.Page(
title="Regions",
components=[
vm.Container(
layout=vm.Grid(grid=[[0, 1]]),
components=[map_container, regions_top_n_chart_container],
controls=[
vm.Filter(id="state_filter", column="State Code", visible=False),
vm.Filter(column="Segment", selector=vm.Checklist(title="Choose segment")),
vm.Filter(column="Category", selector=vm.Checklist(title="Choose category")),
vm.Parameter(
targets=["usa_map.column", "regions_top_n_chart.x"],
selector=vm.RadioItems(options=["Sales", "Profit"], title="Choose metric"),
),
],
)
],
)
# TODO: highlight state instead of filter?
###############################################################################
# Products page
###############################################################################
product_category_container = create_filled_container(
components=[
vm.Graph(
id="product_category_bar",
figure=bar_chart_by_category(df, custom_data=["Category"]),
actions=va.set_control(control="product_category_filter", value="Category"),
)
],
controls=[vm.Filter(id="product_category_filter", column="Category", visible=False)],
)
product_table_container = create_filled_container(
components=[
vm.AgGrid(
header="π‘ Click on a row to highlight the data point in the matrix on the right.",
figure=dash_ag_grid(profit_df, columnDefs=COLUMN_DEFS_PRODUCT),
actions=va.set_control(control="quadrant_subcategory", value="Sub-Category"),
)
],
)
profit_vs_sales_container = create_filled_container(
components=[
vm.Graph(
id="profit_vs_sales_chart",
figure=scatter_with_quadrants(
profit_df,
x="Sales",
y="Profit",
custom_data=["Sub-Category"],
),
)
],
controls=[
vm.Parameter(
id="quadrant_subcategory",
targets=["profit_vs_sales_chart.highlight_sub_category"],
selector=vm.Dropdown(options=["NONE", *df["Sub-Category"]], multi=False),
visible=False,
),
],
)
# TODO: bar chart into histogram
# TODO: fix quadrant highlight
products_page = vm.Page(
title="Products",
components=[
vm.Container(
layout=vm.Grid(grid=[[0, 2], [1, 2], [1, 2]]),
components=[product_category_container, product_table_container, profit_vs_sales_container],
)
],
)
###############################################################################
# Customers page
###############################################################################
customers_page = vm.Page(
title="Customers",
components=[
vm.Container(
layout=vm.Grid(grid=[[0, 1]]),
components=[
vm.AgGrid(
header="π‘ Click on a row to highlight the customer.",
figure=customers_ag_grid(df),
actions=va.set_control(control="customer_parameter", value="Customer Name"),
),
vm.Graph(id="pareto_chart", figure=pareto_customers_chart(df)),
],
controls=[
vm.Filter(column="Region", selector=vm.Checklist(title="Choose region")),
vm.Filter(column="Segment", selector=vm.Checklist(title="Choose segment")),
vm.Filter(column="Category", selector=vm.Checklist(title="Choose category")),
vm.Parameter(
id="customer_parameter",
targets=["pareto_chart.highlight_customer"],
selector=vm.RadioItems(options=["NONE", *df["Customer Name"]]),
visible=False,
),
],
)
],
)
###############################################################################
# Orders page
###############################################################################
orders_page = vm.Page(
title="Orders",
layout=vm.Flex(),
components=[
vm.AgGrid(figure=orders_ag_grid(df)),
vm.Button(text="Export data", icon="download", actions=va.export_data(file_format="xlsx")),
],
)
###############################################################################
# Overall dashboard configuration
###############################################################################
pages = {
"Home": overview_page,
"Globe Asia": regions_page,
"Barcode": products_page,
"Group": customers_page,
"Shopping Cart": orders_page,
}
navigation = vm.Navigation(
nav_selector=vm.NavBar(
items=[vm.NavLink(pages=[page.id], label=page.title, icon=icon) for icon, page in pages.items()]
),
)
dashboard = vm.Dashboard(title="Superstore dashboard", pages=pages.values(), navigation=navigation, theme="vizro_light")
Vizro().build(dashboard).run()