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:
- define a function
- decorate it with the
@capture("action")
decorator - add it as a
function
argument inside theAction
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
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 toinputs
, 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
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
- Just as for any Python function, the names of the arguments
show_species
andpoints_data
are arbitrary and do not need to match on to the names ofinputs
in any particular way. - We bind (set) the argument
show_species
to the valueTrue
in the initial specification of thefunction
field. These are static values that are fixed when the dashboard is built. - The content of
inputs
will "fill in the gaps" by setting values for the remaining unbound arguments inmy_custom_action
. Here there is one such argument, namedpoints_data
. Values for these are bound dynamically at runtime to reflect the live state of your dashboard.
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
my_custom_action
returns two values (which will be in Python tuple).- These values are assigned to the
outputs
in the same order.
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.