Skip to content

Commit 029bd80

Browse files
authored
Dash urls and callbacks
Save to/load from urls and additional callbacks refactor
2 parents 88f69ad + 6c0fc9c commit 029bd80

File tree

9 files changed

+408
-269
lines changed

9 files changed

+408
-269
lines changed

src/chime_dash/__init__.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,31 @@
88
from typing import TypeVar
99
from chime_dash.app.config import from_object
1010
from penn_chime.settings import get_defaults
11-
from chime_dash.app.components import Body
11+
from chime_dash.app.pages.root import Root
1212
from chime_dash.app.utils.callbacks import wrap_callbacks
1313

1414
DashAppInstance = TypeVar('DashAppInstance')
15-
DEFAULTS = get_defaults()
1615

17-
def create_app(context:str='prod')-> DashAppInstance:
16+
17+
def create_app(context: str = 'prod') -> DashAppInstance:
1818
"""
1919
create_app initializes the app instance
20-
20+
2121
Args:
2222
context (str, optional): One of either 'prod', 'dev', 'testing.
2323
Defaults to 'prod' where dash.Dash.run_server(debug=False).
2424
Change to 'dev' or 'test' to set debug to true.
25-
25+
2626
Returns:
2727
Env: Config variables based on context argument received
2828
DashAppInstance: Dash instance with appropriate configuration settings
2929
"""
3030

