Skip to content

Commit 7285a39

Browse files
committed
Enable dynamic filter to be updated from dfp - implicit configuration api
1 parent 0d66cd7 commit 7285a39

File tree

6 files changed

+73
-59
lines changed

6 files changed

+73
-59
lines changed
+43-52
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,58 @@
1-
"""Test app"""
1+
import time
2+
3+
import pandas as pd
24

35
import vizro.models as vm
46
import vizro.plotly.express as px
57
from vizro import Vizro
8+
from vizro.managers import data_manager
69

7-
iris = px.data.iris()
810

9-
page = vm.Page(
10-
title="Page with subsections",
11-
layout=vm.Layout(grid=[[0, 0, 1, 1, 2, 2], [3, 3, 3, 4, 4, 4], [3, 3, 3, 4, 4, 4]]),
12-
components=[
13-
vm.Card(text="""Hello, this is a card with a [link](https://www.google.com)"""),
14-
vm.Card(text="""Hello, this is a card with a [link](https://www.google.com)"""),
15-
vm.Card(text="""Hello, this is a card with a [link](https://www.google.com)"""),
16-
vm.Container(
17-
title="Container I",
18-
components=[
19-
vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species")),
20-
],
21-
variant="outlined",
22-
),
23-
vm.Container(
24-
title="Container II",
25-
components=[
26-
vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species")),
27-
],
28-
variant="filled",
29-
),
30-
],
31-
)
11+
static_df = pd.DataFrame({
12+
"species": ["artificial_species", "artificial_species", "artificial_species"],
13+
"sepal_width": [4, 5, 6],
14+
"sepal_length": [4, 5, 6],
15+
})
3216

33-
page_two = vm.Page(
34-
title="Container",
35-
components=[
36-
vm.Container(
37-
title="Container III",
38-
components=[
39-
vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species")),
40-
],
41-
),
42-
],
43-
)
4417

45-
page_three = vm.Page(
46-
title="Container Style",
18+
def load_data(number_of_points=150):
19+
# Artificial delay to simulate data loading in production
20+
print("\nLoading data...\n")
21+
time.sleep(1)
22+
23+
return px.data.iris().head(number_of_points)
24+
25+
26+
data_manager["dynamic_df"] = load_data
27+
28+
page_1 = vm.Page(
29+
title="Update dynamic filter from DFP",
4730
components=[
48-
vm.Container(
49-
title="Container I",
50-
components=[
51-
vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species")),
52-
],
53-
variant="outlined",
54-
),
55-
vm.Container(
56-
title="Container II",
57-
components=[
58-
vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species")),
59-
],
60-
variant="filled",
31+
vm.Graph(
32+
id="dynamic_graph_1",
33+
figure=px.scatter(data_frame="dynamic_df", x="sepal_width", y="sepal_length", color="species"),
6134
),
35+
vm.Graph(
36+
figure=px.scatter(data_frame=static_df, x="sepal_width", y="sepal_length", color="species"),
37+
)
6238
],
39+
controls=[
40+
vm.Filter(column="species", selector=vm.RadioItems()),
41+
vm.Parameter(
42+
targets=["dynamic_graph_1.data_frame.number_of_points"],
43+
selector=vm.Slider(
44+
min=0,
45+
max=150,
46+
value=150,
47+
title="Number of points",
48+
step=10,
49+
)
50+
),
51+
]
6352
)
64-
dashboard = vm.Dashboard(pages=[page, page_two, page_three])
53+
54+
dashboard = vm.Dashboard(pages=[page_1])
55+
6556

6657
if __name__ == "__main__":
6758
Vizro().build(dashboard).run()

vizro-core/src/vizro/_vizro.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ def _pre_build():
153153
# Run pre_build on all filters first, then on all other models. This handles dependency between Filter
154154
# and Page pre_build and ensures that filters are pre-built before the Page objects that use them.
155155
# This is important because the Page pre_build method checks whether filters are dynamic or not, which is
156-
# defined in the filter's pre_build method.
156+
# defined in the filter's pre_build method. Also, the calculation of the data_frame Parameter targets
157+
# depends on the filter targets, so they should be pre-built after the filters as well.
157158
filter.pre_build()
158159
for model_id in set(model_manager):
159160
model = model_manager[model_id]

vizro-core/src/vizro/actions/_actions_utils.py

-4
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,6 @@ def _get_modified_page_figures(
271271
else:
272272
figure_targets.append(target)
273273

274-
# TODO-NEXT: Add fetching unfiltered data for the Filter.targets as well, once dynamic filters become "targetable"
275-
# from other actions too. For example, in future, if Parameter is targeting only a single Filter.
276-
# Currently, it only works for the on_page_load because Filter.targets are indeed the part of the actions' targets.
277-
# More about the limitation: https://github.com/mckinsey/vizro/pull/879/files#r1863535516
278274
target_to_data_frame = _get_unfiltered_data(ctds_parameter=ctds_parameter, targets=figure_targets)
279275

280276
# TODO: the structure here would be nicer if we could get just the ctds for a single target at one time,

vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def _get_action_callback_outputs(action: Action) -> dict[str, Output]:
9797
targets = []
9898

9999
if action_function == _parameter.__wrapped__:
100-
targets = [target.split(".")[0] for target in targets]
100+
targets = [target.split(".")[0] if "." in target else target for target in targets]
101101

102102
return {
103103
target: Output(

vizro-core/src/vizro/actions/_parameter_action.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def _parameter(targets: list[str], **inputs: dict[str, Any]) -> dict[ModelID, An
2222
Dict mapping target component ids to modified charts/components e.g. {'my_scatter': Figure({})}
2323
2424
"""
25-
target_ids: list[ModelID] = [target.split(".")[0] for target in targets] # type: ignore[misc]
25+
target_ids: list[ModelID] = [target.split(".")[0] if "." in target else target for target in targets] # type: ignore[misc]
2626

2727
return _get_modified_page_figures(
2828
ctds_filter=ctx.args_grouping["external"]["filters"],

vizro-core/src/vizro/models/_controls/parameter.py

+26
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,33 @@ def _set_selector_title(self):
104104
self.selector.title = ", ".join({target.rsplit(".")[-1] for target in self.targets})
105105

106106
def _set_actions(self):
107+
from vizro.models import Filter
108+
107109
if not self.selector.actions:
110+
page_dynamic_filters = [
111+
filter
112+
for filter in cast(
113+
Iterable[Filter],
114+
model_manager._get_models(Filter, page=model_manager._get_model_page(self))
115+
)
116+
if filter._dynamic
117+
]
118+
119+
filter_targets = set()
120+
121+
# Extend parameter targets with dynamic filters linked to the same figure.
122+
# Also, include dynamic filter targets to ensure new filter options are correctly calculated
123+
# and filter targets are updated when filter values change.
124+
for figure_target in self.targets:
125+
figure_target_id, figure_target_argument = figure_target.split(".", 1)
126+
if figure_target_argument.startswith("data_frame"):
127+
for filter in page_dynamic_filters:
128+
if figure_target_id in filter.targets:
129+
filter_targets.add(filter.id)
130+
filter_targets |= set(filter.targets)
131+
132+
self.targets.extend(list(filter_targets))
133+
108134
self.selector.actions = [
109135
Action(id=f"{PARAMETER_ACTION_PREFIX}_{self.id}", function=_parameter(targets=self.targets))
110136
]

0 commit comments

Comments
 (0)