############ Imports ##############
import vizro.plotly.express as px
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 vizro.figures as vf
from vizro.figures import kpi_card
import vizro.plotly.express as px
from vizro.models.types import capture
####### Function definitions ######
@capture("figure")
def tip_percentage_by_size(data_frame):
"""
Create box plot of tip percentage by party size and time
"""
df = data_frame.copy()
df["tip_percentage"] = (df["tip"] / df["total_bill"]) * 100
fig = px.box(
df, x="size", y="tip_percentage", color="time", points="outliers", title=""
)
fig.update_layout(
xaxis_title="Party Size", yaxis_title="Tip Percentage (%)", showlegend=True
)
return fig
@capture("figure")
def calculate_tip_percentage_kpi(data_frame):
"""
Calculate average tip percentage and display as KPI card
"""
df = data_frame.copy()
df["tip_percentage"] = (df["tip"] / df["total_bill"]) * 100
avg_tip_pct = df["tip_percentage"].mean()
return kpi_card(
data_frame=df,
value_column="tip_percentage",
agg_func="mean",
value_format="{value:.1f}%",
title="Avg Tip %",
icon="percent",
)
####### Data Manager Settings #####
data_manager["tips_data"] = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/tips.csv"
)
########### Model code ############
model = vm.Dashboard(
pages=[
vm.Page(
components=[
vm.Figure(
id="avg_tip_kpi",
type="figure",
figure=vf.kpi_card(
data_frame="tips_data",
value_column="tip",
value_format="${value:.2f}",
agg_func="mean",
title="Average Tip",
icon="attach_money",
),
),
vm.Figure(
id="avg_bill_kpi",
type="figure",
figure=vf.kpi_card(
data_frame="tips_data",
value_column="total_bill",
value_format="${value:.2f}",
agg_func="mean",
title="Average Bill",
icon="receipt",
),
),
vm.Figure(
id="tip_percentage_kpi",
type="figure",
figure=calculate_tip_percentage_kpi(data_frame="tips_data"),
),
vm.Figure(
id="total_revenue_kpi",
type="figure",
figure=vf.kpi_card(
data_frame="tips_data",
value_column="total_bill",
value_format="${value:,.0f}",
agg_func="sum",
title="Total Revenue",
icon="trending_up",
),
),
vm.Graph(
id="tip_vs_bill_scatter",
type="graph",
figure=px.scatter(
data_frame="tips_data",
x="total_bill",
y="tip",
color="sex",
size="size",
hover_data=["day", "time"],
opacity=0.7,
trendline="ols",
),
title="π° Tip Amount vs Total Bill - The Tipping Sweet Spot",
),
vm.Graph(
id="tip_by_day_bar",
type="graph",
figure=px.bar(
data_frame="tips_data",
x="day",
y="tip",
color="sex",
category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]},
barmode="group",
),
title="π
Tip Patterns Throughout the Week",
),
vm.Graph(
id="tip_distribution_violin",
type="graph",
figure=px.violin(
data_frame="tips_data",
x="sex",
y="tip",
color="smoker",
points="outliers",
box=True,
),
title="π» Tip Distribution - Gender & Smoking Impact",
),
vm.Graph(
id="party_size_analysis",
type="graph",
figure=tip_percentage_by_size(data_frame="tips_data"),
title="π₯ Party Size Impact on Tips",
),
vm.Graph(
id="bill_size_heatmap",
type="graph",
figure=px.density_heatmap(
data_frame="tips_data",
x="day",
y="size",
z="total_bill",
histfunc="avg",
text_auto=True,
),
title="π₯ Bill Amounts Heatmap - Day vs Party Size",
),
],
title="Tips Analytics Overview",
layout=vm.Grid(
type="grid",
grid=[[0, 1, 2, 3], [4, 4, 5, 5], [6, 7, 8, 8]],
row_gap="16px",
col_gap="16px",
row_min_height="200px",
),
controls=[
vm.Filter(
id="time_filter",
type="filter",
column="time",
targets=[
"tip_vs_bill_scatter",
"tip_by_day_bar",
"tip_distribution_violin",
"bill_size_heatmap",
],
selector=vm.Dropdown(type="dropdown", multi=True),
),
vm.Filter(
id="smoker_filter",
type="filter",
column="smoker",
targets=[
"tip_vs_bill_scatter",
"tip_by_day_bar",
"tip_distribution_violin",
"bill_size_heatmap",
],
selector=vm.Dropdown(type="dropdown", multi=True),
),
],
)
],
theme="vizro_dark",
title="π½οΈ Restaurant Tips Analytics Dashboard",
)
Vizro().build(model).run()