3131
Env = from_object(context)
32-
32+
3333
LANGUAGE = Env.LANG
34-
body = Body(LANGUAGE, DEFAULTS)
35-
36-
34+
body = Root(LANGUAGE, get_defaults())
35+
3736
App = Dash(
3837
__name__,
3938
external_stylesheets=body.external_stylesheets,
@@ -44,7 +43,4 @@ def create_app(context:str='prod')-> DashAppInstance:
4443
App.layout = body.html
4544
wrap_callbacks(App)
4645

47-
48-
4946
return Env, App
50-
Lines changed: 9 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,12 @@
1-
"""Combines all components
1+
"""app/components
22
3-
The `sidebar` component combines all the inputs while other components potentially
4-
have callbacks.
3+
reusable components that desc a bit of UI - nothing should be defined here only initialized
54
6-
To add or remove components, adjust the `setup`.
7-
If callbacks are present, also adjust `CALLBACK_INPUTS`, `CALLBACK_OUTPUTS` and
8-
`callback_body`.
9-
"""
10-
from collections import OrderedDict
11-
12-
from dash_bootstrap_components import Container, Row
13-
from dash_bootstrap_components.themes import BOOTSTRAP
14-
from dash_html_components import Div
15-
16-
from chime_dash.app.components.base import Component
17-
from chime_dash.app.components.navbar import Navbar
18-
from chime_dash.app.pages.index import Index
19-
from chime_dash.app.pages.sidebar import Sidebar
20-
21-
22-
def singleton(class_):
23-
instances = {}
24-
25-
def get_instance(*args, **kwargs):
26-
if class_ not in instances:
27-
instances[class_] = class_(*args, **kwargs)
28-
return instances[class_]
29-
return get_instance
5+
for pages definitions see -> app/pages
6+
for core logic see --> app/services
7+
for utility classes and functions see --> utils
308
31-
32-
@singleton
33-
class Body(Component):
34-
"""
35-
"""
36-
external_stylesheets = [
37-
BOOTSTRAP,
38-
'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&display=swap',
39-
]
40-
41-
def __init__(self, language, defaults):
42-
"""
43-
"""
44-
super().__init__(language, defaults)
45-
self.components = OrderedDict(
46-
navbar=Navbar(language, defaults),
47-
sidebar=Sidebar(language, defaults),
48-
# todo subscribe to changes to URL and select page appropriately
49-
index=Index(language, defaults),
50-
)
51-
52-
def get_html(self):
53-
"""Glues individual setup components together
54-
"""
55-
return Div(
56-
className="app",
57-
children=self.components["navbar"].html + [
58-
Div(
59-
className="app-content",
60-
children=
61-
self.components["sidebar"].html
62-
+ self.components["index"].html
63-
)
64-
]
65-
)
66-
67-
def get_html_old(self):
68-
"""Glues individual setup components together
69-
"""
70-
return Div(children=
71-
self.components["navbar"].html
72-
+ [Container(
73-
children=Row(self.components["sidebar"].html + [Div(
74-
id="page-wrapper",
75-
children=self.components["index"].html
76-
)]),
77-
fluid=True,
78-
className="mt-5",
79-
)])
9+
modules desc. route
10+
---- ---- ----
11+
index homepage /
12+
"""

src/chime_dash/app/components/base.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,17 @@
44
55
#! candidate for moving into utils/components
66
"""
7-
from typing import List, Dict, Any, Union
7+
from typing import List, Dict, Union
88

99
from abc import ABC
1010

11-
from dash import Dash
1211
from dash.development.base_component import ComponentMeta
1312
from dash_html_components import Div
1413

1514
from penn_chime.parameters import Parameters
1615
from penn_chime.settings import get_defaults
1716

1817
from chime_dash.app.utils.templates import read_localization_yml, read_localization_markdown
19-
from chime_dash.app.utils.callbacks import ChimeCallback, register_callbacks
2018

2119
DEFAULTS = get_defaults()
2220

@@ -34,19 +32,13 @@ class Component(ABC):
3432
external_stylesheets: List[str] = []
3533
external_scripts: List[str] = []
3634

37-
def __init__(
38-
self,
39-
language: str = "en",
40-
defaults: Parameters = DEFAULTS,
41-
callbacks: List[ChimeCallback] = None
42-
):
35+
def __init__(self, language: str = "en", defaults: Parameters = DEFAULTS):
4336
"""Initializes the component
4437
"""
4538
self.language = language
4639
self.defaults = defaults
4740
self._content = None
4841
self._html = None
49-
register_callbacks(callbacks)
5042

5143
def get_html(self) -> List[ComponentMeta]: # pylint: disable=R0201
5244
"""Function which is called to render html elements.
@@ -99,6 +91,14 @@ def content(self) -> Union[str, Dict[str, str], None]:
9991
return self._content
10092

10193

94+
class Page(Component):
95+
callbacks_cls = None
96+
97+
def __init__(self, language: str = "en", defaults: Parameters = DEFAULTS):
98+
super().__init__(language, defaults)
99+
self.callbacks_cls(self)
100+
101+
102102
class HTMLComponentError(Exception):
103103
"""Custom exception for errors when rendering component html.
104104

src/chime_dash/app/pages/index.py

Lines changed: 8 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,28 @@
11
"""pages/index
22
Homepage
33
"""
4-
54
from collections import OrderedDict
65

76
from dash_html_components import Main
87
from dash_bootstrap_components import Container
98

10-
from chime_dash.app.components.base import Component
9+
from chime_dash.app.components.base import Page
1110
from chime_dash.app.components.footer import Footer
1211
from chime_dash.app.components.header import Header
1312
from chime_dash.app.components.intro import Intro
1413
from chime_dash.app.components.visualizations import Visualizations
14+
from chime_dash.app.services.callbacks import IndexCallbacks
1515

16-
from chime_dash.app.utils import get_n_switch_values, parameters_deserializer, prepare_visualization_group
17-
from chime_dash.app.utils.callbacks import ChimeCallback
18-
19-
from penn_chime.models import SimSirModel
2016

21-
22-
class Index(Component):
17+
class Index(Page):
2318
"""
2419
"""
25-
26-
@staticmethod
27-
def toggle_tool_details(switch_value):
28-
return get_n_switch_values(switch_value, 1)
29-
30-
@staticmethod
31-
def toggle_tables(switch_value):
32-
return get_n_switch_values(switch_value, 3)
20+
callbacks_cls = IndexCallbacks
3321

3422
def __init__(self, language, defaults):
3523
"""
3624
"""
37-
38-
def handle_model_change_helper(pars_json):
39-
model = {}
40-
pars = None
41-
result = []
42-
viz_kwargs = {}
43-
if pars_json:
44-
pars = parameters_deserializer(pars_json)
45-
model = SimSirModel(pars)
46-
viz_kwargs = dict(
47-
labels=pars.labels,
48-
table_mod=7,
49-
max_y_axis=pars.max_y_axis,
50-
)
51-
result.extend(self.components["intro"].build(model, pars))
52-
for df_key in ["admits_df", "census_df", "sim_sir_w_date_df"]:
53-
df = None
54-
if model:
55-
df = model.__dict__.get(df_key, None)
56-
result.extend(prepare_visualization_group(df, **viz_kwargs))
57-
return result
58-
59-
super().__init__(language, defaults, [
60-
ChimeCallback( # If user toggles show_tables, show/hide tables
61-
changed_elements=OrderedDict(show_tables="value"),
62-
dom_updates=OrderedDict(
63-
SIR_table_container="hidden",
64-
new_admissions_table_container="hidden",
65-
admitted_patients_table_container="hidden",
66-
),
67-
callback_fn=Index.toggle_tables
68-
),
69-
ChimeCallback( # If the parameters or model change, update the text
70-
changed_elements=OrderedDict(pars="children"),
71-
dom_updates=OrderedDict(
72-
intro="children",
73-
new_admissions_graph="figure",
74-
new_admissions_table="children",
75-
new_admissions_download="href",
76-
admitted_patients_graph="figure",
77-
admitted_patients_table="children",
78-
admitted_patients_download="href",
79-
SIR_graph="figure",
80-
SIR_table="children",
81-
SIR_download="href",
82-
),
83-
callback_fn=handle_model_change_helper
84-
)
85-
])
25+
super().__init__()
8626
self.components = OrderedDict(
8727
header=Header(language, defaults),
8828
intro=Intro(language, defaults),
@@ -99,16 +39,13 @@ def get_html(self):
9939
"marginLeft": "320px",
10040
"marginTop": "56px"
10141
},
102-
children=
103-
[Container(
104-
children=
105-
self.components["header"].html
42+
children=[Container(
43+
children=self.components["header"].html
10644
+ self.components["intro"].html
10745
)]
10846
+ self.components["visualizations"].html
10947
+ [Container(
110-
children=
111-
self.components["footer"].html
48+
children=self.components["footer"].html
11249
)],
11350
)
11451

src/chime_dash/app/pages/root.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Combines all components
2+
3+
The `sidebar` component combines all the inputs while other components potentially
4+
have callbacks.
5+
6+
To add or remove components, adjust the `setup`.
7+
"""
8+
from collections import OrderedDict
9+
10+
from dash_bootstrap_components.themes import BOOTSTRAP
11+
from dash_html_components import Div
12+
from dash_core_components import Location, Store
13+
14+
from chime_dash.app.components.base import Page
15+
from chime_dash.app.components.navbar import Navbar
16+
from chime_dash.app.pages.index import Index
17+
from chime_dash.app.pages.sidebar import Sidebar
18+
from chime_dash.app.utils import singleton
19+
from chime_dash.app.services.callbacks import RootCallbacks
20+
21+
@singleton
22+
class Root(Page):
23+
"""
24+
"""
25+
external_stylesheets = [
26+
BOOTSTRAP,
27+
'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&display=swap',
28+
]
29+
callbacks_cls = RootCallbacks
30+
31+
def __init__(self, language, defaults):
32+
"""
33+
"""
34+
self.components = OrderedDict(
35+
navbar=Navbar(language, defaults),
36+
sidebar=Sidebar(language, defaults),
37+
# todo subscribe to changes to URL and select page appropriately
38+
index=Index(language, defaults),
39+
)
40+
super().__init__(language, defaults)
41+
42+
def get_html(self):
43+
"""Glues individual setup components together
44+
"""
45+
return Div(
46+
className="app",
47+
children=self.components["navbar"].html + [
48+
Div(
49+
className="app-content",
50+
children=self.components["sidebar"].html
51+
+ self.components["index"].html
52+
),
53+
Store(id="root-store"),
54+
Location(id='location')
55+
]
56+
)

0 commit comments

Comments
 (0)