Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Enable dynamic filter #879

Merged
merged 77 commits into from
Dec 2, 2024
Merged
Changes from 1 commit
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
9449c73
Reduce to just one load function in filter.py
antonymilne Nov 4, 2024
b37f38f
Refactor set methods and add in __call__
antonymilne Nov 4, 2024
3d6f570
Fix tests
antonymilne Nov 4, 2024
68f6f61
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 4, 2024
9e6f62e
Add numpy lower bound
antonymilne Nov 4, 2024
574169b
Fix tests
antonymilne Nov 5, 2024
568dc58
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 5, 2024
b13e574
Fix tests
antonymilne Nov 5, 2024
01307bd
Add new tests and lint
antonymilne Nov 5, 2024
2ac895b
Final tidy
antonymilne Nov 5, 2024
2e4e0e2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 5, 2024
983940b
Fix min/max=0 bug
antonymilne Nov 6, 2024
13f022e
Move _get_targets_data_and_config into _get_modified_page_figures wit…
antonymilne Nov 6, 2024
a07fda4
Dynamic before filter tidy changes
petar-qb Nov 6, 2024
f2bd362
Turn _get_targets_data_and_config into _get_targets_data - tests pass
antonymilne Nov 6, 2024
1dbacb0
Turn _create_target_arg_mapping into _filter_dot_separated_string - t…
antonymilne Nov 6, 2024
f93d780
categorical selectors after the tidy/dynamic-filter
petar-qb Nov 6, 2024
4d0fb0e
Split up filtered and unfiltered data, create _multi_load, rework Fil…
antonymilne Nov 7, 2024
1a859ff
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 7, 2024
2b3b0ae
Support for Slider and RangeSlider to work as RadioItems
petar-qb Nov 7, 2024
30aa52a
Merge remote-tracking branch 'origin/main' into tidy/dynamic-filter-2
antonymilne Nov 7, 2024
d097733
Lint and small fixes
antonymilne Nov 7, 2024
0f5b096
pull changes from tidy/dynamic-filter-2
petar-qb Nov 8, 2024
d3c677e
dynamic filters implemented as on_page_load targets
petar-qb Nov 12, 2024
1d602ea
Propagating data_frame parameter values as load–kwargs from the model…
petar-qb Nov 13, 2024
2a94f6c
Merge main into the feature branch
petar-qb Nov 13, 2024
e066fdb
More improvements
petar-qb Nov 15, 2024
9e5a239
Reverting: Sending DFP values from the MM to Filter.pre_build DM._mul…
petar-qb Nov 15, 2024
5f161aa
Merge branch 'main' of https://github.com/mckinsey/vizro into feat/dy…
petar-qb Nov 15, 2024
cfdf4fc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2024
8ca5382
Minor code cleaning
petar-qb Nov 15, 2024
472f7a8
Solving conflicts
petar-qb Nov 15, 2024
1e3ba7f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2024
41adc9e
Minor refactoring
petar-qb Nov 15, 2024
b912bb0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2024
1d2a9c5
Minor refactoring
petar-qb Nov 15, 2024
d1bd246
Merge branch 'feat/dynamic-filter' of https://github.com/mckinsey/viz…
petar-qb Nov 15, 2024
a89b8bf
Minor comment change
petar-qb Nov 18, 2024
48e6716
More refactoring
petar-qb Nov 18, 2024
161a1e9
Remove fetching unfiltered data for filter.targets
petar-qb Nov 19, 2024
e1db7ec
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 19, 2024
f13d131
Merge main with the feature branch
petar-qb Nov 19, 2024
b450404
Addressing PR comments
petar-qb Nov 21, 2024
82838f1
Lint
petar-qb Nov 21, 2024
53d73e5
Merge main with the feature branch
petar-qb Nov 21, 2024
db017a2
Unit tests
petar-qb Nov 25, 2024
e6208fa
Lint
petar-qb Nov 25, 2024
cad4694
Merge branch 'main' of https://github.com/mckinsey/vizro into feat/dy…
petar-qb Nov 25, 2024
a03aa45
[Docs] Dynamic filters (#891)
antonymilne Nov 25, 2024
985ec4c
Add review comments and questions and small changes
antonymilne Nov 25, 2024
66da134
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 25, 2024
3c60502
Add review comments and questions and small changes
antonymilne Nov 25, 2024
ca6b4ad
Add todo for filter.build()
petar-qb Nov 26, 2024
9fd0f1d
First chunk of PR comments
petar-qb Nov 26, 2024
1433734
_get_min_max and _get_options improvements
petar-qb Nov 27, 2024
fa5f172
Simple Filter.__call__() tests
petar-qb Nov 28, 2024
d91a151
Removing FILTER_COLUMN from app.py
petar-qb Nov 28, 2024
0bf501c
Merge main with the feature branch
petar-qb Nov 28, 2024
097c02e
Removing TODO
petar-qb Nov 28, 2024
86171e0
Hide selector during the dynamic filter reloading process
petar-qb Nov 29, 2024
9732692
A few comments added
petar-qb Nov 29, 2024
4c0f8e8
Docs improvements
antonymilne Nov 29, 2024
ff6f89a
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
9da32a8
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
9fc39e8
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
c037740
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
7ed7385
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 29, 2024
befb14d
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
1d9f606
Update vizro-core/docs/pages/user-guides/filters.md
antonymilne Nov 29, 2024
97aa9d1
Update vizro-core/docs/pages/user-guides/filters.md
antonymilne Nov 29, 2024
28562c3
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
ecba967
Update vizro-core/docs/pages/user-guides/data.md
antonymilne Nov 29, 2024
aa38a40
Remove one comment
petar-qb Nov 29, 2024
8fde5d9
Merge branch 'main' of https://github.com/mckinsey/vizro into feat/dy…
petar-qb Nov 29, 2024
744931d
TestFilterCall refactoring
petar-qb Nov 29, 2024
ca07e82
Merge branch 'main' of https://github.com/mckinsey/vizro into feat/dy…
petar-qb Nov 30, 2024
81a9bdb
PR comment referenced in the _actions_utils
petar-qb Dec 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
pre-commit-ci[bot] committed Nov 15, 2024
commit cfdf4fcebd0b8f4b64b9763a7fe9a1c54499aa1e
57 changes: 34 additions & 23 deletions vizro-core/examples/scratch_dev/_poc_dynamic_controls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import dash
import plotly.express as px

from dash import Dash, html, dcc, Output, callback, clientside_callback, Input, State, set_props
import dash_mantine_components as dmc

import plotly.express as px
from dash import Dash, Input, Output, State, callback, clientside_callback, dcc, html

CONTROL_SELECTOR = dcc.RangeSlider

@@ -90,18 +88,18 @@ def categorical_filter_build(options=None):
kwargs["multi"] = MULTI

return CONTROL_SELECTOR(
id=f'filter',
id="filter",
options=options or pre_build_options,
value=pre_build_categorical_value,
persistence=True,
persistence_type="session",
**kwargs
**kwargs,
)


def numerical_filter_build(min_value=None, max_value=None):
return CONTROL_SELECTOR(
id=f'filter',
id="filter",
min=min_value or pre_build_min,
max=max_value or pre_build_max,
value=pre_build_numerical_value,
@@ -117,7 +115,7 @@ def _get_initial_page_build_object():
if CONTROL_SELECTOR == dcc.Dropdown:
# A hack explained in on_page_load To-do:"Limitations" section below in this page.
return dmc.DateRangePicker(
id='filter',
id="filter",
value=pre_build_categorical_value,
persistence=True,
persistence_type="session",
@@ -133,27 +131,28 @@ def _get_initial_page_build_object():
[
dcc.Store(id="on_page_load_trigger_another_page"),
html.H2("Another page"),

# # This does NOT work because id="filter" doesn't exist but is used as OPL callback State.
# dcc.Loading(id="filter_container"),

# # Possible solution is to alter filter.options from on_page_load. This would work, but it's not optimal.
# dcc.Dropdown(id="filter", options=options, value=options, multi=True, persistence=True),

# # Outer container can be changed with dcc.Loading.
html.Div(
_get_initial_page_build_object(),
id="filter_container",
),

# # Does not work because OPL filter input is missing, but it's used for filtering figures data_frame.
# html.Div(
# html.Div(id="filter"),
# id="filter_container",
# ),

html.Br(),
dcc.RadioItems(id="parameter", options=["sepal_width", "sepal_length"], value="sepal_width", persistence=True, persistence_type="session"),
dcc.RadioItems(
id="parameter",
options=["sepal_width", "sepal_length"],
value="sepal_width",
persistence=True,
persistence_type="session",
),
dcc.Loading(dcc.Graph(id="graph1")),
dcc.Loading(dcc.Graph(id="graph2")),
]
@@ -206,11 +205,10 @@ def get_data(species):
],
inputs=[
Input("global_on_page_load_another_page_action_trigger", "data"),

State("filter", "value"),
State("parameter", "value"),
],
prevent_initial_call=True
prevent_initial_call=True,
)
def on_page_load(data, persisted_filter_value, x):
# Ideally, OPL flow should look like this:
@@ -263,9 +261,13 @@ def on_page_load(data, persisted_filter_value, x):
if CONTROL_SELECTOR in SELECTOR_TYPE["categorical"]:
categorical_filter_options = sorted(df["species"].unique().tolist())
if MULTI:
categorical_filter_value = [value for value in persisted_filter_value if value in categorical_filter_options]
categorical_filter_value = [
value for value in persisted_filter_value if value in categorical_filter_options
]
else:
categorical_filter_value = persisted_filter_value if persisted_filter_value in categorical_filter_options else None
categorical_filter_value = (
persisted_filter_value if persisted_filter_value in categorical_filter_options else None
)
new_filter_obj = categorical_filter_build(options=categorical_filter_options)

# --- Filtering data: ---
@@ -298,19 +300,28 @@ def on_page_load(data, persisted_filter_value, x):
numerical_filter_min = float(df["sepal_length"].min())
numerical_filter_max = float(df["sepal_length"].max())
if MULTI:
numerical_filter_value = [max(numerical_filter_min, persisted_filter_value[0]), min(numerical_filter_max, persisted_filter_value[1])]
numerical_filter_value = [
max(numerical_filter_min, persisted_filter_value[0]),
min(numerical_filter_max, persisted_filter_value[1]),
]
else:
numerical_filter_value = persisted_filter_value if numerical_filter_min < persisted_filter_value < numerical_filter_max else numerical_filter_min
numerical_filter_value = (
persisted_filter_value
if numerical_filter_min < persisted_filter_value < numerical_filter_max
else numerical_filter_min
)
new_filter_obj = numerical_filter_build(min_value=numerical_filter_min, max_value=numerical_filter_max)
# set_props(component_id="numerical_filter_container", props={"children": new_filter_obj})

# --- Filtering data: ---
if MULTI:
df = df[(df["sepal_length"] >= numerical_filter_value[0]) & (df["sepal_length"] <= numerical_filter_value[1])]
df = df[
(df["sepal_length"] >= numerical_filter_value[0]) & (df["sepal_length"] <= numerical_filter_value[1])
]
else:
df = df[(df["sepal_length"] == numerical_filter_value)]

print("")
print()
return graph1_call(df), graph2_call(df, x), new_filter_obj


@@ -394,4 +405,4 @@ def on_page_load(data, persisted_filter_value, x):
# IMPORTANT: also consider parametrised data case.

if __name__ == "__main__":
app.run(debug=True, dev_tools_hot_reload=False)
app.run(debug=True, dev_tools_hot_reload=False)
95 changes: 54 additions & 41 deletions vizro-core/examples/scratch_dev/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Dev app to try things out."""

import time
import yaml

@@ -27,24 +28,35 @@
def load_from_file(filter_column=None, parametrized_species=None):
# Load the full iris dataset
df = px.data.iris()
df['date_column'] = pd.date_range(start=pd.to_datetime("2024-01-01"), periods=len(df), freq='D')
df["date_column"] = pd.date_range(start=pd.to_datetime("2024-01-01"), periods=len(df), freq="D")

if parametrized_species:
return df[df["species"].isin(parametrized_species)]

with open('data.yaml', 'r') as file:
with open("data.yaml", "r") as file:
data = yaml.safe_load(file)
data = data or {}

filter_column = filter_column or FILTER_COLUMN
if filter_column == "species":
final_df = pd.concat(objs=[
df[df[filter_column] == 'setosa'].head(data.get("setosa", 0)),
df[df[filter_column] == 'versicolor'].head(data.get("versicolor", 0)),
df[df[filter_column] == 'virginica'].head(data.get("virginica", 0)),
], ignore_index=True)
final_df = pd.concat(
objs=[
df[df[filter_column] == "setosa"].head(data.get("setosa", 0)),
df[df[filter_column] == "versicolor"].head(data.get("versicolor", 0)),
df[df[filter_column] == "virginica"].head(data.get("virginica", 0)),
],
ignore_index=True,
)
elif filter_column == "sepal_length":
final_df = df[df[filter_column].between(data.get("min"), data.get("max",), inclusive="both")]
final_df = df[
df[filter_column].between(
data.get("min"),
data.get(
"max",
),
inclusive="both",
)
]
elif filter_column == "date_column":
date_min = pd.to_datetime(data.get("date_min"))
date_max = pd.to_datetime(data.get("date_max"))
@@ -82,16 +94,18 @@ def load_from_file(filter_column=None, parametrized_species=None):
vm.Graph(
id="p1-G-2",
figure=px.scatter(data_frame=px.data.iris(), **SCATTER_CHART_CONF),
)
),
],
controls=[
vm.Filter(id="p1-F-1", column="species", targets=["p1-G-1"], selector=vm.Dropdown(title="Dynamic filter")),
vm.Filter(id="p1-F-2", column="species", targets=["p1-G-2"], selector=vm.Dropdown(title="Static filter")),
vm.Parameter(
targets=["p1-G-1.x", "p1-G-2.x"],
selector=vm.RadioItems(options=["species", "sepal_width"], value="species", title="Simple X-axis parameter")
)
]
selector=vm.RadioItems(
options=["species", "sepal_width"], value="species", title="Simple X-axis parameter"
),
),
],
)


@@ -110,9 +124,11 @@ def load_from_file(filter_column=None, parametrized_species=None):
vm.Filter(id="p2-F-4", column="species", selector=vm.RadioItems()),
vm.Parameter(
targets=["p2-G-1.x"],
selector=vm.RadioItems(options=["species", "sepal_width"], value="species", title="Simple X-axis parameter")
)
]
selector=vm.RadioItems(
options=["species", "sepal_width"], value="species", title="Simple X-axis parameter"
),
),
],
)


@@ -129,9 +145,11 @@ def load_from_file(filter_column=None, parametrized_species=None):
vm.Filter(id="p3-F-2", column="sepal_length", selector=vm.RangeSlider()),
vm.Parameter(
targets=["p3-G-1.x"],
selector=vm.RadioItems(options=["species", "sepal_width"], value="species", title="Simple X-axis parameter")
)
]
selector=vm.RadioItems(
options=["species", "sepal_width"], value="species", title="Simple X-axis parameter"
),
),
],
)

page_4 = vm.Page(
@@ -147,9 +165,11 @@ def load_from_file(filter_column=None, parametrized_species=None):
vm.Filter(id="p4-F-2", column="date_column", selector=vm.DatePicker()),
vm.Parameter(
targets=["p4-G-1.x"],
selector=vm.RadioItems(options=["species", "sepal_width"], value="species", title="Simple X-axis parameter")
)
]
selector=vm.RadioItems(
options=["species", "sepal_width"], value="species", title="Simple X-axis parameter"
),
),
],
)

page_5 = vm.Page(
@@ -170,73 +190,66 @@ def load_from_file(filter_column=None, parametrized_species=None):
# "p5-F-1.",
],
selector=vm.Dropdown(
options=["setosa", "versicolor", "virginica"],
multi=True,
title="Parametrized species"
)
options=["setosa", "versicolor", "virginica"], multi=True, title="Parametrized species"
),
),
vm.Parameter(
targets=[
"p5-G-1.x",
# TODO: Uncomment the following target and see the magic :D
# "p5-F-1.",
],
selector=vm.RadioItems(options=["species", "sepal_width"], value="species", title="Simple X-axis parameter")
selector=vm.RadioItems(
options=["species", "sepal_width"], value="species", title="Simple X-axis parameter"
),
),
]
],
)


page_6 = vm.Page(
title="Page to test things out",
components=[
vm.Graph(
id="graph_dynamic",
figure=px.bar(data_frame="load_from_file", **BAR_CHART_CONF)
),
vm.Graph(id="graph_dynamic", figure=px.bar(data_frame="load_from_file", **BAR_CHART_CONF)),
vm.Graph(
id="graph_static",
figure=px.scatter(data_frame=px.data.iris(), **SCATTER_CHART_CONF),
)
),
],
controls=[
vm.Filter(
id="filter_container_id",
column=FILTER_COLUMN,
targets=["graph_dynamic"],
# targets=["graph_static"],

# selector=vm.Dropdown(id="filter_id"),
# selector=vm.Dropdown(id="filter_id", value=["setosa"]),

# selector=vm.Checklist(id="filter_id"),
# selector=vm.Checklist(id="filter_id", value=["setosa"]),

# TODO-BUG: vm.Dropdown(multi=False) Doesn't work if value is cleared. The persistence storage become
# "null" and our placeholder component dmc.DateRangePicker can't process null value. It expects a value or
# a list of values.
# SOLUTION -> Create the "Universal Vizro placeholder component".
# TEMPORARY SOLUTION -> set clearable=False for the dynamic Dropdown(multi=False)
# selector=vm.Dropdown(id="filter_id", multi=False), ->
# selector=vm.Dropdown(id="filter_id", multi=False, value="setosa"),

# selector=vm.RadioItems(id="filter_id"),
# selector=vm.RadioItems(id="filter_id", value="setosa"),

# selector=vm.Slider(id="filter_id"),
# selector=vm.Slider(id="filter_id", value=5),

# selector=vm.RangeSlider(id="filter_id"),
# selector=vm.RangeSlider(id="filter_id", value=[5, 7]),
),
),
vm.Parameter(
id="parameter_x",
targets=["graph_dynamic.x",],
targets=[
"graph_dynamic.x",
],
selector=vm.Dropdown(
options=["species", "sepal_width"],
value="species",
multi=False,
)
),
),
],
)
2 changes: 1 addition & 1 deletion vizro-core/examples/scratch_dev/data.yaml
Original file line number Diff line number Diff line change
@@ -10,4 +10,4 @@ max: 7
# Choose from:
# 2020-01-01 to 2020-05-29
date_min: 2024-01-01
date_max: 2024-05-29
date_max: 2024-05-29
10 changes: 6 additions & 4 deletions vizro-core/src/vizro/actions/_actions_utils.py
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
from vizro.models.types import MultiValueType, SelectorType, SingleValueType

if TYPE_CHECKING:
from vizro.models import Action, VizroBaseModel, Filter
from vizro.models import Action, VizroBaseModel

ValidatedNoneValueType = Union[SingleValueType, MultiValueType, None, list[None]]

@@ -162,6 +162,7 @@ def _update_nested_figure_properties(
current_property[keys[-1]] = value
return figure_config


def _get_parametrized_config(
ctd_parameter: list[CallbackTriggerDict], target: ModelID, data_frame: bool
) -> dict[str, Any]:
@@ -275,7 +276,9 @@ def _get_modified_page_figures(
# Also, it was a good decision to return action output as key: value pairs for the predefined actions.
_get_unfiltered_data_targets = list(set(figure_targets + control_targets_targets))

figure_targets_unfiltered_data: dict[ModelID, pd.DataFrame] = _get_unfiltered_data(ctds_parameter, _get_unfiltered_data_targets)
figure_targets_unfiltered_data: dict[ModelID, pd.DataFrame] = _get_unfiltered_data(
ctds_parameter, _get_unfiltered_data_targets
)

for target, unfiltered_data in figure_targets_unfiltered_data.items():
if target in figure_targets:
@@ -292,8 +295,7 @@ def _get_modified_page_figures(
current_value = []

outputs[target] = model_manager[target](
target_to_data_frame=figure_targets_unfiltered_data,
current_value=current_value
target_to_data_frame=figure_targets_unfiltered_data, current_value=current_value
)

return outputs
17 changes: 8 additions & 9 deletions vizro-core/src/vizro/actions/_on_page_load_action.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@
from vizro.actions._actions_utils import _get_modified_page_figures
from vizro.managers._model_manager import ModelID
from vizro.models.types import capture
from vizro.managers import model_manager, data_manager


@capture("action")
@@ -46,17 +45,17 @@ def _on_page_load(targets: list[ModelID], **inputs: dict[str, Any]) -> dict[Mode
# if current_value in ["ALL", ["ALL"]]:
# current_value = []

# TODO: Also propagate DFP values into the load() method
# 1. "new_options"/"min/max" DOES NOT include the "current_value"
# filter_obj._set_categorical_selectors_options(force=True, current_value=[])
# TODO: Also propagate DFP values into the load() method
# 1. "new_options"/"min/max" DOES NOT include the "current_value"
# filter_obj._set_categorical_selectors_options(force=True, current_value=[])

# 2. "new_options" DOES include the "current_value"
# filter_obj._set_categorical_selectors_options(force=True, current_value=current_value)
# filter_obj._set_numerical_and_temporal_selectors_values(force=True, current_value=current_value)
# 2. "new_options" DOES include the "current_value"
# filter_obj._set_categorical_selectors_options(force=True, current_value=current_value)
# filter_obj._set_numerical_and_temporal_selectors_values(force=True, current_value=current_value)

# return_obj[filter_id] = filter_obj.selector(on_page_load_value=current_value)
# return_obj[filter_id] = filter_obj.selector(on_page_load_value=current_value)

# return_obj[filter_id] = filter_obj(current_value=current_value)
# return_obj[filter_id] = filter_obj(current_value=current_value)

print("ON PAGE LOAD - END\n")

8 changes: 2 additions & 6 deletions vizro-core/src/vizro/models/_components/form/dropdown.py
Original file line number Diff line number Diff line change
@@ -125,12 +125,8 @@ def _build_dynamic_placeholder(self):
children=[
dbc.Label(self.title, html_for=self.id) if self.title else None,
dmc.DateRangePicker(
id=self.id,
value=self.value,
persistence=True,
persistence_type="session",
style={'opacity': 0}
)
id=self.id, value=self.value, persistence=True, persistence_type="session", style={"opacity": 0}
),
]
)

Original file line number Diff line number Diff line change
@@ -126,7 +126,7 @@ def _build_static(self, current_value=None, new_min=None, new_max=None, **kwargs
persistence_type="session",
className="slider-text-input-field",
),
dcc.Store(id=f"{self.id}_input_store", storage_type="session")
dcc.Store(id=f"{self.id}_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
@@ -154,4 +154,4 @@ def _build_dynamic_placeholder(self):
def build(self):
# TODO: We don't have to implement _build_dynamic_placeholder, _build_static here. It's possible to:
# if dynamic and self.value is None -> set self.value + return standard build (static)
return self._build_dynamic_placeholder() if self._dynamic else self._build_static()
return self._build_dynamic_placeholder() if self._dynamic else self._build_static()
2 changes: 1 addition & 1 deletion vizro-core/src/vizro/models/_components/form/slider.py
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ def _build_static(self, current_value=None, new_min=None, new_max=None, **kwargs
persistence_type="session",
className="slider-text-input-field",
),
dcc.Store(id=f"{self.id}_input_store", storage_type="session")
dcc.Store(id=f"{self.id}_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
16 changes: 6 additions & 10 deletions vizro-core/src/vizro/models/_controls/filter.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from __future__ import annotations

from dash import dcc, html

from typing import Any, Literal, Union

import numpy as np
import pandas as pd
from dash import dcc
from pandas.api.types import is_datetime64_any_dtype, is_numeric_dtype

from vizro.managers._data_manager import DataSourceName
@@ -18,6 +17,7 @@
from vizro._constants import FILTER_ACTION_PREFIX
from vizro.actions import _filter
from vizro.managers import data_manager, model_manager
from vizro.managers._data_manager import _DynamicData
from vizro.managers._model_manager import ModelID
from vizro.models import Action, VizroBaseModel
from vizro.models._components.form import (
@@ -30,8 +30,6 @@
)
from vizro.models._models_utils import _log_call
from vizro.models.types import MultiValueType, SelectorType
from vizro.models._components.form._form_utils import get_options_and_default
from vizro.managers._data_manager import _DynamicData

# Ideally we might define these as NumericalSelectorType = Union[RangeSlider, Slider] etc., but that will not work
# with isinstance checks.
@@ -179,12 +177,10 @@ def pre_build(self):
# Selector doesn't support dynamic mode
# Selector is categorical and "options" is defined
# Selector is numerical/Temporal and "min" and "max" are defined
if (
isinstance(self.selector, DYNAMIC_SELECTORS) and
(
hasattr(self.selector, "options") and not getattr(self.selector, "options") or
all(hasattr(self.selector, attr) and getattr(self.selector, attr) is None for attr in ["min", "max"])
)
if isinstance(self.selector, DYNAMIC_SELECTORS) and (
hasattr(self.selector, "options")
and not getattr(self.selector, "options")
or all(hasattr(self.selector, attr) and getattr(self.selector, attr) is None for attr in ["min", "max"])
):
for target_id in self.targets:
data_source_name = model_manager[target_id]["data_frame"]
28 changes: 21 additions & 7 deletions vizro-core/src/vizro/static/js/models/range_slider.js
Original file line number Diff line number Diff line change
@@ -28,19 +28,33 @@ function update_range_slider_values(
}
return [start, end, [start, end], [start, end]];

// slider component is the trigger
// slider component is the trigger
} else if (trigger_id === self_data["id"]) {
return [slider[0], slider[1], slider, slider];

// on_page_load is the trigger
// on_page_load is the trigger
} else {
if (input_store === null) {
return [dash_clientside.no_update, dash_clientside.no_update, dash_clientside.no_update, slider];
}
else {
if (slider[0] === start && input_store[0] === start && slider[1] === end && input_store[1] === end){
return [
dash_clientside.no_update,
dash_clientside.no_update,
dash_clientside.no_update,
slider,
];
} else {
if (
slider[0] === start &&
input_store[0] === start &&
slider[1] === end &&
input_store[1] === end
) {
// To prevent filter_action to be triggered after on_page_load
return [dash_clientside.no_update, dash_clientside.no_update, dash_clientside.no_update, dash_clientside.no_update];
return [
dash_clientside.no_update,
dash_clientside.no_update,
dash_clientside.no_update,
dash_clientside.no_update,
];
}
return [input_store[0], input_store[1], input_store, input_store];
}
14 changes: 8 additions & 6 deletions vizro-core/src/vizro/static/js/models/slider.js
Original file line number Diff line number Diff line change
@@ -14,26 +14,28 @@ function update_slider_values(start, slider, input_store, self_data) {
}
return [start, start, start];

// slider component is the trigger
// slider component is the trigger
} else if (trigger_id === self_data["id"]) {
return [slider, slider, slider];

// on_page_load is the trigger
// on_page_load is the trigger
} else {
if (input_store === null) {
return [dash_clientside.no_update, dash_clientside.no_update, slider];
}
else {
} else {
if (slider === start && start === input_store) {
// To prevent filter_action to be triggered after on_page_load
return [dash_clientside.no_update, dash_clientside.no_update, dash_clientside.no_update];
return [
dash_clientside.no_update,
dash_clientside.no_update,
dash_clientside.no_update,
];
}
return [input_store, input_store, input_store];
}
}
}


window.dash_clientside = {
...window.dash_clientside,
slider: { update_slider_values: update_slider_values },