From 0eeb35f17309e3911413598a17425ae09219ecca Mon Sep 17 00:00:00 2001 From: "Tammo.Weber" Date: Fri, 6 Feb 2026 15:06:48 +0100 Subject: [PATCH] GHA1 ES mit Linie, Legende --- dashboard.py | 138 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 32 deletions(-) diff --git a/dashboard.py b/dashboard.py index 5314d5b..d0e2fb3 100644 --- a/dashboard.py +++ b/dashboard.py @@ -27,7 +27,7 @@ from GHA_triaxial.gha2_approx import gha2_approx def _no_print(*args, **kwargs): pass -builtins.print = _no_print +#builtins.print = _no_print # Bootstrap (CSS) einbindung @@ -290,6 +290,7 @@ pane_gha1 = html.Div( html.Div(id="tabs-GHA1-out", style={"marginBottom": "10px"}), + html.Div(id="gha1-header"), dcc.Loading(html.Div(id="output-gha1-ana")), dcc.Loading(html.Div(id="output-gha1-num")), dcc.Loading(html.Div(id="output-gha1-stoch")), @@ -331,6 +332,7 @@ pane_gha2 = html.Div( html.Div(id="tabs-GHA2-out", style={"marginBottom": "10px"}), + html.Div(id="gha2-header"), dcc.Loading(html.Div(id="output-gha2-num")), dcc.Loading(html.Div(id="output-gha2-stoch")), dcc.Loading(html.Div(id="output-gha2-approx")), @@ -460,7 +462,6 @@ def fill_inputs_from_dropdown(selected_ell): if not selected_ell: return None, None, None - ell = EllipsoidTriaxial.init_name(selected_ell) ax = ell.ax ay = ell.ay @@ -562,23 +563,17 @@ def gha1_method_hint(n, a, nu, st, ap): prevent_initial_call=True, ) def compute_gha1_ana(n1, cb_ana, n_in, beta0, lamb0, s, a0, ax, ay, b): - out = html.Div([ - html.H4("Erste Hauptaufgabe"), - ]) - - n_in = int(n_in) if n_in else 70 - if not n1: return no_update, no_update if None in (ax, ay, b): return html.Span("Bitte Ellipsoid wählen.", style={"color": "red"}), None if None in (beta0, lamb0, s, a0): return html.Span("Bitte β₀, λ₀, s und α₀ eingeben.", style={"color": "red"}), None - #if not method1: - #return html.Span("Bitte Berechnungsverfahren wählen.", style={"color": "red"}), None if "on" not in (cb_ana or []): return "", None + n_in = int(n_in) if n_in else 70 + ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) @@ -590,7 +585,6 @@ def compute_gha1_ana(n1, cb_ana, n_in, beta0, lamb0, s, a0, ax, ay, b): beta2_ana, lamb2_ana = ell.cart2ell(P1_ana) out = html.Div([ - html.H4("Erste Hauptaufgabe"), html.Strong("Analytisch: "), html.Br(), html.Span(f"kartesisch: x₁={P1_ana[0]:.4f} m, y₁={P1_ana[1]:.4f} m, z₁={P1_ana[2]:.4f} m"), @@ -602,6 +596,7 @@ def compute_gha1_ana(n1, cb_ana, n_in, beta0, lamb0, s, a0, ax, ay, b): store = { "points": [("P0", P0, "black"), ("P1 (ana)", P1_ana, "red")], "polyline": None, + "name": "Analytisch", "color": "red" } return out, store @@ -654,6 +649,7 @@ def compute_gha1_num(n1, cb_num, n_in, beta0, lamb0, s, a0, ax, ay, b): store = { "points": [("P0", P0, "black"), ("P1 (num)", P1_num, "#ff8c00")], "polyline": polyline, + "name": "Numerisch", "color": "#ff8c00" } return out, store @@ -687,7 +683,7 @@ def compute_gha1_stoch(n1, cb_stoch, n_in, beta0, lamb0, s, a0, ax, ay, b): alpha_rad = wu.deg2rad(float(a0)) s_val = float(s) - P1_stoch, alpha = gha1_ES(ell, beta0=beta_rad, omega0=lamb_rad, alpha0=alpha_rad, s_total=s_val, maxSegLen=n_in) + P1_stoch, alpha, points = gha1_ES(ell, beta0=beta_rad, omega0=lamb_rad, alpha0=alpha_rad, s_total=s_val, maxSegLen=n_in) P0 = ell.ell2cart(beta_rad, lamb_rad) beta1_stoch, lamb1_stoch = ell.cart2ell(P1_stoch) @@ -701,9 +697,10 @@ def compute_gha1_stoch(n1, cb_stoch, n_in, beta0, lamb0, s, a0, ax, ay, b): ]) store = { - "points": [("P0", P0, "black"), ("P1 (ES)", P1_stoch, "#d62728")], - "polyline": None, - "color": "#d62728" + "points": [("P0", P0, "black"), ("P1 (ES)", P1_stoch, "#1fa342")], + "polyline": points, + "name": "Stochastisch (ES)", + "color": "#1fa342" } return out, store @@ -752,6 +749,7 @@ def compute_gha1_approx(n1, cb_approx, ds_in, beta0, lamb0, s, a0, ax, ay, b): store = { "points": [("P0", P0, "black"), ("P1 (approx)", P1_app, "#00c2fc")], "polyline": points, + "name": "Approximiert", "color": "#00c2fc" } return out, store @@ -774,9 +772,6 @@ def compute_gha1_approx(n1, cb_approx, ds_in, beta0, lamb0, s, a0, ax, ay, b): prevent_initial_call=True, ) def compute_gha2_num(n2, cb_num, n_in, beta0, lamb0, beta1, lamb1, ax, ay, b): - out = html.Div([ - html.H4("Zweite Hauptaufgabe"), - ]) if not n2: return no_update, no_update if None in (ax, ay, b): @@ -806,7 +801,6 @@ def compute_gha2_num(n2, cb_num, n_in, beta0, lamb0, beta1, lamb1, ax, ay, b): polyline.append([float(x), float(y), float(z)]) out = html.Div([ - html.H4("Zweite Hauptaufgabe"), html.Strong("Numerisch: "), html.Span(f"{aus.gms('α₀', a0_num, 4)}, {aus.gms('α₁', a1_num, 4)}, s = {s_num:.4f} m"), ]) @@ -814,7 +808,7 @@ def compute_gha2_num(n2, cb_num, n_in, beta0, lamb0, beta1, lamb1, ax, ay, b): store = { "points": [("P0", P0, "black"), ("P1", P1, "black")], "polyline": polyline, - "name": "numerisch", + "name": "Numerisch", "color": "#ff8c00", } return out, store @@ -852,7 +846,8 @@ def compute_gha2_stoch(n2, cb_stoch, n_in, beta0, lamb0, beta1, lamb1, ax, ay, b P0 = ell.ell2cart(beta0_rad, lamb0_rad) P1 = ell.ell2cart(beta1_rad, lamb1_rad) - a0_stoch, a1_stoch, s_stoch, points = gha2_ES(ell, P0, P1, maxSegLen=n_in, all_points=True) + #a0_stoch, a1_stoch, s_stoch, points = gha2_ES(ell, P0, P1, maxSegLen=n_in, all_points=True) + a0_stoch, a1_stoch, s_stoch, points = gha2_ES(ell, P0, P1) out = html.Div([ html.Strong("Stochastisch (ES): "), @@ -862,8 +857,8 @@ def compute_gha2_stoch(n2, cb_stoch, n_in, beta0, lamb0, beta1, lamb1, ax, ay, b store = { "points": [("P0", P0, "black"), ("P1", P1, "black")], "polyline": points, - "name": "stochastisch (ES)", - "color": "#d62728", + "name": "Stochastisch (ES)", + "color": "#1fa342", } return out, store @@ -911,7 +906,7 @@ def compute_gha2_approx(n2, cb_approx, ds_in, beta0, lamb0, beta1, lamb1, ax, ay store = { "points": [("P0", P0, "black"), ("P1", P1, "black")], "polyline": points, - "name": "approximiert", + "name": "Approximiert", "color": "#00c2fc", } @@ -942,29 +937,88 @@ def render_all(ax, ay, b, coords_type, tab, t1, t2, return go.Figure() ell = EllipsoidTriaxial(ax, ay, b) + fig = ellipsoid_figure(ell, title="") fig = figure_constant_lines(fig, ell, coords_type) + legend_added = set() + + def add_legend_for_store(store): + nonlocal fig + if not store: + return + name = store.get("name") + color = store.get("color") + if not name or not color: + return + + key = (name, color) + if key in legend_added: + return + legend_added.add(key) + + has_line = bool(store.get("polyline")) + + if has_line: + fig.add_trace(go.Scatter3d( + x=[None], y=[None], z=[None], + mode="lines", + line=dict(width=6, color=color), + name=name, + showlegend=True, + hoverinfo="skip", + )) + else: + fig.add_trace(go.Scatter3d( + x=[None], y=[None], z=[None], + mode="markers", + marker=dict(size=8, color=color), + name=name, + showlegend=True, + hoverinfo="skip", + )) + def add_from_store(store): nonlocal fig if not store: return + pts = store.get("points") or [] if pts: fig = figure_points(fig, pts) + line = store.get("polyline") if line: - fig = figure_lines(fig, line, store.get("name", ""), store.get("color", "#ff8c00")) + fig = figure_lines( + fig, + line, + store.get("name", ""), + store.get("color", "#ff8c00"), + ) if tab == "tab-GHA1": - for st in (s1a, s1n, s1s, s1p): - add_from_store(st) + stores = (s1a, s1n, s1s, s1p) else: - for st in (s2n, s2s, s2p): - add_from_store(st) + stores = (s2n, s2s, s2p) + + for st in stores: + add_legend_for_store(st) + add_from_store(st) + + fig.update_layout( + showlegend=True, + legend=dict( + orientation="h", + yanchor="bottom", + y=1.02, + xanchor="left", + x=0.0, + ), + ) return fig + # Funktion zum Leeren des Plots bei Änderung des Ellipsoids @app.callback( Output("store-gha1-ana", "data", allow_duplicate=True), @@ -989,6 +1043,7 @@ def clear_all_stores_on_ellipsoid_change(ax, ay, b): # Funktionen zur separaten Darstellung der Tabs @app.callback( Output("calc-token-gha1", "data"), + Output("gha1-header", "children", allow_duplicate=True), Output("output-gha1-ana", "children", allow_duplicate=True), Output("output-gha1-num", "children", allow_duplicate=True), Output("output-gha1-stoch", "children", allow_duplicate=True), @@ -1005,11 +1060,11 @@ def start_calc_gha1(n, token): if not n: raise PreventUpdate token = (token or 0) + 1 - return token, "", "", "", "", None, None, None, None - + return token, "", "", "", "", "", None, None, None, None @app.callback( Output("calc-token-gha2", "data"), + Output("gha2-header", "children", allow_duplicate=True), Output("output-gha2-num", "children", allow_duplicate=True), Output("output-gha2-stoch", "children", allow_duplicate=True), Output("output-gha2-approx", "children", allow_duplicate=True), @@ -1024,7 +1079,26 @@ def start_calc_gha2(n, token): if not n: raise PreventUpdate token = (token or 0) + 1 - return token, "", "", "", None, None, None + return token, "", "", "", "", None, None, None + + + +# Funktionen zur Erzeugung der Überschriften +@app.callback( + Output("gha1-header", "children"), + Input("calc-token-gha1", "data"), + prevent_initial_call=True, +) +def set_gha1_header(_): + return html.H4("Erste Hauptaufgabe") + +@app.callback( + Output("gha2-header", "children"), + Input("calc-token-gha2", "data"), + prevent_initial_call=True, +) +def set_gha2_header(_): + return html.H4("Zweite Hauptaufgabe")