diff --git a/vizro-core/changelog.d/20240607_125345_huong_li_nguyen_create_kpi_cards.md b/vizro-core/changelog.d/20240607_125345_huong_li_nguyen_create_kpi_cards.md
index aeeb34aef..568c4f46a 100644
--- a/vizro-core/changelog.d/20240607_125345_huong_li_nguyen_create_kpi_cards.md
+++ b/vizro-core/changelog.d/20240607_125345_huong_li_nguyen_create_kpi_cards.md
@@ -6,8 +6,8 @@ Uncomment the section that is right (remove the HTML comment wrapper).
### Highlights ✨
-- Introduce `Figure` as a new `Page` component, enabling all dash components to be reactive in
- `Vizro`. See the [user guide on figure](XXXX) for more information. ([#493](https://github.com/mckinsey/vizro/pull/493))
+- Introduce `Figure` as a new `Page` component, enabling all Dash components to be reactive in
+ `Vizro`. See the [user guide on figure](https://vizro.readthedocs.io/en/stable/pages/user-guides/figure/) for more information. ([#493](https://github.com/mckinsey/vizro/pull/493), [#524](https://github.com/mckinsey/vizro/pull/524))
- Introduce styled KPI cards to be used inside `Figure`. See the [user guide on KPI cards](XXXX) for more information. ([#493](https://github.com/mckinsey/vizro/pull/493))
+
+
+
+
+
+
+
+
diff --git a/vizro-core/docs/assets/user_guides/figure/custom_html.png b/vizro-core/docs/assets/user_guides/figure/custom_html.png
new file mode 100644
index 000000000..82d4f8d48
Binary files /dev/null and b/vizro-core/docs/assets/user_guides/figure/custom_html.png differ
diff --git a/vizro-core/docs/assets/user_guides/figure/custom_kpi.png b/vizro-core/docs/assets/user_guides/figure/custom_kpi.png
new file mode 100644
index 000000000..b6d2f2727
Binary files /dev/null and b/vizro-core/docs/assets/user_guides/figure/custom_kpi.png differ
diff --git a/vizro-core/docs/assets/user_guides/figure/custom_multiple_cards.png b/vizro-core/docs/assets/user_guides/figure/custom_multiple_cards.png
new file mode 100644
index 000000000..3f1b66bf9
Binary files /dev/null and b/vizro-core/docs/assets/user_guides/figure/custom_multiple_cards.png differ
diff --git a/vizro-core/docs/assets/user_guides/figure/figure.png b/vizro-core/docs/assets/user_guides/figure/figure.png
new file mode 100644
index 000000000..dad982f3e
Binary files /dev/null and b/vizro-core/docs/assets/user_guides/figure/figure.png differ
diff --git a/vizro-core/docs/pages/API-reference/actions.md b/vizro-core/docs/pages/API-reference/action-callables.md
similarity index 85%
rename from vizro-core/docs/pages/API-reference/actions.md
rename to vizro-core/docs/pages/API-reference/action-callables.md
index 3cbd4d926..804dff6bc 100644
--- a/vizro-core/docs/pages/API-reference/actions.md
+++ b/vizro-core/docs/pages/API-reference/action-callables.md
@@ -1,4 +1,4 @@
-# Actions
+# Action functions
API reference for all pre-defined action functions.
diff --git a/vizro-core/docs/pages/API-reference/captured-callables.md b/vizro-core/docs/pages/API-reference/captured-callables.md
deleted file mode 100644
index a83e79850..000000000
--- a/vizro-core/docs/pages/API-reference/captured-callables.md
+++ /dev/null
@@ -1,21 +0,0 @@
-
-# Table functions
-
-API reference for all pre-defined [`CapturedCallable`][vizro.models.types.CapturedCallable] table functions to be used in the
-[`AgGrid`][vizro.models.AgGrid] and [`Table`][vizro.models.Table] models. Visit the how-to guide on [tables](../user-guides/table.md)
-for more information.
-
-::: vizro.tables
- options:
- show_source: true
-
-# Figure functions
-API reference for all pre-defined [`CapturedCallable`][vizro.models.types.CapturedCallable] figure functions to be used in the
-[`Figure`][vizro.models.Figure]. Visit the how-to guide on [figures](../user-guides/figure.md)
-for more information.
-
-::: vizro.figures
- options:
- show_source: true
-
-
diff --git a/vizro-core/docs/pages/API-reference/figure-callables.md b/vizro-core/docs/pages/API-reference/figure-callables.md
new file mode 100644
index 000000000..ada2b5d95
--- /dev/null
+++ b/vizro-core/docs/pages/API-reference/figure-callables.md
@@ -0,0 +1,10 @@
+
+# Figure functions
+API reference for all pre-defined [`CapturedCallable`][vizro.models.types.CapturedCallable] figure functions to be used in the
+[`Figure`][vizro.models.Figure]. The [how-to guide on figures](../user-guides/figure.md) contains more information.
+
+::: vizro.figures
+ options:
+ show_source: true
+
+
diff --git a/vizro-core/docs/pages/API-reference/table-callables.md b/vizro-core/docs/pages/API-reference/table-callables.md
new file mode 100644
index 000000000..7c3c8d33c
--- /dev/null
+++ b/vizro-core/docs/pages/API-reference/table-callables.md
@@ -0,0 +1,11 @@
+
+# Table functions
+
+API reference for all pre-defined [`CapturedCallable`][vizro.models.types.CapturedCallable] table functions to be used in the
+[`AgGrid`][vizro.models.AgGrid] and [`Table`][vizro.models.Table] models. The how-to guide on [tables](../user-guides/table.md) contains more information.
+
+::: vizro.tables
+ options:
+ show_source: true
+
+
diff --git a/vizro-core/docs/pages/user-guides/components.md b/vizro-core/docs/pages/user-guides/components.md
index 222ffbff1..106bf6a0b 100755
--- a/vizro-core/docs/pages/user-guides/components.md
+++ b/vizro-core/docs/pages/user-guides/components.md
@@ -6,7 +6,7 @@ listed below to fill your dashboard with visuals.
-- :octicons-graph-16:{ .lg .middle } __Graph__
+- :octicons-graph-16:{ .lg .middle } __Graphs__
---
@@ -14,7 +14,7 @@ listed below to fill your dashboard with visuals.
[:octicons-arrow-right-24: View user guide](graph.md)
-- :material-table-large:{ .lg .middle } __Table__
+- :material-table-large:{ .lg .middle } __Tables__
---
@@ -22,23 +22,24 @@ listed below to fill your dashboard with visuals.
[:octicons-arrow-right-24: View user guide](table.md)
-- :material-cards-outline:{ .lg .middle } __Card & button__
+- :material-graph:{ .lg .middle } __Figures__
---
- Use cards and buttons to visualize text, navigate to different URLs or attach any [action](actions.md).
+ Use figures to make any [Dash component](https://dash.plotly.com/#open-source-component-libraries) reactive.
- [:octicons-arrow-right-24: View user guide](card-button.md)
+ [:octicons-arrow-right-24: View user guide](figure.md)
-- :material-graph:{ .lg .middle } __Figure__
+- :material-cards-outline:{ .lg .middle } __Cards & buttons__
---
- Use figure to visualize your make any dash component reactive.
+ Use cards and buttons to visualize text, navigate to different URLs or attach any [action](actions.md).
+
+ [:octicons-arrow-right-24: View user guide](card-button.md)
- [:octicons-arrow-right-24: View user guide](figure.md)
-- :octicons-table-16:{ .lg .middle } __Container__
+- :octicons-table-16:{ .lg .middle } __Containers__
---
diff --git a/vizro-core/docs/pages/user-guides/custom-charts.md b/vizro-core/docs/pages/user-guides/custom-charts.md
index 31a312ecb..e5c7eebca 100644
--- a/vizro-core/docs/pages/user-guides/custom-charts.md
+++ b/vizro-core/docs/pages/user-guides/custom-charts.md
@@ -3,26 +3,27 @@
This guide shows you how to create custom charts and how to add them to your dashboard.
The [`Graph`][vizro.models.Graph] model accepts the `figure` argument, where you can enter _any_ [`plotly.express`](https://plotly.com/python/plotly-express/) chart as explained in the [user guide on graphs](graph.md).
-## Overview of custom charts
+## When to use a custom chart
+In general, you should use the custom chart decorator `@capture("graph")` if your plotly chart needs any post-update calls or customization. For example:
-In general, the usage of the custom chart decorator `@capture("graph")` is required if your plotly chart requires any post-update calls or customization.
+- You want to use any of the post figure update calls by `plotly` such as `update_layout`, `update_xaxes`, `update_traces` (for more details, see the docs on [plotly's update calls](https://plotly.com/python/creating-and-updating-figures/#other-update-methods))
+- You want to use a custom-created [`plotly.graph_objects.Figure()`](https://plotly.com/python/graph-objects/) object (in short, `go.Figure()`) and add traces yourself via [`add_trace`](https://plotly.com/python/creating-and-updating-figures/#adding-traces)
-### When to use a custom chart
+## Steps to create a custom chart
-- If you want to use any of the post figure update calls by `plotly` such as `update_layout`, `update_xaxes`, `update_traces` (for more details, see the docs on [plotly's update calls](https://plotly.com/python/creating-and-updating-figures/#other-update-methods))
-- If you want to use a custom-created [`plotly.graph_objects.Figure()`](https://plotly.com/python/graph-objects/) object (in short, `go.Figure()`) and add traces yourself via [`add_trace`](https://plotly.com/python/creating-and-updating-figures/#adding-traces)
+1. Define a function that returns a `go.Figure()`.
+2. Decorate it with `@capture("graph")`.
+3. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
+4. The visualization should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments
+will not react to dashboard controls such as [`Filter`](filters.md).
+5. Pass your function to the `figure` argument of the [`Graph`][vizro.models.Graph] model.
-### Requirements of a custom chart function
-
-- a `go.Figure()` object is returned by the function
-- the function must be decorated with the `@capture("graph")` decorator
-- the function accepts a `data_frame` argument (of type `pandas.DataFrame`)
-- the visualization is derived from and requires only one `pandas.DataFrame` (for example, any further dataframes added through other arguments will not react to dashboard components such as `Filter`)
-
-The below minimal example can be used as a base to build more sophisticated charts.
+The minimal example below can be used as a base to build more sophisticated charts.
```py title="Minimal example of a custom chart"
from vizro.models.types import capture
+import pandas as pd
+import plotly.graph_objects as go
@capture("graph")
def minimal_example(data_frame:pd.DataFrame=None):
diff --git a/vizro-core/docs/pages/user-guides/custom-components.md b/vizro-core/docs/pages/user-guides/custom-components.md
index 121209040..94997230c 100644
--- a/vizro-core/docs/pages/user-guides/custom-components.md
+++ b/vizro-core/docs/pages/user-guides/custom-components.md
@@ -11,7 +11,7 @@ In general, you can create a custom component based on any dash-compatible compo
All our components are based on `Dash`, and they are shipped with a set of sensible defaults that can be modified. If you would like to overwrite one of those defaults,
-or if you would like to use extra `args` or `kwargs` of those components, then this is the correct way to include those. You can use any existing attribute of any underlying Dash component with this method.
+or if you would like to use extra `args` or `kwargs` of those components, then this is the correct way to include those. You can use any existing attribute of any underlying [Dash component](https://dash.plotly.com/#open-source-component-libraries) with this method.
!!!note
diff --git a/vizro-core/docs/pages/user-guides/custom-figures.md b/vizro-core/docs/pages/user-guides/custom-figures.md
new file mode 100644
index 000000000..cf78c61f7
--- /dev/null
+++ b/vizro-core/docs/pages/user-guides/custom-figures.md
@@ -0,0 +1,280 @@
+# How to create custom figures
+
+This guide explains how to create custom figures, which is useful when you need a component that reacts to
+[filter](filters.md) and [parameter](parameters.md) controls.
+
+The [`Figure`][vizro.models.Figure] model accepts the `figure` argument, where you can enter _any_ custom figure function
+as explained in the [user guide on figures](figure.md).
+
+## When to use a custom figure
+As described in the flowchart detailing [when to use `Figure`](figure.md), custom figures should be used if
+**both** of the following conditions are met:
+
+- You need a figure that doesn't fit into the existing pre-defined components ([`Graph`][vizro.models.Graph], [`Table`][vizro.models.Table] or [`AgGrid`][vizro.models.AgGrid]).
+- You need a figure that isn't available in our pre-defined figure functions [`vizro.figures`](../API-reference/figure-callables.md).
+
+## Steps to create a custom figure
+
+1. Define a function that returns a [Dash component](https://dash.plotly.com/#open-source-component-libraries).
+This can, but does not need to, be based on code in our pre-defined figure functions in [`vizro.figures`](../API-reference/figure-callables.md).
+2. Decorate it with `@capture("figure")`.
+3. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
+4. The figure should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments
+will not react to dashboard controls such as [`Filter`](filters.md).
+5. Pass your function to the `figure` argument of the [`Figure`][vizro.models.Figure] model.
+
+The following examples can be used as a base to build more sophisticated figures.
+
+## Examples of custom figures
+
+### Custom KPI card
+If you wish to change the design or content of our existing KPI (key performance indicator) cards from
+[`vizro.figures`](../API-reference/figure-callables.md), you can do so by following the steps described above.
+
+For instance, to make a KPI card with the icon positioned on the right side of the title instead of the left,
+copy and paste the [source code of `kpi_card`](../API-reference/figure-callables.md/#kpi_card) and
+adjust the return statement of the function.
+
+
+!!! example "Custom KPI card"
+ === "app.py"
+ ```py
+ from typing import Optional
+
+ import dash_bootstrap_components as dbc
+ import pandas as pd
+ import vizro.models as vm
+ import vizro.plotly.express as px
+ from dash import html
+ from vizro import Vizro
+ from vizro.figures import kpi_card
+ from vizro.models.types import capture
+
+ tips = px.data.tips
+
+
+ @capture("figure") # (1)!
+ def custom_kpi_card(
+ data_frame: pd.DataFrame,
+ value_column: str,
+ *,
+ value_format: str = "{value}",
+ agg_func: str = "sum",
+ title: Optional[str] = None,
+ icon: Optional[str] = None,
+ ) -> dbc.Card: # (2)!
+ """Creates a custom KPI Card."""
+ title = title or f"{agg_func} {value_column}".title()
+ value = data_frame[value_column].agg(agg_func)
+
+ return dbc.Card(
+ [
+ dbc.CardHeader(
+ [
+ html.H2(title),
+ html.P(icon, className="material-symbols-outlined") if icon else None, # (3)!
+ ],
+ ),
+ dbc.CardBody([value_format.format(value=value)]),
+ ],
+ className="card-kpi",
+ )
+
+
+ page = vm.Page(
+ title="Create your own KPI Card",
+ layout=vm.Layout(grid=[[0, 1, -1, -1]] + [[-1, -1, -1, -1]] * 3), # (4)!
+ components=[
+ vm.Figure(
+ figure=kpi_card( # (5)!
+ data_frame=tips,
+ value_column="tip",
+ value_format="${value:.2f}",
+ icon="shopping_cart",
+ title="Default KPI Card",
+ )
+ ),
+ vm.Figure(
+ figure=custom_kpi_card( # (6)!
+ data_frame=tips,
+ value_column="tip",
+ value_format="${value:.2f}",
+ icon="payment",
+ title="Custom KPI Card",
+ )
+ ),
+ ],
+ )
+
+ dashboard = vm.Dashboard(pages=[page])
+ Vizro().build(dashboard).run()
+ ```
+
+ 1. Here we decorate our custom figure function with the `@capture("figure")` decorator.
+ 2. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
+ 3. We adjust the return statement to include the icon on the right side of the title. This is achieved by swapping the order of the `html.H2` and `html.P` compared to the original `kpi_card`.
+ 4. This creates a [`layout`](layouts.md) with four rows and columns. The KPI cards are positioned in the first two cells, while the remaining cells are empty.
+ 5. For more information, refer to the API reference for the [`kpi_card`](../API-reference/figure-callables.md#kpi_card).
+ 6. Our custom figure function `custom_kpi_card` now needs to be passed on to the `vm.Figure`.
+
+ === "app.yaml"
+ ```yaml
+ # Custom figures are currently only possible via python configuration
+ ```
+ === "Result"
+ [![CustomKPI]][CustomKPI]
+
+ [CustomKPI]: ../../assets/user_guides/figure/custom_kpi.png
+
+
+
+### Dynamic HTML header
+Generally, you can create a custom figure for any [Dash component](https://dash.plotly.com/#open-source-component-libraries).
+Below is an example of a custom figure that returns a `html.H2` component that dynamically updates based on the selected
+name from a filter.
+
+
+!!! example "Dynamic HTML header"
+ === "app.py"
+ ```py
+ import pandas as pd
+ import vizro.models as vm
+ from dash import html
+ from vizro import Vizro
+ from vizro.models.types import capture
+
+ df = pd.DataFrame({"names": ["Emma", "Jack", "Sophia", "Ethan", "Mia"]})
+
+
+ @capture("figure") # (1)!
+ def dynamic_html_header(data_frame: pd.DataFrame, column: str) -> html.H2: # (2)!
+ """Creates a HTML header that dynamically updates based on controls."""
+ return html.H2(f"Good morning, {data_frame[column].iloc[0]}! ☕ ⛅") # (3)!
+
+
+ page = vm.Page(
+ title="Dynamic HTML header",
+ components=[vm.Figure(figure=dynamic_html_header(data_frame=df, column="names"))], # (4)!
+ controls=[vm.Filter(column="names", selector=vm.RadioItems(title="Select a name"))],
+ )
+
+ dashboard = vm.Dashboard(pages=[page])
+ Vizro().build(dashboard).run()
+ ```
+
+ 1. Here we decorate our custom figure function with the `@capture("figure")` decorator.
+ 2. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
+ 3. We return a `html.H2` component that dynamically updates based on the selected name from the filter.
+ 4. Our custom figure function `dynamic_html_header` now needs to be passed on to the `vm.Figure`.
+
+ === "app.yaml"
+ ```yaml
+ # Custom figures are currently only possible via python configuration
+ ```
+ === "Result"
+ [![CustomHTML]][CustomHTML]
+
+ [CustomHTML]: ../../assets/user_guides/figure/custom_html.png
+
+
+
+
+### Dynamic number of cards
+The example below shows how to create multiple cards created from a `pandas.DataFrame` where the
+number of cards displayed dynamically adjusts based on a `vm.Parameter`.
+
+
+!!! example "Dynamic number of cards"
+ === "app.py"
+ ```py
+ from typing import Optional
+
+ import dash_bootstrap_components as dbc
+ import pandas as pd
+ import vizro.models as vm
+ from dash import dcc, html
+ from vizro import Vizro
+ from vizro.models.types import capture
+
+ text = [
+ "Lorem ipsum dolor sit amet, consetetur sadipscing no sea elitr sed diam nonumy.",
+ "Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
+ "Sed diam voluptua. At vero eos et accusam et justo no duo dolores et ea rebum.",
+ "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
+ "Lorem ipsum dolor sit amet, consetetur sadipscing no sea est elitr dolor sit amet.",
+ "Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
+ ]
+
+ df = pd.DataFrame({"text": text * 2})
+
+
+ @capture("figure") # (1)!
+ def multiple_cards(data_frame: pd.DataFrame, n_rows: Optional[int] = 1) -> html.Div: # (2)!
+ """Creates a list with a variable number of `vm.Card` components from the provided data_frame.
+
+ Args:
+ data_frame: Data frame containing the data.
+ n_rows: Number of rows to use from the data_frame. Defaults to 1.
+
+ Returns:
+ html.Div with a list of dbc.Card objects generated from the data.
+
+ """
+ texts = data_frame.head(n_rows)["text"]
+ return html.Div(
+ [dbc.Card(dcc.Markdown(f"### Card #{i}\n{text}")) for i, text in enumerate(texts, 1)],
+ className="multiple-cards-container",
+ )
+
+
+ page = vm.Page(
+ title="Page with variable number of cards",
+ components=[vm.Figure(id="my-figure", figure=multiple_cards(data_frame=df))], # (3)!
+ controls=[
+ vm.Parameter(
+ targets=["my-figure.n_rows"], # (4)!
+ selector=vm.Slider(min=2, max=12, step=2, value=8, title="Number of cards to display"),
+ ),
+ ],
+ )
+
+ dashboard = vm.Dashboard(pages=[page])
+ Vizro().build(dashboard).run()
+ ```
+
+ 1. Here we decorate our custom figure function with the `@capture("figure")` decorator.
+ 2. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
+ 3. Our decorated figure function `multiple_cards` now needs to be passed on to the `vm.Figure`.
+ 4. We add a [`vm.Parameter`](parameters.md) to dynamically adjust the number of cards displayed.
+ The parameter targets the `n_rows` argument of the `multiple_cards` function, determining the number of rows
+ taken from the data.
+
+ === "css"
+ ```css
+ .multiple-cards-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ }
+
+ .figure-container {
+ height: unset;
+ width: unset;
+ }
+
+ .figure-container .card {
+ height: 210px;
+ width: 240px;
+ }
+ ```
+ === "app.yaml"
+ ```yaml
+ # Custom figures are currently only possible via python configuration
+ ```
+ === "Result"
+ [![CustomFigure]][CustomFigure]
+
+ [CustomFigure]: ../../assets/user_guides/figure/custom_multiple_cards.png
+
+
+
diff --git a/vizro-core/docs/pages/user-guides/custom-tables.md b/vizro-core/docs/pages/user-guides/custom-tables.md
index 9a50816a5..e5fa4d413 100644
--- a/vizro-core/docs/pages/user-guides/custom-tables.md
+++ b/vizro-core/docs/pages/user-guides/custom-tables.md
@@ -3,14 +3,19 @@
In cases where the available arguments for the [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] models are not sufficient,
you can create a custom Dash AG Grid or Dash DataTable.
+The [`Table`][vizro.models.Table] and the [`AgGrid`][vizro.models.AgGrid] model accept the `figure` argument, where you can enter
+_any_ [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] chart as explained in the [user guide on tables](table.md).
+
One reason could be that you want to create a table/grid that requires computations that can be controlled by parameters (see the example below).
-For this, similar to how one would create a [custom chart](../user-guides/custom-charts.md), do the following:
+### Steps to create a custom table
-- Define a function that returns a `dash_ag_grid.AgGrid` or `dash_table.DataTable` object.
-- Decorate it with the `@capture("ag_grid")` or `@capture("table")` decorator respectively.
-- The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
-- The table should be derived from and require only one `pandas.DataFrame` (for example, any further dataframes added through other arguments will not react to dashboard components such as `Filter`).
+1. Define a function that returns a `dash_ag_grid.AgGrid` or `dash_table.DataTable` object.
+2. Decorate it with `@capture("ag_grid")` or `@capture("table")`.
+3. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
+4. The table should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments
+will not react to dashboard controls such as [`Filter`](filters.md).
+5. Pass your function to the `figure` argument of the [`Table`][vizro.models.Table] or [`AgGrid`][vizro.models.AgGrid] model.
The following examples show a possible version of a custom table. In this case the argument `chosen_columns` was added, which you can control with a parameter:
diff --git a/vizro-core/docs/pages/user-guides/figure.md b/vizro-core/docs/pages/user-guides/figure.md
index 1d8a9a8d2..c9c596d50 100644
--- a/vizro-core/docs/pages/user-guides/figure.md
+++ b/vizro-core/docs/pages/user-guides/figure.md
@@ -1 +1,120 @@
# How to use figures
+
+This guide shows you how to add any [Dash component](https://dash.plotly.com/#open-source-component-libraries) that needs to be reactive to [filter](filters.md) and [parameter](parameters.md) controls.
+If you want to add a static Dash component to your page, use [custom components](custom-components.md) instead.
+
+[`Figure`][vizro.models.Figure] provides a flexible foundation for all types of reactive Dash components in Vizro.
+The [`Graph`][vizro.models.Graph], [`Table`][vizro.models.Table] and [`AgGrid`][vizro.models.AgGrid] components are
+specific implementations of `Figure`. They serve as intuitive shortcuts, embedding behaviors and interactions specific
+to their purposes.
+
+If these more specific models already achieve what you need then they should be used in preference to
+the more generic `Figure`. Remember that it is possible to supply [custom charts](custom-charts.md) to `Graph`
+and [custom tables](custom-tables.md) to `Table`.
+
+There are already a few figure functions you can reuse:
+
+- [`kpi_card`][vizro.figures.kpi_card]
+- [`kpi_card_reference`][vizro.figures.kpi_card_reference]
+
+The following flowchart shows what you need to consider when choosing which model to use:
+
+``` mermaid
+graph TD
+ first["`Does your desired component exist in Vizro, e.g. Graph, Table or AgGrid?`"]
+ specific-component([Use the specific component])
+ second["`Does your component need to be reactive to controls?`"]
+ second-static([Use custom components])
+ second-reactive([Use Figure])
+
+ first -- Yes --> specific-component
+ first -- No --> second
+ second -- No --> second-static
+ second -- Yes --> second-reactive
+
+ click specific-component href "../components/"
+ click second-static href "../custom-components/"
+ click second-reactive href "#how-to-use-figures"
+
+ classDef clickable color:#4051b5;
+```
+
+
+To add a `Figure` to your page:
+
+1. Add the `Figure` model to the components argument of the [Page][vizro.models.Page] model.
+2. Use an existing figure function from [`vizro.figures`](../API-reference/figure-callables.md) and pass it to the `figure` argument of the `Figure` model.
+
+!!! example "Use existing figure functions"
+
+ === "app.py"
+ ```py
+ import vizro.models as vm
+ import vizro.plotly.express as px
+ from vizro import Vizro
+ from vizro.figures import kpi_card
+
+ tips = px.data.tips
+
+ page = vm.Page(
+ title="KPI Indicators",
+ layout=vm.Layout(grid=[[0, -1, -1, -1]] + [[-1, -1, -1, -1]] * 4), # (1)!
+ components=[
+ vm.Figure(
+ figure=kpi_card( # (2)!
+ data_frame=tips,
+ value_column="tip",
+ value_format="${value:.2f}",
+ icon="shopping_cart",
+ title="KPI Card I",
+ )
+ )
+ ],
+ controls=[vm.Filter(column="day", selector=vm.RadioItems())],
+ )
+
+ dashboard = vm.Dashboard(pages=[page])
+ Vizro().build(dashboard).run()
+ ```
+
+ 1. This creates a [`layout`](layouts.md) with five rows and four columns. The KPI card is positioned in the first cell, while the remaining cells are empty.
+ 2. For more information, refer to the API reference for the [`kpi_card`](../API-reference/figure-callables.md#kpi_card).
+
+ === "app.yaml"
+ ```yaml
+ # Still requires a .py to add data to the data manager and parse YAML configuration
+ # See from_yaml example
+ pages:
+ - components:
+ - figure:
+ _target_: kpi_card
+ data_frame: tips
+ value_column: tip
+ value_format: ${value:.2f}
+ icon: shopping_cart
+ title: KPI Card I
+ type: figure
+ controls:
+ - column: day
+ type: filter
+ selector:
+ type: radio_items
+ layout:
+ grid:
+ [
+ [0, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ ]
+ title: KPI Indicators
+ ```
+ === "Result"
+ [![Figure]][Figure]
+
+ [Figure]: ../../assets/user_guides/figure/figure.png
+
+
+If the pre-defined figure functions from [`vizro.figures`](../API-reference/figure-callables.md) do not serve your purpose,
+there is always the option to create a [custom figure](custom-figures.md).
diff --git a/vizro-core/examples/_dev/app.py b/vizro-core/examples/_dev/app.py
index a1699fe5f..9b783413a 100644
--- a/vizro-core/examples/_dev/app.py
+++ b/vizro-core/examples/_dev/app.py
@@ -1,23 +1,57 @@
-"""Example to show dashboard configuration."""
+"""Dev app to try things out."""
+from typing import Optional
+
+import dash_bootstrap_components as dbc
+import pandas as pd
import vizro.models as vm
-import vizro.plotly.express as px
+from dash import dcc, html
from vizro import Vizro
+from vizro.models.types import capture
-df = px.data.gapminder()
+text = [
+ "Lorem ipsum dolor sit amet, consetetur sadipscing no sea elitr sed diam nonumy.",
+ "Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
+ "Sed diam voluptua. At vero eos et accusam et justo no duo dolores et ea rebum.",
+ "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
+ "Lorem ipsum dolor sit amet, consetetur sadipscing no sea est elitr dolor sit amet.",
+ "Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
+]
-page_one = vm.Page(
- title="Vizro filters exporting",
- components=[
- vm.Graph(id="graph_1", figure=px.scatter(df, x="gdpPercap", y="lifeExp", color="continent", size="pop")),
- vm.Graph(id="graph_2", figure=px.scatter(df, x="gdpPercap", y="lifeExp", color="continent", size="pop")),
- ],
+df = pd.DataFrame({"text": text * 2})
+
+
+@capture("figure") # (1)!
+def multiple_cards(data_frame: pd.DataFrame, n_rows: Optional[int] = 1) -> html.Div: # (2)!
+ """Creates a list with a variable number of `vm.Card` components from the provided data_frame.
+
+ Args:
+ data_frame: Data frame containing the data.
+ n_rows: Number of rows to use from the data_frame. Defaults to 1.
+
+ Returns:
+ html.Div with a list of dbc.Card objects generated from the data.
+
+ """
+ texts = data_frame.head(n_rows)["text"]
+ return html.Div(
+ [dbc.Card(dcc.Markdown(f"### Card #{i}\n{text}")) for i, text in enumerate(texts, 1)],
+ className="multiple-cards-container",
+ )
+
+
+page = vm.Page(
+ title="Page with variable number of cards",
+ components=[vm.Figure(id="my-figure", figure=multiple_cards(data_frame=df))], # (3)!
controls=[
- vm.Filter(column="continent"),
+ vm.Parameter(
+ targets=["my-figure.n_rows"], # (4)!
+ selector=vm.Slider(min=2, max=12, step=2, value=8, title="Number of cards to display"),
+ ),
],
)
-dashboard = vm.Dashboard(pages=[page_one])
+dashboard = vm.Dashboard(pages=[page])
if __name__ == "__main__":
Vizro().build(dashboard).run()
diff --git a/vizro-core/examples/_dev/assets/css/custom.css b/vizro-core/examples/_dev/assets/css/custom.css
index 8a2651c0b..4d79dddef 100644
--- a/vizro-core/examples/_dev/assets/css/custom.css
+++ b/vizro-core/examples/_dev/assets/css/custom.css
@@ -1,4 +1,5 @@
-/* Apply reverse color logic via CSS */
-#kpi-card-reverse-coloring .card-kpi:has(.color-neg) {
- border-left: 4px solid #1a85ff;
+.multiple-cards-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
}
diff --git a/vizro-core/examples/_dev/yaml_version/app.py b/vizro-core/examples/_dev/yaml_version/app.py
index 808cdae9b..9f8d84516 100644
--- a/vizro-core/examples/_dev/yaml_version/app.py
+++ b/vizro-core/examples/_dev/yaml_version/app.py
@@ -12,7 +12,7 @@
data_manager["iris"] = px.data.iris()
data_manager["gapminder"] = px.data.gapminder()
data_manager["gapminder_2007"] = px.data.gapminder().query("year == 2007")
-
+data_manager["tips"] = px.data.tips()
df_stocks_long = pd.melt(
px.data.stocks(datetimes=True),
diff --git a/vizro-core/examples/_dev/yaml_version/dashboard.yaml b/vizro-core/examples/_dev/yaml_version/dashboard.yaml
index cd3cb3923..7e14655db 100644
--- a/vizro-core/examples/_dev/yaml_version/dashboard.yaml
+++ b/vizro-core/examples/_dev/yaml_version/dashboard.yaml
@@ -3,10 +3,25 @@
pages:
- components:
- figure:
- _target_: dash_ag_grid
- data_frame: gapminder
- dashGridOptions:
- pagination: true
- title: Dash AG Grid
- type: ag_grid
- title: Example of a Dash AG Grid
+ _target_: kpi_card
+ data_frame: tips
+ value_column: tip
+ value_format: ${value:.2f}
+ icon: shopping_cart
+ title: KPI Card I
+ type: figure
+ controls:
+ - column: day
+ type: filter
+ selector:
+ type: radio_items
+ layout:
+ grid:
+ [
+ [0, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ ]
+ title: KPI Indicators
diff --git a/vizro-core/examples/features/app.py b/vizro-core/examples/features/app.py
index 0155eb348..90464e542 100644
--- a/vizro-core/examples/features/app.py
+++ b/vizro-core/examples/features/app.py
@@ -3,13 +3,15 @@
from time import sleep
from typing import List, Literal, Optional
+import dash_bootstrap_components as dbc
import pandas as pd
import plotly.graph_objects as go
import vizro.models as vm
import vizro.plotly.express as px
-from dash import dash_table, html
+from dash import dash_table, dcc, html
from vizro import Vizro
from vizro.actions import export_data, filter_interaction
+from vizro.figures import kpi_card
from vizro.models.types import capture
from vizro.tables import dash_ag_grid, dash_data_table
@@ -25,6 +27,20 @@
"y": [60, 80, 0, -40, -20, 0],
}
)
+custom_fig_df = pd.DataFrame(
+ {
+ "text": [
+ "Lorem ipsum dolor sit amet, consetetur sadipscing no sea elitr sed diam nonumy.",
+ "Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
+ "Sed diam voluptua. At vero eos et accusam et justo no duo dolores et ea rebum.",
+ "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
+ "Lorem ipsum dolor sit amet, consetetur sadipscing no sea est elitr dolor sit amet.",
+ "Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
+ ]
+ * 2
+ }
+)
+
# HOME ------------------------------------------------------------------------
home = vm.Page(
@@ -37,7 +53,7 @@
### Components
- Main components of Vizro include **charts**, **tables**, **cards**, **containers**,
+ Main components of Vizro include **charts**, **tables**, **cards**, **figures**, **containers**,
**buttons** and **tabs**.
""",
href="/graphs",
@@ -180,6 +196,23 @@
],
)
+figure = vm.Page(
+ title="Figure",
+ layout=vm.Layout(grid=[[0, -1, -1, -1]] + [[-1, -1, -1, -1]] * 4),
+ components=[
+ vm.Figure(
+ figure=kpi_card(
+ data_frame=tips,
+ value_column="tip",
+ value_format="${value:.2f}",
+ icon="shopping_cart",
+ title="KPI Card I",
+ )
+ )
+ ],
+ controls=[vm.Filter(column="day", selector=vm.RadioItems())],
+)
+
button = vm.Page(
title="Button",
layout=vm.Layout(grid=[[0], [0], [0], [0], [1]]),
@@ -653,11 +686,42 @@ def my_custom_action(t: int):
controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))],
)
+
+# CUSTOM FIGURE ----------------------------------------------------------------
+@capture("figure") # (1)!
+def multiple_cards(data_frame: pd.DataFrame, n_rows: Optional[int] = 1) -> html.Div:
+ """Creates a list with a variable number of `vm.Card` components from the provided data_frame.
+
+ Args:
+ data_frame: Data frame containing the data.
+ n_rows: Number of rows to use from the data_frame. Defaults to 1.
+
+ Returns:
+ html.Div with a list of dbc.Card objects generated from the data.
+
+ """
+ texts = data_frame.head(n_rows)["text"]
+ return html.Div(
+ [dbc.Card(dcc.Markdown(f"### Card #{i}\n{text}")) for i, text in enumerate(texts, 1)],
+ className="multiple-cards-container",
+ )
+
+
+custom_figures = vm.Page(
+ title="Custom Figures",
+ components=[vm.Figure(id="my-figure", figure=multiple_cards(data_frame=custom_fig_df))],
+ controls=[
+ vm.Parameter(
+ targets=["my-figure.n_rows"],
+ selector=vm.Slider(min=2, max=12, step=2, value=8, title="Number of cards to display"),
+ ),
+ ],
+)
# DASHBOARD -------------------------------------------------------------------
-components = [graphs, ag_grid, table, cards, button, containers, tabs]
+components = [graphs, ag_grid, table, cards, figure, button, containers, tabs]
controls = [filters, parameters, selectors]
actions = [export_data_action, chart_interaction]
-extensions = [custom_charts, custom_tables, custom_components, custom_actions]
+extensions = [custom_charts, custom_tables, custom_components, custom_actions, custom_figures]
dashboard = vm.Dashboard(
title="Vizro Features",
@@ -669,10 +733,16 @@ def my_custom_action(t: int):
vm.NavLink(
label="Features",
pages={
- "Components": ["Graphs", "AG Grid", "Table", "Cards", "Button", "Containers", "Tabs"],
+ "Components": ["Graphs", "AG Grid", "Table", "Cards", "Figure", "Button", "Containers", "Tabs"],
"Controls": ["Filters", "Parameters", "Selectors"],
"Actions": ["Export data", "Chart interaction"],
- "Extensions": ["Custom Charts", "Custom Tables", "Custom Components", "Custom Actions"],
+ "Extensions": [
+ "Custom Charts",
+ "Custom Tables",
+ "Custom Components",
+ "Custom Actions",
+ "Custom Figures",
+ ],
},
icon="Library Add",
),
diff --git a/vizro-core/examples/features/assets/css/custom.css b/vizro-core/examples/features/assets/css/custom.css
index f8c8df785..6de1c7d59 100644
--- a/vizro-core/examples/features/assets/css/custom.css
+++ b/vizro-core/examples/features/assets/css/custom.css
@@ -1,3 +1,19 @@
#page-header {
padding-left: 8px;
}
+
+.multiple-cards-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+}
+
+.figure-container {
+ height: unset;
+ width: unset;
+}
+
+.figure-container .card {
+ height: 210px;
+ width: 240px;
+}
diff --git a/vizro-core/examples/features/yaml_version/dashboard.yaml b/vizro-core/examples/features/yaml_version/dashboard.yaml
index 2b25679da..82f9a3447 100644
--- a/vizro-core/examples/features/yaml_version/dashboard.yaml
+++ b/vizro-core/examples/features/yaml_version/dashboard.yaml
@@ -5,7 +5,7 @@ pages:
### Components
- Main components of vizro include **charts**, **tables**, **cards**, **containers**, **buttons** and **tabs**.
+ Main components of vizro include **charts**, **tables**, **cards**, **figures**, **containers**, **buttons** and **tabs**.
href: /graphs
type: card
- text: |
@@ -130,6 +130,30 @@ pages:
This word will be _**bold and italic**_
type: card
title: Cards
+ - components:
+ - figure:
+ _target_: kpi_card
+ data_frame: tips
+ value_column: tip
+ value_format: ${value:.2f}
+ icon: shopping_cart
+ title: KPI Card I
+ type: figure
+ controls:
+ - column: day
+ type: filter
+ selector:
+ type: radio_items
+ layout:
+ grid:
+ [
+ [0, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ [-1, -1, -1, -1],
+ ]
+ title: Figure
- components:
- figure:
_target_: scatter
@@ -286,6 +310,11 @@ pages:
## Custom actions are currently only possible via python configuration
type: card
title: Custom Actions
+ - components:
+ - text: |
+ ## Custom figures are currently only possible via python configuration
+ type: card
+ title: Custom Figures
- components:
- components:
- figure:
@@ -481,6 +510,7 @@ navigation:
- AG Grid
- Table
- Cards
+ - Figure
- Button
- Containers
- Tabs
@@ -496,4 +526,5 @@ navigation:
- Custom Tables
- Custom Components
- Custom Actions
+ - Custom Figures
title: Vizro Features
diff --git a/vizro-core/mkdocs.yml b/vizro-core/mkdocs.yml
index 591eac13e..d7be9a0de 100644
--- a/vizro-core/mkdocs.yml
+++ b/vizro-core/mkdocs.yml
@@ -39,11 +39,13 @@ nav:
- Custom tables: pages/user-guides/custom-tables.md
- Custom components: pages/user-guides/custom-components.md
- Custom actions: pages/user-guides/custom-actions.md
+ - Custom figures: pages/user-guides/custom-figures.md
- API Reference:
- Vizro: pages/API-reference/vizro.md
- Models: pages/API-reference/models.md
- - Actions: pages/API-reference/actions.md
- - Table functions: pages/API-reference/captured-callables.md
+ - Action functions: pages/API-reference/action-callables.md
+ - Table functions: pages/API-reference/table-callables.md
+ - Figure functions: pages/API-reference/figure-callables.md
- Explanation:
- FAQs: pages/explanation/faq.md
- Contribute to Vizro: pages/explanation/contributing.md