-
Notifications
You must be signed in to change notification settings - Fork 142
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/dynamic filter #879
Draft
petar-qb
wants to merge
37
commits into
main
Choose a base branch
from
feat/dynamic-filter
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+575
−136
Draft
Feat/dynamic filter #879
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
9449c73
Reduce to just one load function in filter.py
antonymilne b37f38f
Refactor set methods and add in __call__
antonymilne 3d6f570
Fix tests
antonymilne 68f6f61
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 9e6f62e
Add numpy lower bound
antonymilne 574169b
Fix tests
antonymilne 568dc58
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] b13e574
Fix tests
antonymilne 01307bd
Add new tests and lint
antonymilne 2ac895b
Final tidy
antonymilne 2e4e0e2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 983940b
Fix min/max=0 bug
antonymilne 13f022e
Move _get_targets_data_and_config into _get_modified_page_figures wit…
antonymilne a07fda4
Dynamic before filter tidy changes
petar-qb f2bd362
Turn _get_targets_data_and_config into _get_targets_data - tests pass
antonymilne 1dbacb0
Turn _create_target_arg_mapping into _filter_dot_separated_string - t…
antonymilne f93d780
categorical selectors after the tidy/dynamic-filter
petar-qb 4d0fb0e
Split up filtered and unfiltered data, create _multi_load, rework Fil…
antonymilne 1a859ff
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 2b3b0ae
Support for Slider and RangeSlider to work as RadioItems
petar-qb 30aa52a
Merge remote-tracking branch 'origin/main' into tidy/dynamic-filter-2
antonymilne d097733
Lint and small fixes
antonymilne 0f5b096
pull changes from tidy/dynamic-filter-2
petar-qb d3c677e
dynamic filters implemented as on_page_load targets
petar-qb 1d602ea
Propagating data_frame parameter values as load–kwargs from the model…
petar-qb 2a94f6c
Merge main into the feature branch
petar-qb e066fdb
More improvements
petar-qb 9e5a239
Reverting: Sending DFP values from the MM to Filter.pre_build DM._mul…
petar-qb 5f161aa
Merge branch 'main' of https://github.com/mckinsey/vizro into feat/dy…
petar-qb cfdf4fc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 8ca5382
Minor code cleaning
petar-qb 472f7a8
Solving conflicts
petar-qb 1e3ba7f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 41adc9e
Minor refactoring
petar-qb b912bb0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 1d2a9c5
Minor refactoring
petar-qb d1bd246
Merge branch 'feat/dynamic-filter' of https://github.com/mckinsey/viz…
petar-qb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,255 @@ | ||
"""Dev app to try things out.""" | ||
|
||
import time | ||
import yaml | ||
|
||
import dash | ||
import pandas as pd | ||
from flask_caching import Cache | ||
|
||
import vizro.models as vm | ||
import vizro.plotly.express as px | ||
from vizro import Vizro | ||
from vizro._themes._color_values import COLORS | ||
|
||
pastry = pd.DataFrame( | ||
{ | ||
"pastry": [ | ||
"Scones", | ||
"Bagels", | ||
"Muffins", | ||
"Cakes", | ||
"Donuts", | ||
"Cookies", | ||
"Croissants", | ||
"Eclairs", | ||
"Brownies", | ||
"Tarts", | ||
"Macarons", | ||
"Pies", | ||
], | ||
"Profit Ratio": [-0.10, -0.15, -0.05, 0.10, 0.05, 0.20, 0.15, -0.08, 0.08, -0.12, 0.02, -0.07], | ||
} | ||
from vizro.managers import data_manager | ||
from functools import partial | ||
|
||
print("INITIALIZING") | ||
|
||
SPECIES_COLORS = {"setosa": "#00b4ff", "versicolor": "#ff9222", "virginica": "#3949ab"} | ||
BAR_CHART_CONF = dict(x="species", color="species", color_discrete_map=SPECIES_COLORS) | ||
SCATTER_CHART_CONF = dict(x="sepal_length", y="petal_length", color="species", color_discrete_map=SPECIES_COLORS) | ||
|
||
# Relevant for the "page_6" only | ||
FILTER_COLUMN = "species" | ||
# FILTER_COLUMN = "sepal_length" | ||
# FILTER_COLUMN = "date_column" | ||
|
||
|
||
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") | ||
|
||
if parametrized_species: | ||
return df[df["species"].isin(parametrized_species)] | ||
|
||
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, | ||
) | ||
elif filter_column == "sepal_length": | ||
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")) | ||
final_df = df[df[filter_column].between(date_min, date_max, inclusive="both")] | ||
else: | ||
raise ValueError("Invalid FILTER_COLUMN") | ||
|
||
return final_df | ||
|
||
|
||
data_manager["load_from_file"] = load_from_file | ||
data_manager["load_from_file_species"] = partial(load_from_file, filter_column="species") | ||
data_manager["load_from_file_sepal_length"] = partial(load_from_file, filter_column="sepal_length") | ||
data_manager["load_from_file_date_column"] = partial(load_from_file, filter_column="date_column") | ||
|
||
|
||
# TODO-DEV: Turn on/off caching to see how it affects the app. | ||
# data_manager.cache = Cache(config={"CACHE_TYPE": "SimpleCache", "CACHE_DEFAULT_TIMEOUT": 5}) | ||
|
||
|
||
homepage = vm.Page( | ||
title="Homepage", | ||
components=[ | ||
vm.Card(text="This is the homepage."), | ||
], | ||
) | ||
|
||
page_1 = vm.Page( | ||
title="Dynamic vs Static filter", | ||
components=[ | ||
vm.Graph( | ||
id="p1-G-1", | ||
figure=px.bar(data_frame="load_from_file_species", **BAR_CHART_CONF), | ||
), | ||
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"], title="Simple X-axis parameter"), | ||
), | ||
], | ||
) | ||
|
||
page = vm.Page( | ||
title="Charts UI", | ||
|
||
page_2 = vm.Page( | ||
title="Categorical dynamic selectors", | ||
components=[ | ||
vm.Graph( | ||
figure=px.bar( | ||
pastry.sort_values("Profit Ratio"), | ||
orientation="h", | ||
x="Profit Ratio", | ||
y="pastry", | ||
color="Profit Ratio", | ||
color_continuous_scale=COLORS["DIVERGING_RED_CYAN"], | ||
id="p2-G-1", | ||
figure=px.bar(data_frame="load_from_file_species", **BAR_CHART_CONF), | ||
), | ||
], | ||
controls=[ | ||
vm.Filter(id="p2-F-1", column="species", selector=vm.Dropdown()), | ||
vm.Filter(id="p2-F-2", column="species", selector=vm.Dropdown(multi=False)), | ||
vm.Filter(id="p2-F-3", column="species", selector=vm.Checklist()), | ||
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" | ||
), | ||
), | ||
], | ||
) | ||
|
||
dashboard = vm.Dashboard(pages=[page]) | ||
|
||
page_3 = vm.Page( | ||
title="Numerical dynamic selectors", | ||
components=[ | ||
vm.Graph( | ||
id="p3-G-1", | ||
figure=px.bar(data_frame="load_from_file_sepal_length", **BAR_CHART_CONF), | ||
), | ||
], | ||
controls=[ | ||
vm.Filter(id="p3-F-1", column="sepal_length", selector=vm.Slider()), | ||
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" | ||
), | ||
), | ||
], | ||
) | ||
|
||
page_4 = vm.Page( | ||
title="[TO BE DONE IN THE FOLLOW UP PR] Temporal dynamic selectors", | ||
components=[ | ||
vm.Graph( | ||
id="p4-G-1", | ||
figure=px.bar(data_frame="load_from_file_date_column", **BAR_CHART_CONF), | ||
), | ||
], | ||
controls=[ | ||
vm.Filter(id="p4-F-1", column="date_column", selector=vm.DatePicker(range=False)), | ||
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" | ||
), | ||
), | ||
], | ||
) | ||
|
||
page_5 = vm.Page( | ||
title="Parametrised dynamic selectors", | ||
components=[ | ||
vm.Graph( | ||
id="p5-G-1", | ||
figure=px.bar(data_frame="load_from_file_species", **BAR_CHART_CONF), | ||
), | ||
], | ||
controls=[ | ||
vm.Filter(id="p5-F-1", column="species", targets=["p5-G-1"], selector=vm.Checklist()), | ||
vm.Parameter( | ||
targets=[ | ||
"p5-G-1.data_frame.parametrized_species", | ||
# TODO: Uncomment the following target and see the magic :D | ||
# Is this the indicator that parameter.targets prop has to support 'target' definition without the '.'? | ||
# "p5-F-1.", | ||
], | ||
selector=vm.Dropdown( | ||
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" | ||
), | ||
), | ||
], | ||
) | ||
|
||
|
||
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_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( | ||
targets=["graph_dynamic.x"], | ||
selector=vm.RadioItems(options=["species", "sepal_width"], title="Simple X-axis parameter"), | ||
), | ||
], | ||
) | ||
|
||
dashboard = vm.Dashboard(pages=[homepage, page_1, page_2, page_3, page_4, page_5, page_6]) | ||
|
||
if __name__ == "__main__": | ||
Vizro().build(dashboard).run() | ||
app = Vizro().build(dashboard) | ||
|
||
print("RUNNING\n") | ||
|
||
app.run(dev_tools_hot_reload=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Choose from 0-50 | ||
setosa: 5 | ||
versicolor: 10 | ||
virginica: 15 | ||
|
||
# Choose from: 4.8 to 7.4 | ||
min: 5 | ||
max: 7 | ||
|
||
# Choose from: | ||
# 2020-01-01 to 2020-05-29 | ||
date_min: 2024-01-01 | ||
date_max: 2024-05-29 | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjusting these values, the input data is changed for the
scratch/app.py
example.