Skip to content

How to create custom actions

This guide demonstrates the usage of custom actions, an idea that shares similarities with, but is not identical to callbacks in Dash. If you want to use the Action model to perform functions that are not available in the pre-defined action functions, you can create your own custom action. Like other actions, custom actions could also be added as an element inside the actions chain, and it can be triggered with one of many dashboard components.

Simple custom action

Custom actions enable you to implement your own action function. Simply do the following:

  1. define a function
  2. decorate it with the @capture("action") decorator
  3. add it as a function argument inside the Action model

The following example shows how to create a custom action that postpones execution of the next action in the chain for t seconds.

Simple custom action

import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
from vizro.actions import export_data
from vizro.models.types import capture
from time import sleep


@capture("action")
def my_custom_action(t: int):
    """Custom action."""
    sleep(t)


df = px.data.iris()

page = vm.Page(
    title="Simple custom action",
    components=[
        vm.Graph(
            figure=px.scatter(df, x="sepal_length", y="petal_width", color="species")
        ),
        vm.Button(
            text="Export data",
            actions=[
                vm.Action(function=export_data()),
                vm.Action(
                    function=my_custom_action(t=2)
                ),
                vm.Action(function=export_data(file_format="xlsx")),
            ]
        )
    ],
    controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))],
)

dashboard = vm.Dashboard(pages=[page])

Vizro().build(dashboard).run()

Run and edit this code in Py.Cafe

# Custom actions are currently only possible via python configuration

Interact with inputs and outputs

When a custom action needs to interact with the dashboard, it is possible to define inputs and outputs for the custom action.

  • inputs represents dashboard component properties whose values are passed to the custom action function as arguments. It is a list of strings in the format "<component_id>.<property>" (for example, "my_selector.value").
  • outputs represents dashboard component properties corresponding to the custom action function return value(s). Similar to inputs, it is a list of strings in the format "<component_id>.<property>" (for example, "my_card.children").

Example of value as input

The following example shows a custom action that takes the value of the vm.RadioItem and returns it inside a Card component.

Display value in Card

import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
from vizro.models.types import capture

df = px.data.iris()
vm.Page.add_type("components", vm.RadioItems)

@capture("action")
def update_card_text(species):
    """Returns the input value."""
    return f"You selected species **{species}**"

page = vm.Page(
    title="Action with value as input",
    layout=vm.Layout(grid=[[0, 1]]),
    components=[
        vm.RadioItems(
            id="my_selector",
            title="Select a species:",
            options=df["species"].unique().tolist(),
            actions=[
                vm.Action(function=update_card_text(), inputs=["my_selector.value"], outputs=["my_card.children"])
            ],
        ),
        vm.Card(text="Placeholder text", id="my_card"),
    ],
)

dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()

Run and edit this code in Py.Cafe

# Custom actions are currently only possible via python configuration

ValueAction

Example of clickData as input

The following example shows how to create a custom action that shows the clickData of a chart in a Card component. For further information on the structure and content of the clickData property, refer to the Dash documentation on interactive visualizations.

Display clickData in Card

import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
from vizro.models.types import capture

df = px.data.iris()

@capture("action")
def my_custom_action(show_species: bool, points_data: dict): # (1)!
    """Custom action."""
    clicked_point = points_data["points"][0]
    x, y = clicked_point["x"], clicked_point["y"]
    text = f"Clicked point has sepal length {x}, petal width {y}"

    if show_species:
        species = clicked_point["customdata"][0]
        text += f" and species {species}"
    return text

page = vm.Page(
    title="Action with clickData as input",
    components=[
        vm.Graph(
            id="scatter_chart",
            figure=px.scatter(df, x="sepal_length", y="petal_width", color="species", custom_data=["species"]),
            actions=[
                vm.Action(
                    function=my_custom_action(show_species=True), # (2)!
                    inputs=["scatter_chart.clickData"], # (3)!
                    outputs=["my_card.children"],
                ),
            ],
        ),
        vm.Card(id="my_card", text="Click on a point on the above graph."),
    ],
)
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()

Run and edit this code in Py.Cafe

  1. Just as for any Python function, the names of the arguments show_species and points_data are arbitrary and do not need to match on to the names of inputs in any particular way.
  2. We bind (set) the argument show_species to the value True in the initial specification of the function field. These are static values that are fixed when the dashboard is built.
  3. The content of inputs will "fill in the gaps" by setting values for the remaining unbound arguments in my_custom_action. Here there is one such argument, named points_data. Values for these are bound dynamically at runtime to reflect the live state of your dashboard.
# Custom actions are currently only possible via python configuration

CustomAction

Multiple return values

The return value of the custom action function is propagated to the dashboard components that are defined in the outputs argument of the Action model. If there is a single output defined then the function return value is directly assigned to the component property. If there are multiple outputs defined then the return value is iterated through and each part is assigned to each component property given in outputs in turn. This behavior is identical to Python's flexibility in managing multiple return values.

Multiple return values

import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
from vizro.models.types import capture


@capture("action")
def my_custom_action(points_data: dict):
    """Custom action."""
    clicked_point = points_data["points"][0]
    x, y = clicked_point["x"], clicked_point["y"]
    species = clicked_point["customdata"][0]
    card_1_text = f"Clicked point has sepal length {x}, petal width {y}"
    card_2_text = f"Clicked point has species {species}"
    return card_1_text, card_2_text # (1)!


df = px.data.iris()

page = vm.Page(
    title="Example of a custom action with UI inputs and outputs",
    layout=vm.Layout(
        grid=[
            [0, 0],
            [0, 0],
            [0, 0],
            [1, 2],
        ],
        row_gap="25px",
    ),
    components=[
        vm.Graph(
            id="scatter_chart",
            figure=px.scatter(df, x="sepal_length", y="petal_width", color="species", custom_data=["species"]),
            actions=[
                vm.Action(
                    function=my_custom_action(),
                    inputs=["scatter_chart.clickData"],
                    outputs=["my_card_1.children", "my_card_2.children"], # (2)!
                ),
            ],
        ),
        vm.Card(id="my_card_1", text="Click on a point on the above graph."),
        vm.Card(id="my_card_2", text="Click on a point on the above graph."),
    ],
    controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))],
)

dashboard = vm.Dashboard(pages=[page])

Vizro().build(dashboard).run()

Run and edit this code in Py.Cafe

  1. my_custom_action returns two values (which will be in Python tuple).
  2. These values are assigned to the outputs in the same order.
# Custom actions are currently only possible via python configuration

CustomAction2

Warning

Note that users of this package are responsible for the content of any custom action function that they write - especially with regard to leaking any sensitive information or exposing to any security threat during implementation. You should always treat the content of user input as untrusted.