diff --git a/.github/images/huggingface_collection.png b/.github/images/huggingface_collection.png
new file mode 100644
index 000000000..e45d4ef60
Binary files /dev/null and b/.github/images/huggingface_collection.png differ
diff --git a/.github/images/vizro_examples_gallery.png b/.github/images/vizro_examples_gallery.png
new file mode 100644
index 000000000..1875d1bde
Binary files /dev/null and b/.github/images/vizro_examples_gallery.png differ
diff --git a/README.md b/README.md
index 5c7f79223..035facc56 100644
--- a/README.md
+++ b/README.md
@@ -104,7 +104,7 @@ You can see Vizro in action by clicking on the following image or by visiting [t
-
+
## Dashboard screenshots
diff --git a/vizro-core/changelog.d/20240826_141315_huong_li_nguyen_remove_kpi_dashboard.md b/vizro-core/changelog.d/20240826_141315_huong_li_nguyen_remove_kpi_dashboard.md
new file mode 100644
index 000000000..f1f65e73c
--- /dev/null
+++ b/vizro-core/changelog.d/20240826_141315_huong_li_nguyen_remove_kpi_dashboard.md
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
diff --git a/vizro-core/examples/README.md b/vizro-core/examples/README.md
new file mode 100644
index 000000000..72146bfb7
--- /dev/null
+++ b/vizro-core/examples/README.md
@@ -0,0 +1,20 @@
+## Examples
+
+Please note that this folder contains only example dashboards that are still **in development**.
+
+### Vizro examples gallery
+
+To view a comprehensive list of available demos, please visit our [examples gallery](http://vizro.mckinsey.com/).
+There, you can explore a wide range of dashboards and applications created with Vizro.
+
+
+
+
+
+### Huggingface collection
+
+For a curated list of example dashboards, check out our [dashboard collection on Huggingface](https://huggingface.co/collections/vizro/vizro-official-gallery-66697d414646eeac61eae6de).
+
+
+
+
diff --git a/vizro-core/examples/kpi/README.md b/vizro-core/examples/kpi/README.md
deleted file mode 100644
index 22d3ed4cd..000000000
--- a/vizro-core/examples/kpi/README.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# KPI Dashboard
-
-This dashboard provides an example of a Key Performance Indicator (KPI) dashboard, designed to help users get started
-and extend further. It uses fictional budget data to demonstrate the capabilities of Vizro using real world applications.
-
-**Created by:** [Huong Li Nguyen](https://github.com/huong-li-nguyen)
-
----
-
-### ๐๏ธ Data
-
-Special thanks to the [#RWFD Real World Fake Data initiative](https://data.world/markbradbourne/rwfd-real-world-fake-data), a community project that
-provides high-quality fake data for creating realistic dashboard examples for real-world applications.
-
-**Note:** The data has been additionally edited for the purpose of this example.
-
-### ๐ Plotly resources
-
-- [Bar charts](https://plotly.com/python/bar-charts/)
-- [Pie charts](https://plotly.com/python/pie-charts/)
-- [Choropleth maps](https://plotly.com/python/choropleth-maps/)
-- [Unstacked area charts](https://plotly.com/python/filled-area-plots/)
-
-### ๐ Vizro features applied
-
-- [Vizro tutorial on pages, layouts and dashboards](https://vizro.readthedocs.io/en/stable/pages/tutorials/explore-components/)
-- [Custom components](https://vizro.readthedocs.io/en/stable/pages/user-guides/custom-components/)
-- [Custom charts](https://vizro.readthedocs.io/en/stable/pages/user-guides/custom-charts/)
-- [Custom CSS](https://vizro.readthedocs.io/en/stable/pages/user-guides/assets/)
-
-### ๐ฅ๏ธ App demo
-
-
-
----
-
-## How to run the example locally
-
-1. Run the `app.py` file with your environment activated where `vizro` is installed.
-2. You should now be able to access the app locally via http://127.0.0.1:8050/.
diff --git a/vizro-core/examples/kpi/app.py b/vizro-core/examples/kpi/app.py
deleted file mode 100644
index d46e76a6d..000000000
--- a/vizro-core/examples/kpi/app.py
+++ /dev/null
@@ -1,251 +0,0 @@
-"""Example to show dashboard configuration."""
-
-import pandas as pd
-import vizro.models as vm
-from utils._charts import COLUMN_DEFS, FlexContainer, area, bar, choropleth, pie
-from utils._helper import clean_data_and_add_columns, create_data_for_kpi_cards
-from vizro import Vizro
-from vizro.actions import filter_interaction
-from vizro.figures import kpi_card_reference
-from vizro.tables import dash_ag_grid
-
-# DATA --------------------------------------------------------------------------------------------
-df_complaints = pd.read_csv("https://query.data.world/s/glbdstahsuw3hjgunz3zssggk7dsfu?dws=00000")
-df_complaints = clean_data_and_add_columns(df_complaints)
-df_kpi_cards = create_data_for_kpi_cards(df_complaints)
-vm.Page.add_type("components", FlexContainer)
-
-
-# SUB-SECTIONS ------------------------------------------------------------------------------------
-kpi_banner = FlexContainer(
- components=[
- vm.Figure(
- id="kpi-reverse-coloring",
- figure=kpi_card_reference(
- df_kpi_cards,
- value_column="Total Complaints_2019",
- reference_column="Total Complaints_2018",
- title="Total Complaints",
- value_format="{value:.0f}",
- reference_format="{delta_relative:+.1%} vs. 2018 ({reference:.0f})",
- icon="person",
- ),
- ),
- vm.Figure(
- figure=kpi_card_reference(
- df_kpi_cards,
- value_column="Closed Complaints_2019",
- reference_column="Closed Complaints_2018",
- title="Closed Complaints",
- value_format="{value:.1f}%",
- reference_format="{delta:+.1f}pp vs. 2018 ({reference:.1f}%)",
- icon="inventory",
- )
- ),
- vm.Figure(
- figure=kpi_card_reference(
- df_kpi_cards,
- value_column="Timely response_2019",
- reference_column="Timely response_2018",
- title="Timely Response",
- value_format="{value:.1f}%",
- reference_format="{delta:+.1f}pp vs. 2018 ({reference:.1f}%)",
- icon="timer",
- )
- ),
- vm.Figure(
- figure=kpi_card_reference(
- df_kpi_cards,
- value_column="Closed w/o cost_2019",
- reference_column="Closed w/o cost_2018",
- title="Closed w/o cost",
- value_format="{value:.1f}%",
- reference_format="{delta:.1f}pp vs. 2018 ({reference:.1f}%)",
- icon="payments",
- )
- ),
- vm.Figure(
- figure=kpi_card_reference(
- df_kpi_cards,
- value_column="Consumer disputed_2019",
- reference_column="Consumer disputed_2018",
- title="Consumer disputed",
- value_format="{value:.1f}%",
- reference_format="{delta:+.1f}pp vs. 2018 ({reference:.1f}%)",
- icon="sentiment_dissatisfied",
- )
- ),
- ],
- classname="kpi-banner",
-)
-
-bar_charts_tabbed = vm.Tabs(
- tabs=[
- vm.Container(
- title="By Product",
- components=[
- vm.Graph(
- figure=bar(
- data_frame=df_complaints,
- y="Product",
- x="Complaint ID",
- ),
- )
- ],
- ),
- vm.Container(
- title="By Channel",
- components=[
- vm.Graph(
- figure=bar(
- data_frame=df_complaints,
- y="Channel",
- x="Complaint ID",
- ),
- )
- ],
- ),
- vm.Container(
- title="By Region",
- components=[
- vm.Graph(
- figure=bar(
- data_frame=df_complaints,
- y="Region",
- x="Complaint ID",
- ),
- )
- ],
- ),
- vm.Container(
- title="By Issue",
- components=[
- vm.Graph(
- figure=bar(
- data_frame=df_complaints,
- y="Issue",
- x="Complaint ID",
- ),
- )
- ],
- ),
- ],
-)
-
-# PAGES --------------------------------------------------------------------------------------
-page_exec = vm.Page(
- title="Executive View",
- layout=vm.Layout(
- grid=[
- [0, 0],
- [0, 0],
- [1, 2],
- [1, 2],
- [1, 2],
- [1, 3],
- [1, 3],
- [1, 3],
- ],
- ),
- components=[
- kpi_banner,
- bar_charts_tabbed,
- vm.Graph(figure=area(data_frame=df_complaints, y="Complaint ID", x="Month")),
- vm.Graph(
- figure=pie(
- data_frame=df_complaints[df_complaints["Company response - Closed"] != "Not closed"],
- values="Complaint ID",
- names="Company response - Closed",
- title="Closed company responses",
- )
- ),
- ],
-)
-
-page_region = vm.Page(
- title="Regional View",
- layout=vm.Layout(grid=[[0, 1]]),
- components=[
- vm.Graph(
- figure=choropleth(
- data_frame=df_complaints,
- locations="State",
- color="Complaint ID",
- title="Complaints by State โคต Click on a state to filter the "
- "charts on the right. Refresh the page to deselect. ",
- custom_data=["State"],
- ),
- actions=[
- vm.Action(
- function=filter_interaction(targets=["regional-issue", "regional-product"]),
- )
- ],
- ),
- vm.Tabs(
- tabs=[
- vm.Container(
- title="By Product",
- components=[
- vm.Graph(
- id="regional-product",
- figure=bar(
- data_frame=df_complaints,
- y="Product",
- x="Complaint ID",
- ),
- )
- ],
- ),
- vm.Container(
- title="By Issue",
- components=[
- vm.Graph(
- id="regional-issue",
- figure=bar(
- data_frame=df_complaints,
- y="Issue",
- x="Complaint ID",
- ),
- )
- ],
- ),
- ],
- ),
- ],
- controls=[
- vm.Filter(column="Region", selector=vm.Checklist()),
- vm.Filter(column="State"),
- vm.Filter(column="Product"),
- vm.Filter(column="Issue"),
- ],
-)
-
-page_table = vm.Page(
- title="List of complaints",
- components=[
- vm.AgGrid(
- figure=dash_ag_grid(
- data_frame=df_complaints,
- columnDefs=COLUMN_DEFS,
- dashGridOptions={"pagination": True},
- )
- )
- ],
-)
-
-dashboard = vm.Dashboard(
- pages=[page_exec, page_region, page_table],
- title="Cumulus Financial Corp. - Fiscal Year 2019",
- navigation=vm.Navigation(
- nav_selector=vm.NavBar(
- items=[
- vm.NavLink(label="Executive View", icon="Leaderboard", pages=["Executive View"]),
- vm.NavLink(label="Regional View", icon="South America", pages=["Regional View"]),
- vm.NavLink(label="Table View", icon="Table View", pages=["List of complaints"]),
- ]
- )
- ),
-)
-
-if __name__ == "__main__":
- Vizro().build(dashboard).run()
diff --git a/vizro-core/examples/kpi/assets/css/custom.css b/vizro-core/examples/kpi/assets/css/custom.css
deleted file mode 100644
index 1117dcaef..000000000
--- a/vizro-core/examples/kpi/assets/css/custom.css
+++ /dev/null
@@ -1,40 +0,0 @@
-#page-header {
- padding-left: 4px;
-}
-
-.card-kpi {
- min-width: 220px;
- padding: 0.75rem;
-}
-
-.kpi-banner {
- display: flex;
- gap: 1rem;
- height: 100%;
- overflow: scroll;
-}
-
-.kpi-banner .figure-container {
- height: unset;
-}
-
-.kpi-banner::-webkit-scrollbar-thumb {
- border: 5px solid var(--main-container-bg-color);
-}
-
-/* Apply reverse color coding for one KPI card */
-#kpi-reverse-coloring .card-kpi .color-pos.card-footer {
- color: var(--bs-pink);
-}
-
-#kpi-reverse-coloring .card-kpi .color-neg.card-footer {
- color: var(--bs-blue);
-}
-
-#kpi-reverse-coloring .card-kpi:has(.color-pos) {
- border-left: 4px solid var(--bs-pink);
-}
-
-#kpi-reverse-coloring .card-kpi:has(.color-neg) {
- border-left: 4px solid var(--bs-blue);
-}
diff --git a/vizro-core/examples/kpi/assets/favicon.ico b/vizro-core/examples/kpi/assets/favicon.ico
deleted file mode 100644
index 240c9f541..000000000
Binary files a/vizro-core/examples/kpi/assets/favicon.ico and /dev/null differ
diff --git a/vizro-core/examples/kpi/assets/images/app.svg b/vizro-core/examples/kpi/assets/images/app.svg
deleted file mode 100644
index 9d07d6372..000000000
--- a/vizro-core/examples/kpi/assets/images/app.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/vizro-core/examples/kpi/assets/images/logo.svg b/vizro-core/examples/kpi/assets/images/logo.svg
deleted file mode 100644
index 0904b87de..000000000
--- a/vizro-core/examples/kpi/assets/images/logo.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/vizro-core/examples/kpi/images/kpi-dashboard.gif b/vizro-core/examples/kpi/images/kpi-dashboard.gif
deleted file mode 100644
index 39b0b188d..000000000
Binary files a/vizro-core/examples/kpi/images/kpi-dashboard.gif and /dev/null differ
diff --git a/vizro-core/examples/kpi/utils/__init__.py b/vizro-core/examples/kpi/utils/__init__.py
deleted file mode 100644
index 11387ccac..000000000
--- a/vizro-core/examples/kpi/utils/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Utils folder to contain helper functions and custom charts/components."""
diff --git a/vizro-core/examples/kpi/utils/_charts.py b/vizro-core/examples/kpi/utils/_charts.py
deleted file mode 100644
index 7b8be2985..000000000
--- a/vizro-core/examples/kpi/utils/_charts.py
+++ /dev/null
@@ -1,204 +0,0 @@
-"""Contains custom components and charts used inside the dashboard."""
-
-from typing import List, Literal, Optional
-
-import pandas as pd
-import plotly.graph_objects as go
-import vizro.models as vm
-import vizro.plotly.express as px
-from dash import html
-from vizro.models.types import capture
-
-
-# CUSTOM COMPONENTS -------------------------------------------------------------
-class FlexContainer(vm.Container):
- """Custom flex `Container`."""
-
- type: Literal["flex_container"] = "flex_container"
- title: str = None # Title exists in vm.Container but we don't want to use it here.
- classname: str = "d-flex"
-
- def build(self):
- """Returns a flex container."""
- return html.Div(
- id=self.id, children=[component.build() for component in self.components], className=self.classname
- )
-
-
-# CUSTOM CHARTS ----------------------------------------------------------------
-@capture("graph")
-def bar(
- x: str,
- y: str,
- data_frame: pd.DataFrame,
- top_n: int = 15,
- custom_data: Optional[List[str]] = None,
-):
- """Custom bar chart implementation.
-
- Based on [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar).
- """
- df_agg = data_frame.groupby(y).agg({x: "count"}).sort_values(by=x, ascending=False).reset_index()
- fig = px.bar(
- data_frame=df_agg.head(top_n),
- x=x,
- y=y,
- orientation="h",
- text=x,
- color_discrete_sequence=["#1A85FF"],
- custom_data=custom_data,
- )
- fig.update_layout(xaxis_title="# of Complaints", yaxis={"title": "", "autorange": "reversed"})
- return fig
-
-
-@capture("graph")
-def area(x: str, y: str, data_frame: pd.DataFrame):
- """Custom chart to create unstacked area chart.
-
- Based on [go.Scatter](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Scatter.html).
-
- """
- df_agg = data_frame.groupby(["Year", "Month"]).agg({y: "count"}).reset_index()
- df_agg_2019 = df_agg[df_agg["Year"] == "2018"]
- df_agg_2020 = df_agg[df_agg["Year"] == "2019"]
-
- fig = go.Figure()
- fig.add_trace(
- go.Scatter(x=df_agg_2020[x], y=df_agg_2020[y], fill="tozeroy", name="2019", marker={"color": "#1a85ff"})
- )
- fig.add_trace(go.Scatter(x=df_agg_2019[x], y=df_agg_2019[y], fill="tonexty", name="2018", marker={"color": "grey"}))
- fig.update_layout(
- title="Complaints over time",
- xaxis_title="Date Received",
- yaxis_title="# of Complaints",
- title_pad_t=4,
- xaxis={
- "showgrid": False,
- "tickmode": "array",
- "tickvals": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
- "ticktext": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
- },
- )
- return fig
-
-
-@capture("graph")
-def pie(
- names: str,
- values: str,
- data_frame: pd.DataFrame = None,
- title: Optional[str] = None,
-):
- """Custom pie chart implementation.
-
- Based on [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie).
- """
- df_agg = data_frame.groupby(names).agg({values: "count"}).reset_index()
- fig = px.pie(
- data_frame=df_agg,
- names=names,
- values=values,
- color=names,
- color_discrete_map={
- "Closed with explanation": "#1a85ff",
- "Closed with monetary relief": "#d41159",
- "Closed with non-monetary relief": "#adbedc",
- "Closed without relief": "#7ea1ee",
- "Closed with relief": "#df658c",
- "Closed": "#1a85ff",
- },
- title=title,
- hole=0.4,
- )
- fig.update_layout(legend_x=1, legend_y=1, title_pad_t=2, margin={"l": 0, "r": 0, "t": 60, "b": 0})
- return fig
-
-
-@capture("graph")
-def choropleth(
- locations: str,
- color: str,
- data_frame: pd.DataFrame = None,
- title: Optional[str] = None,
- custom_data: Optional[List[str]] = None,
-):
- """Custom choropleth implementation.
-
- Based on [px.choropleth](https://plotly.com/python-api-reference/generated/plotly.express.choropleth).
- """
- df_agg = data_frame.groupby(locations).agg({color: "count"}).reset_index()
- fig = px.choropleth(
- data_frame=df_agg,
- locations=locations,
- color=color,
- color_continuous_scale=[
- "#ded6d8",
- "#f3bdcb",
- "#f7a9be",
- "#f894b1",
- "#f780a3",
- "#f46b94",
- "#ee517f",
- "#e94777",
- "#e43d70",
- "#df3168",
- "#d92460",
- "#d41159",
- ],
- scope="usa",
- locationmode="USA-states",
- title=title,
- custom_data=custom_data,
- )
- fig.update_coloraxes(colorbar={"thickness": 10, "title": {"side": "bottom"}, "orientation": "h", "x": 0.5, "y": 0})
- return fig
-
-
-# TABLE CONFIGURATIONS ---------------------------------------------------------
-CELL_STYLE = {
- "styleConditions": [
- {
- "condition": "params.value == 'Closed with explanation'",
- "style": {"backgroundColor": "#1a85ff"},
- },
- {
- "condition": "params.value == 'Closed with monetary relief'",
- "style": {"backgroundColor": "#d41159"},
- },
- {
- "condition": "params.value == 'Closed with non-monetary relief'",
- "style": {"backgroundColor": "#adbedc"},
- },
- {
- "condition": "params.value == 'Closed without relief'",
- "style": {"backgroundColor": "#7ea1ee"},
- },
- {
- "condition": "params.value == 'Closed with relief'",
- "style": {"backgroundColor": "#df658c"},
- },
- {
- "condition": "params.value == 'Closed'",
- "style": {"backgroundColor": "#1a85ff"},
- },
- ]
-}
-
-
-COLUMN_DEFS = [
- {"field": "Complaint ID", "cellDataType": "text", "headerName": "ID", "flex": 3},
- {"field": "Date Received", "cellDataType": "text", "headerName": "Date", "flex": 3},
- {"field": "Channel", "cellDataType": "text", "flex": 3},
- {"field": "State", "cellDataType": "text", "flex": 2},
- {"field": "Product", "cellDataType": "text", "flex": 5},
- {"field": "Issue", "cellDataType": "text", "flex": 5},
- {
- "field": "Company response - detailed",
- "cellDataType": "text",
- "cellStyle": CELL_STYLE,
- "headerName": "Company response",
- "flex": 6,
- },
- {"field": "Timely response?", "cellRenderer": "markdown", "headerName": "On time?", "flex": 3},
-]
diff --git a/vizro-core/examples/kpi/utils/_helper.py b/vizro-core/examples/kpi/utils/_helper.py
deleted file mode 100644
index 0157a60ff..000000000
--- a/vizro-core/examples/kpi/utils/_helper.py
+++ /dev/null
@@ -1,128 +0,0 @@
-"""Contains helper functions and variables."""
-
-from functools import reduce
-
-import numpy as np
-import pandas as pd
-
-REGION_MAPPING = {
- **dict.fromkeys(["CT", "ME", "MA", "NH", "RI", "VT", "NJ", "NY", "PA"], "North East"),
- **dict.fromkeys(
- ["IL", "IN", "MI", "OH", "WI", "IA", "KS", "MN", "MO", "NE", "ND", "SD"], "Mid West" # codespell:ignore
- ),
- **dict.fromkeys(
- ["DE", "FL", "GA", "MD", "NC", "SC", "VA", "WV", "DC", "AL", "KY", "MS", "TN", "AR", "LA"], "South"
- ),
- **dict.fromkeys(["AZ", "NM", "OK", "TX"], "South West"),
- **dict.fromkeys(["CO", "ID", "MT", "NV", "UT", "WY", "AK", "CA", "HI", "OR", "WA"], "West"),
- **dict.fromkeys(["UM", "PR", "AP", "VI", "AE", "AS", "GU", "FM", "PW", "MP"], "Other"),
-}
-
-
-def fill_na_with_random(df, column):
- """Fills missing values in a column with random values from the same column."""
- non_na_values = df[column].dropna().values
- df[column] = df[column].apply(lambda x: np.random.choice(non_na_values) if pd.isna(x) else x)
- return df[column]
-
-
-def clean_data_and_add_columns(data: pd.DataFrame):
- """Tidies the original data set, adds new columns, and changes cell values for the purpose of this example."""
- data = data.rename(
- columns={
- "Date Sumbited": "Date Submitted",
- "Submitted via": "Channel",
- "Company response to consumer": "Company response - detailed",
- },
- )
-
- # Clean cell values and/or assign different values for the purpose of this example
- data["Company response - detailed"] = data["Company response - detailed"].replace("Closed", "Closed without relief")
- data["State"] = data["State"].replace("UNITED STATES MINOR OUTLYING ISLANDS", "UM")
- data["State"] = fill_na_with_random(data, "State")
- data["Consumer disputed?"] = data["Consumer disputed?"].fillna("No")
-
- # Convert to correct data type
- data["Date Received"] = pd.to_datetime(data["Date Received"], format="%m/%d/%y").dt.strftime("%Y-%m-%d")
-
- # Create additional columns
- data["Month"] = pd.to_datetime(data["Date Received"], format="%Y-%m-%d").dt.strftime("%m")
- data["Year"] = pd.to_datetime(data["Date Received"], format="%Y-%m-%d").dt.strftime("%Y")
- data["Region"] = data["State"].map(REGION_MAPPING)
- data["Company response"] = np.where(
- data["Company response - detailed"].str.contains("Closed"), "Closed", data["Company response - detailed"]
- )
- data["Company response - Closed"] = np.where(
- data["Company response - detailed"].str.contains("Closed"), data["Company response - detailed"], "Not closed"
- )
-
- # Filter 2018 and 2019 only
- data = data[(data["Year"].isin(["2018", "2019"]))]
- return data
-
-
-def create_data_for_kpi_cards(data):
- """Formats and aggregates the data for the KPI cards."""
- total_complaints = (
- data.groupby("Year")
- .agg({"Complaint ID": "count"})
- .rename(columns={"Complaint ID": "Total Complaints"})
- .reset_index()
- )
- closed_complaints = (
- data[data["Company response"] == "Closed"]
- .groupby("Year")
- .agg({"Complaint ID": "count"})
- .rename(columns={"Complaint ID": "Closed Complaints"})
- .reset_index()
- )
- timely_response = (
- data[data["Timely response?"] == "Yes"]
- .groupby("Year")
- .agg({"Complaint ID": "count"})
- .rename(columns={"Complaint ID": "Timely response"})
- .reset_index()
- )
- closed_without_cost = (
- data[data["Company response - Closed"] != "Closed with monetary relief"]
- .groupby("Year")
- .agg({"Complaint ID": "count"})
- .rename(columns={"Complaint ID": "Closed w/o cost"})
- .reset_index()
- )
- consumer_disputed = (
- data[data["Consumer disputed?"] == "Yes"]
- .groupby("Year")
- .agg({"Complaint ID": "count"})
- .rename(columns={"Complaint ID": "Consumer disputed"})
- .reset_index()
- )
-
- # Merge all data frames into one
- dfs_to_merge = [total_complaints, closed_complaints, timely_response, closed_without_cost, consumer_disputed]
- df_kpi = reduce(lambda left, right: pd.merge(left, right, on="Year", how="outer"), dfs_to_merge)
-
- # Calculate percentages
- df_kpi.fillna(0, inplace=True)
- df_kpi["Closed Complaints"] = df_kpi["Closed Complaints"] / df_kpi["Total Complaints"] * 100
- df_kpi["Open Complaints"] = 100 - df_kpi["Closed Complaints"]
- df_kpi["Timely response"] = df_kpi["Timely response"] / df_kpi["Total Complaints"] * 100
- df_kpi["Closed w/o cost"] = df_kpi["Closed w/o cost"] / df_kpi["Total Complaints"] * 100
- df_kpi["Consumer disputed"] = df_kpi["Consumer disputed"] / df_kpi["Total Complaints"] * 100
-
- # Pivot the dataframe and flatten
- df_kpi["index"] = 0
- df_kpi = df_kpi.pivot(
- index="index",
- columns="Year",
- values=[
- "Total Complaints",
- "Closed Complaints",
- "Open Complaints",
- "Timely response",
- "Closed w/o cost",
- "Consumer disputed",
- ],
- )
- df_kpi.columns = [f"{kpi}_{year}" for kpi, year in df_kpi.columns]
- return df_kpi