—
Discharge Homogeneity Analysis — Dash Dashboard.
Imports the data pipeline and figure builders from lensing_analysis, then wraps them in an interactive Dash application with live filter controls.
Run with:
python examples/lensing_analysis_dash.py
Then open http://127.0.0.1:8052 in your browser.
For a standalone (non-Dash) Plotly chart instead:
python examples/lensing_analysis.py
import sys
from pathlib import Path
from typing import Any, cast
sys.path.insert(0, str(Path(__file__).parent))
from dash import Dash, Input, Output, dcc, html # noqa: E402
from lensing_analysis import build_dataframes, build_lab_figure # noqa: E402
# ── Build the data once at startup ───────────────────────────────────────────
df_all, df_ep = build_dataframes()
ALL_TESTS_IN_DATA = sorted(df_all["Test"].unique().tolist())
ALL_GENS_IN_DATA = sorted(df_all["generator"].unique().tolist())
_gaps_numeric = sorted(
[g for g in df_all["gap_mm"].dropna().unique().tolist() if g != "—"],
key=lambda x: float(x),
)
_gaps_ep = ["—"] if "—" in df_all["gap_mm"].values else []
ALL_GAPS_IN_DATA = _gaps_numeric + _gaps_ep
# ── Layout helpers ────────────────────────────────────────────────────────────
_BTN_STYLE = {"fontSize": "11px", "padding": "2px 7px", "cursor": "pointer"}
_SECTION_HEADER = {
"marginTop": "14px",
"marginBottom": "6px",
"fontSize": "13px",
"fontWeight": "bold",
"color": "#333",
}
def _filter_section(
title: str, btn_all_id: str, btn_none_id: str, checklist_id: str, options: list[str]
) -> html.Div:
return html.Div(
[
html.Div(title, style=_SECTION_HEADER),
html.Span(
[
html.Button(
"All",
id=btn_all_id,
n_clicks=0,
style={**_BTN_STYLE, "marginRight": "4px"},
),
html.Button("None", id=btn_none_id, n_clicks=0, style=_BTN_STYLE),
]
),
html.Hr(style={"margin": "8px 0"}),
dcc.Checklist(
id=checklist_id,
options=cast(
Any,
[
{"label": f" {v} (EP)" if v == "—" else f" {v}", "value": v}
for v in options
],
),
value=options,
labelStyle={
"display": "block",
"fontSize": "12px",
"marginBottom": "3px",
},
inputStyle={"marginRight": "5px"},
),
]
)
# ── Dash application ──────────────────────────────────────────────────────────
app = Dash(__name__, title="Discharge Homogeneity")
app.layout = html.Div(
style={"display": "flex", "fontFamily": "sans-serif", "height": "100vh"},
children=[
# ── Left panel ───────────────────────────────────────────────────────
html.Div(
style={
"width": "200px",
"minWidth": "200px",
"padding": "14px 14px 14px 12px",
"borderRight": "1px solid #ddd",
"overflowY": "auto",
"background": "#fafafa",
},
children=[
html.H4(
"Filters",
style={"marginTop": 0, "marginBottom": "4px", "fontSize": "15px"},
),
_filter_section(
"Tests",
"btn-test-all",
"btn-test-none",
"test-checklist",
ALL_TESTS_IN_DATA,
),
_filter_section(
"Generator",
"btn-gen-all",
"btn-gen-none",
"gen-checklist",
ALL_GENS_IN_DATA,
),
_filter_section(
"Gap (mm)",
"btn-gap-all",
"btn-gap-none",
"gap-checklist",
ALL_GAPS_IN_DATA,
),
],
),
# ── Main panel ───────────────────────────────────────────────────────
html.Div(
style={"flex": "1", "padding": "16px", "overflowY": "auto"},
children=[
dcc.Graph(
id="lab-graph",
figure=build_lab_figure(
df_all, ALL_TESTS_IN_DATA, ALL_GENS_IN_DATA, ALL_GAPS_IN_DATA
),
style={"height": "calc(100vh - 40px)"},
config={"displayModeBar": True, "scrollZoom": True},
),
],
),
],
)
@app.callback(
Output("test-checklist", "value"),
Input("btn-test-all", "n_clicks"),
Input("btn-test-none", "n_clicks"),
prevent_initial_call=True,
)
def _toggle_tests(n_all, n_none):
from dash import ctx
return ALL_TESTS_IN_DATA if ctx.triggered_id == "btn-test-all" else []
@app.callback(
Output("gen-checklist", "value"),
Input("btn-gen-all", "n_clicks"),
Input("btn-gen-none", "n_clicks"),
prevent_initial_call=True,
)
def _toggle_gens(n_all, n_none):
from dash import ctx
return ALL_GENS_IN_DATA if ctx.triggered_id == "btn-gen-all" else []
@app.callback(
Output("gap-checklist", "value"),
Input("btn-gap-all", "n_clicks"),
Input("btn-gap-none", "n_clicks"),
prevent_initial_call=True,
)
def _toggle_gaps(n_all, n_none):
from dash import ctx
return ALL_GAPS_IN_DATA if ctx.triggered_id == "btn-gap-all" else []
@app.callback(
Output("lab-graph", "figure"),
Input("test-checklist", "value"),
Input("gen-checklist", "value"),
Input("gap-checklist", "value"),
)
def _update_lab_graph(selected_tests, selected_gens, selected_gaps):
return build_lab_figure(
df_all, selected_tests or [], selected_gens or [], selected_gaps or []
)
if __name__ == "__main__":
print("\nStarting Dash app at http://127.0.0.1:8052")
app.run(debug=False, port=8052)