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] Recognise controls outside page.controls #903

Merged
merged 18 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
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
5 changes: 1 addition & 4 deletions vizro-ai/hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,9 @@ dependencies = [
"langchain-anthropic",
"pre-commit"
]
env-vars = {VIZRO_AI_LOG_LEVEL = "DEBUG"}
installer = "uv"

[envs.default.env-vars]
UV_PRERELEASE = "allow"
VIZRO_AI_LOG_LEVEL = "DEBUG"

petar-qb marked this conversation as resolved.
Show resolved Hide resolved
[envs.default.scripts]
example = "cd examples; python example.py"
example-create-dashboard = "cd examples; python example_dashboard.py"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!--
A new scriv changelog fragment.

Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Highlights ✨

- A bullet item for the Highlights ✨ category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Removed

- A bullet item for the Removed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Added

- A bullet item for the Added category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->

### Changed

- Custom controls can be nested arbitrarily deep inside `Page.controls`. ([#903](https://github.com/mckinsey/vizro/pull/903))
petar-qb marked this conversation as resolved.
Show resolved Hide resolved

<!--
### Deprecated

- A bullet item for the Deprecated category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Fixed

- A bullet item for the Fixed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Security

- A bullet item for the Security category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
95 changes: 52 additions & 43 deletions vizro-core/examples/scratch_dev/app.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,69 @@
"""Dev app to try things out."""
from typing import List, Literal

from dash import html

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

df_gapminder = px.data.gapminder()


class ControlGroup(vm.VizroBaseModel):
"""Container to group controls."""

type: Literal["control_group"] = "control_group"
title: str
controls: List[ControlType] = []

gapminder_2007 = px.data.gapminder().query("year == 2007")
def build(self):
return html.Div(
[html.H4(self.title), html.Hr()] + [control.build() for control in self.controls],
)

page = vm.Page(
title="Tabs",

vm.Page.add_type("controls", ControlGroup)

page1 = vm.Page(
title="Relationship Analysis",
components=[
vm.Tabs(
tabs=[
vm.Container(
title="Tab I",
components=[
vm.Graph(
title="Graph I",
figure=px.bar(
gapminder_2007,
x="continent",
y="lifeExp",
color="continent",
),
),
vm.Graph(
title="Graph II",
figure=px.box(
gapminder_2007,
x="continent",
y="lifeExp",
color="continent",
),
),
],
vm.Graph(id="scatter", figure=px.scatter(df_gapminder, x="gdpPercap", y="lifeExp", size="pop")),
],
controls=[
ControlGroup(
title="Group A",
controls=[
vm.Parameter(
id="this",
targets=["scatter.x"],
selector=vm.Dropdown(
options=["lifeExp", "gdpPercap", "pop"], multi=False, value="gdpPercap", title="Choose x-axis"
),
),
vm.Container(
title="Tab II",
components=[
vm.Graph(
title="Graph III",
figure=px.scatter(
gapminder_2007,
x="gdpPercap",
y="lifeExp",
size="pop",
color="continent",
),
),
],
vm.Parameter(
targets=["scatter.y"],
selector=vm.Dropdown(
options=["lifeExp", "gdpPercap", "pop"], multi=False, value="lifeExp", title="Choose y-axis"
),
),
],
),
ControlGroup(
title="Group B",
controls=[
vm.Parameter(
targets=["scatter.size"],
selector=vm.Dropdown(
options=["lifeExp", "gdpPercap", "pop"], multi=False, value="pop", title="Choose bubble size"
),
)
],
),
],
)

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

if __name__ == "__main__":
Vizro().build(dashboard).run()
1 change: 0 additions & 1 deletion vizro-core/hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ dependencies = [
"opencv-python",
"pyhamcrest"
]
env-vars = {UV_PRERELEASE = "allow"}
installer = "uv"

[envs.default.scripts]
Expand Down
13 changes: 10 additions & 3 deletions vizro-core/src/vizro/actions/_action_loop/_action_loop.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""The action loop creates all the required action callbacks and its components."""

from collections.abc import Iterable
from typing import cast

from dash import html

from vizro.actions._action_loop._action_loop_utils import _get_actions_on_registered_pages
from vizro.actions._action_loop._build_action_loop_callbacks import _build_action_loop_callbacks
from vizro.actions._action_loop._get_action_loop_components import _get_action_loop_components
from vizro.managers import model_manager
from vizro.models import Action


class ActionLoop:
Expand Down Expand Up @@ -37,5 +41,8 @@ def _build_actions_models():
List of required components for each `Action` in the `Dashboard` e.g. list[dcc.Download]

"""
actions = _get_actions_on_registered_pages()
return html.Div([action.build() for action in actions], id="app_action_models_components_div", hidden=True)
return html.Div(
[action.build() for action in cast(Iterable[Action], model_manager._get_models(Action))],
antonymilne marked this conversation as resolved.
Show resolved Hide resolved
id="app_action_models_components_div",
hidden=True,
)
35 changes: 0 additions & 35 deletions vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@

from dash import ClientsideFunction, Input, Output, State, clientside_callback

from vizro.actions._action_loop._action_loop_utils import (
_get_actions_chains_on_all_pages,
_get_actions_on_registered_pages,
)
from vizro.managers import model_manager
from vizro.managers._model_manager import ModelID
from vizro.models import Action
from vizro.models._action._actions_chain import ActionsChain

logger = logging.getLogger(__name__)


def _build_action_loop_callbacks() -> None:
"""Creates all required dash callbacks for the action loop."""
actions_chains = _get_actions_chains_on_all_pages()
actions = _get_actions_on_registered_pages()
# actions_chain and actions are not iterated over multiple times so conversion to list is not technically needed,
# but it prevents future bugs and matches _get_action_loop_components.
actions_chains: list[ActionsChain] = list(model_manager._get_models(ActionsChain))
actions: list[Action] = list(model_manager._get_models(Action))

if not actions_chains:
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from dash import dcc, html

from vizro.actions._action_loop._action_loop_utils import (
_get_actions_chains_on_all_pages,
_get_actions_on_registered_pages,
)
from vizro.managers import model_manager
from vizro.models import Action
from vizro.models._action._actions_chain import ActionsChain


def _get_action_loop_components() -> html.Div:
Expand All @@ -15,8 +14,9 @@ def _get_action_loop_components() -> html.Div:
List of dcc or html components.

"""
actions_chains = _get_actions_chains_on_all_pages()
actions = _get_actions_on_registered_pages()
# actions_chain and actions are iterated over multiple times so must be realized into a list.
actions_chains: list[ActionsChain] = list(model_manager._get_models(ActionsChain))
actions: list[Action] = list(model_manager._get_models(Action))

if not actions_chains:
return html.Div(id="action_loop_components_div")
Expand Down
14 changes: 6 additions & 8 deletions vizro-core/src/vizro/actions/_actions_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

from __future__ import annotations

from collections.abc import Iterable
from copy import deepcopy
from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, Union
from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, Union, cast

import pandas as pd

Expand Down Expand Up @@ -80,15 +81,12 @@ def _apply_filter_controls(
return data_frame


def _get_parent_vizro_model(_underlying_callable_object_id: str) -> VizroBaseModel:
def _get_parent_model(_underlying_callable_object_id: str) -> VizroBaseModel:
from vizro.models import VizroBaseModel

for _, vizro_base_model in model_manager._items_with_type(VizroBaseModel):
if (
hasattr(vizro_base_model, "_input_component_id")
and vizro_base_model._input_component_id == _underlying_callable_object_id
):
return vizro_base_model
for model in cast(Iterable[VizroBaseModel], model_manager._get_models()):
if hasattr(model, "_input_component_id") and model._input_component_id == _underlying_callable_object_id:
return model
raise KeyError(
f"No parent Vizro model found for underlying callable object with id: {_underlying_callable_object_id}."
)
Expand Down
Loading