Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
175 changes: 172 additions & 3 deletions ml_peg/app/build_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
from importlib import import_module
import warnings

from dash import Dash, Input, Output, callback
from dash import Dash, Input, Output, callback, ctx, no_update
from dash.dash_table import DataTable
from dash.dcc import Store, Tab, Tabs
from dash.html import H1, H3, Div
from dash.dcc import Checklist, Store, Tab, Tabs
from dash.exceptions import PreventUpdate
from dash.html import H1, H3, Button, Details, Div, Summary
from yaml import safe_load

from ml_peg.analysis.utils.utils import calc_table_scores, get_table_style
Expand Down Expand Up @@ -276,17 +277,112 @@ def build_tabs(
all_tabs = [Tab(label="Summary", value="summary-tab", id="summary-tab")] + [
Tab(label=category_name, value=category_name) for category_name in layouts
]
model_options = [{"label": model, "value": model} for model in MODELS]

tabs_layout = [
Div(
[
H1("ML-PEG"),
Tabs(id="all-tabs", value="summary-tab", children=all_tabs),
Details(
[
Summary("Visible models"),
Div(
[
H3("Visible models"),
Checklist(
id="model-filter-checklist",
options=model_options,
value=MODELS,
inline=True,
style={
"display": "flex",
"flexWrap": "wrap",
"gap": "6px",
},
labelStyle={
"display": "flex",
"alignItems": "center",
"gap": "6px",
"border": "1px solid #ced4da",
"borderRadius": "6px",
"padding": "4px 10px",
"margin": "2px",
},
),
Div(
[
Button(
"Select all",
id="model-filter-select-all",
n_clicks=0,
style={
"fontSize": "12px",
"padding": "4px 10px",
"backgroundColor": "#0d6efd",
"color": "#fff",
"border": "none",
"borderRadius": "4px",
"cursor": "pointer",
},
),
Button(
"Clear",
id="model-filter-clear-all",
n_clicks=0,
style={
"fontSize": "12px",
"padding": "4px 10px",
"backgroundColor": "#6c757d",
"color": "#fff",
"border": "none",
"borderRadius": "4px",
"cursor": "pointer",
},
),
],
style={
"display": "flex",
"gap": "8px",
"flexWrap": "wrap",
"marginTop": "8px",
},
),
],
style={
"padding": "12px",
"border": "1px solid #dee2e6",
"borderRadius": "6px",
"background": "#f8f9fa",
},
),
],
id="model-filter-details",
open=True,
style={
"marginTop": "16px",
"marginBottom": "16px",
"padding": "0 8px 8px 8px",
"border": "1px solid #dee2e6",
"borderRadius": "6px",
"background": "#fff",
},
),
Div(id="tabs-content"),
],
style={"flex": "1", "marginBottom": "40px"},
),
build_footer(),
Store(
id="selected-models-store",
storage_type="session",
data=MODELS,
),
Store(
id="summary-table-computed-store",
storage_type="session",
data=summary_table.data,
),
]

full_app.layout = Div(
Expand Down Expand Up @@ -323,6 +419,79 @@ def select_tab(tab) -> Div:
)
return Div([layouts[tab]])

@callback(
Output("model-filter-checklist", "value"),
Output("selected-models-store", "data"),
Input("model-filter-checklist", "value"),
Input("model-filter-select-all", "n_clicks"),
Input("model-filter-clear-all", "n_clicks"),
Input("selected-models-store", "data"),
prevent_initial_call=False,
)
def sync_model_filter(
checklist_value: list[str] | None,
select_all_clicks: int,
clear_clicks: int,
stored_selection: list[str] | None,
) -> tuple[list[str], list[str] | object]:
"""
Keep the model selector and backing store synchronised.

Parameters
----------
checklist_value
Current selection from the checklist.
select_all_clicks
Number of clicks on the Select all button.
clear_clicks
Number of clicks on the Clear button.
stored_selection
Previously persisted models pulled from ``selected-models-store``.

Returns
-------
tuple[list[str], list[str] | object]
Updated checklist value and store contents.
"""
trigger_id = ctx.triggered_id
stored_value = stored_selection if stored_selection is not None else MODELS

if trigger_id in (None, "selected-models-store"):
return stored_value, no_update

if trigger_id == "model-filter-select-all":
return MODELS, MODELS

if trigger_id == "model-filter-clear-all":
return [], []

if trigger_id == "model-filter-checklist":
selected = checklist_value or []
return selected, selected

raise PreventUpdate

@callback(
Output("model-filter-details", "open"),
Input("all-tabs", "value"),
prevent_initial_call=False,
)
def toggle_filter_panel(tab: str) -> bool:
"""
Keep the visible-models panel expanded on the summary tab only.

Parameters
----------
tab
Currently selected tab identifier.

Returns
-------
bool
``True`` when the summary tab is selected, otherwise ``False``.
"""
return tab == "summary-tab"


def build_full_app(full_app: Dash, category: str = "*") -> None:
"""
Expand Down
Loading