From c240da85c1ad05304b3b57c44f151c196670433a Mon Sep 17 00:00:00 2001 From: "Tammo.Weber" Date: Thu, 5 Feb 2026 13:04:31 +0100 Subject: [PATCH] Eingabe Berechnungsparameter --- dashboard.py | 248 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 147 insertions(+), 101 deletions(-) diff --git a/dashboard.py b/dashboard.py index e820286..7abadd1 100644 --- a/dashboard.py +++ b/dashboard.py @@ -42,49 +42,65 @@ def inputfeld(left_text, input_id, right_text="", width=200, min=None, max=None) style={"display": "flex", "alignItems": "center", "marginBottom": "10px"}, ) -def method_row(label, cb_id, input_id, placeholder=""): - if placeholder == "": - return html.Div( - [ - dcc.Checklist( - id=cb_id, - options=[{"label": "", "value": "on"}], - value=[], - style={"margin": "0"}, - persistence=True, - persistence_type="memory", - ), - html.Span(label, style={"marginLeft": "6px", "minWidth": "110px"}), - ], - style={"display": "flex", "alignItems": "center", "gap": "6px", - "marginLeft": "10px", "marginBottom": "6px"}, - ) - else: - return html.Div( - [ - dcc.Checklist( - id=cb_id, - options=[{"label": "", "value": "on"}], - value=[], - style={"margin": "0"}, - persistence=True, - persistence_type="memory", - ), - html.Span(label, style={"marginLeft": "6px", "minWidth": "110px"}), +def method_row(label, cb_id, input_id=None, value="", info=""): + base_row_style = { + "display": "flex", + "alignItems": "center", + "gap": "4px", + "marginLeft": "10px", + "marginBottom": "6px", + } + + checkbox = dcc.Checklist( + id=cb_id, + options=[{"label": "", "value": "on"}], + value=[], + style={"margin": "0"}, + persistence=True, + persistence_type="memory", + ) + + label_span = html.Span( + label, + style={ + "marginLeft": "4px", + "minWidth": "130px", + }, + ) + + if not info: + return html.Div([checkbox, label_span], style=base_row_style) + + input_box = dcc.Input( + id=input_id, + type="number", + value=value, + #placeholder=placeholder, + style={ + "width": "90px", + "marginLeft": "2px", + }, + disabled=True, + persistence=True, + persistence_type="memory", + ) + + info_text = html.Span( + info, + style={ + "marginLeft": "6px", + "fontSize": "12px", + "color": "#6c757d", + "lineHeight": "1.1", + "whiteSpace": "nowrap", + }, + ) + children = [checkbox, label_span, input_box] + if info: + children.append(info_text) + + return html.Div(children, style=base_row_style) - dcc.Input( - id=input_id, - type="number", - placeholder=placeholder, - style={"width": "80px", "marginLeft": "10px"}, - disabled=True, - persistence=True, - persistence_type="memory", - ), - ], - style={"display": "flex", "alignItems": "center", "gap": "6px", - "marginLeft": "10px", "marginBottom": "6px"}, - ) @@ -237,23 +253,9 @@ pane_gha1 = html.Div( inputfeld("s", "input-GHA1-s", "m", min=0), inputfeld("α₀", "input-GHA1-a", "°", min=0, max=360), - dcc.Checklist( - id="method-checklist-1", - options=[ - {"label": "Analytisch", "value": "analytisch"}, - {"label": "Numerisch", "value": "numerisch"}, - {"label": "Approximiert", "value": "approx"}, - ], - value=[], - style={"marginBottom": "10px", "marginLeft": "10px"}, - persistence=True, - persistence_type="memory", - persisted_props=["value"], - ), - method_row("Analytisch", "cb-ana-1", "input-ana1", ""), - method_row("Numerisch", "cb-num-1", "input-num-n-1", "n"), - method_row("Stochastisch", "cb-stoch-1", "input-stoch-n-1", "n"), - method_row("Approximiert", "cb-approx-1", "input-approx-ds-1", "ds"), + method_row("Analytisch", "cb-ana-1", "input-ana-1", ""), + method_row("Numerisch", "cb-num-1", "input-num-n-1", "2000", info="Anzahl Schritte"), + method_row("Approximiert", "cb-approx-1", "input-approx-ds-1", "1000", info="Länge Streckensegment [m]"), html.Div( @@ -292,26 +294,18 @@ pane_gha2 = html.Div( inputfeld("β₁", "input-GHA2-beta1", "°", min=-90, max=90), inputfeld("λ₁", "input-GHA2-lamb1", "°", min=-180, max=180), - dcc.Checklist( - id="method-checklist-2", - options=[ - {"label": "Numerisch", "value": "numerisch"}, - {"label": "Stochastisch (ES)", "value": "stochastisch"}, - {"label": "Approximiert", "value": "approx"}, - ], - value=[], - style={"marginBottom": "10px", "marginLeft": "10px"}, - persistence=True, - persistence_type="memory", - persisted_props=["value"], - ), + method_row("Numerisch", "cb-num-2", "input-num-n-2", "2000", info="Anzahl Schritte"), + method_row("Stochastisch", "cb-stoch-2", "input-stoch-2", ""), + method_row("Approximiert", "cb-approx-2", "input-approx-ds-2", "1000", info="Länge Streckensegment [m]"), + html.Div( [ html.Button( "Berechnen", id="button-calc-gha2", n_clicks=0, - style={"marginRight": "10px", "marginLeft": "10px"}, + className="btn btn-secondary btn-lg shadow", + style={"marginRight": "10px", "marginLeft": "10px", "marginTop": "30px"}, ), ], style={"marginBottom": "20px"}, @@ -376,6 +370,8 @@ app.layout = html.Div( inputfeld("aᵧ", "input-ay", "m", min=0), inputfeld("b", "input-b", "m", min=0), + html.Br(), + dcc.Tabs( id="tabs-GHA", value="tab-GHA1", @@ -463,13 +459,53 @@ def switch_tabs(tab): def toggle_ds(v): return "on" not in (v or []) +@app.callback( + Output("input-num-n-1", "disabled"), + Input("cb-num-1", "value"), +) +def toggle_ds(v): + return "on" not in (v or []) +@app.callback( + Output("input-approx-ds-2", "disabled"), + Input("cb-approx-2", "value"), +) +def toggle_ds(v): + return "on" not in (v or []) + +@app.callback( + Output("input-num-n-2", "disabled"), + Input("cb-num-2", "value"), +) +def toggle_ds(v): + return "on" not in (v or []) + +@app.callback( + Output("input-stoch-2", "disabled"), + Input("cb-stoch-2", "value"), +) +def toggle_ds(v): + return "on" not in (v or []) + + +@app.callback( + Output("tabs-GHA1-out", "children"), + Input("button-calc-gha1", "n_clicks"), + State("cb-ana-1", "value"), + State("cb-num-1", "value"), + State("cb-approx-1", "value"), + prevent_initial_call=True, +) +def gha1_method_hint(n, a, nu, ap): + any_on = any("on" in (v or []) for v in (a, nu, ap)) + return "" if any_on else html.Span("Bitte Berechnungsverfahren wählen.", style={"color": "red"}) # -- GHA 1 --- @app.callback( Output("output-gha1-ana", "children"), Output("store-gha1-ana", "data"), Input("button-calc-gha1", "n_clicks"), + State("cb-ana-1", "value"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), @@ -477,10 +513,9 @@ def toggle_ds(v): State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), - State("method-checklist-1", "value"), prevent_initial_call=True, ) -def compute_gha1_ana(n1, beta0, lamb0, s, a0, ax, ay, b, method1): +def compute_gha1_ana(n1, cb_ana, beta0, lamb0, s, a0, ax, ay, b): out = html.Div([ html.H4("Erste Hauptaufgabe"), ]) @@ -490,9 +525,9 @@ def compute_gha1_ana(n1, beta0, lamb0, s, a0, ax, ay, b, method1): 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 "analytisch" not in (method1 or []): + #if not method1: + #return html.Span("Bitte Berechnungsverfahren wählen.", style={"color": "red"}), None + if "on" not in (cb_ana or []): return out, no_update @@ -527,6 +562,8 @@ def compute_gha1_ana(n1, beta0, lamb0, s, a0, ax, ay, b, method1): Output("output-gha1-num", "children"), Output("store-gha1-num", "data"), Input("button-calc-gha1", "n_clicks"), + State("cb-num-1", "value"), + State("input-num-n-1", "value"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), @@ -534,15 +571,16 @@ def compute_gha1_ana(n1, beta0, lamb0, s, a0, ax, ay, b, method1): State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), - State("method-checklist-1", "value"), prevent_initial_call=True, ) -def compute_gha1_num(n1, beta0, lamb0, s, a0, ax, ay, b, method1): +def compute_gha1_num(n1, cb_num, n_in, beta0, lamb0, s, a0, ax, ay, b): if not n1: return no_update, no_update - if "numerisch" not in (method1 or []): + if not n1 or "on" not in (cb_num or []): return no_update, no_update + n_in = int(n_in) if n_in else 2000 + ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) @@ -551,7 +589,7 @@ def compute_gha1_num(n1, beta0, lamb0, s, a0, ax, ay, b, method1): P0 = ell.ell2cart(beta_rad, lamb_rad) - P1_num, alpha1, werte = gha1_num(ell, P0, alpha_rad, s_val, 10000, all_points=True) + P1_num, alpha1, werte = gha1_num(ell, P0, alpha_rad, s_val, n_in, all_points=True) beta2_num, lamb2_num = ell.cart2ell(P1_num) out = html.Div([ @@ -629,6 +667,8 @@ def compute_gha1_stoch(n1, beta0, lamb0, s, a0, ax, ay, b, method1): Output("output-gha1-approx", "children"), Output("store-gha1-approx", "data"), Input("button-calc-gha1", "n_clicks"), + State("cb-approx-1", "value"), + State("input-approx-ds-1", "value"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), @@ -636,15 +676,16 @@ def compute_gha1_stoch(n1, beta0, lamb0, s, a0, ax, ay, b, method1): State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), - State("method-checklist-1", "value"), prevent_initial_call=True, ) -def compute_gha1_approx(n1, beta0, lamb0, s, a0, ax, ay, b, method1): +def compute_gha1_approx(n1, cb_approx, ds_in, beta0, lamb0, s, a0, ax, ay, b): if not n1: return no_update, no_update - if "approx" not in (method1 or []): + if not n1 or "on" not in (cb_approx or []): return no_update, no_update + ds_in = int(ds_in) if ds_in else 1000 + ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) @@ -652,7 +693,7 @@ def compute_gha1_approx(n1, beta0, lamb0, s, a0, ax, ay, b, method1): s_val = float(s) P0 = ell.ell2cart(beta_rad, lamb_rad) - P1_app, alpha1_app, points, alphas = gha1_approx(ell, P0, alpha_rad, s_val, ds=5000, all_points=True) + P1_app, alpha1_app, points, alphas = gha1_approx(ell, P0, alpha_rad, s_val, ds=ds_in, all_points=True) beta1_app, lamb1_app = ell.cart2ell(P1_app) @@ -677,6 +718,8 @@ def compute_gha1_approx(n1, beta0, lamb0, s, a0, ax, ay, b, method1): Output("output-gha2-num", "children"), Output("store-gha2-num", "data"), Input("button-calc-gha2", "n_clicks"), + State("cb-num-2", "value"), + State("input-num-n-2", "value"), State("input-GHA2-beta0", "value"), State("input-GHA2-lamb0", "value"), State("input-GHA2-beta1", "value"), @@ -684,10 +727,9 @@ def compute_gha1_approx(n1, beta0, lamb0, s, a0, ax, ay, b, method1): State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), - State("method-checklist-2", "value"), prevent_initial_call=True, ) -def compute_gha2_num(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): +def compute_gha2_num(n2, cb_num, n_in, beta0, lamb0, beta1, lamb1, ax, ay, b): out = html.Div([ html.H4("Zweite Hauptaufgabe"), ]) @@ -697,10 +739,10 @@ def compute_gha2_num(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): return html.Span("Bitte Ellipsoid wählen.", style={"color": "red"}), None if None in (beta0, lamb0, beta1, lamb1): return html.Span("Bitte β₀, λ₀, β₁ und λ₁ eingeben.", style={"color": "red"}), None - if not method2: - return html.Span("Bitte Berechnungsverfahren wählen.", style={"color": "red"}), None - if "numerisch" not in (method2 or []): - return out, no_update + if "on" not in (cb_num or []): + return no_update, no_update + + n_in = int(n_in) if n_in else 2000 ell = EllipsoidTriaxial(ax, ay, b) @@ -712,7 +754,7 @@ def compute_gha2_num(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): P0 = ell.ell2cart(beta0_rad, lamb0_rad) P1 = ell.ell2cart(beta1_rad, lamb1_rad) - a0_num, a1_num, s_num, beta_arr, lamb_arr = gha2_num(ell, beta0_rad, lamb0_rad, beta1_rad, lamb1_rad, all_points=True, n=3000) + a0_num, a1_num, s_num, beta_arr, lamb_arr = gha2_num(ell, beta0_rad, lamb0_rad, beta1_rad, lamb1_rad, all_points=True, n=n_in) polyline = [] for b_rad, l_rad in zip(beta_arr, lamb_arr): @@ -736,6 +778,8 @@ def compute_gha2_num(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): Output("output-gha2-stoch", "children"), Output("store-gha2-stoch", "data"), Input("button-calc-gha2", "n_clicks"), + State("cb-stoch-2", "value"), + State("input-stoch-2", "value"), State("input-GHA2-beta0", "value"), State("input-GHA2-lamb0", "value"), State("input-GHA2-beta1", "value"), @@ -743,13 +787,12 @@ def compute_gha2_num(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), - State("method-checklist-2", "value"), prevent_initial_call=True, ) -def compute_gha2_stoch(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): +def compute_gha2_stoch(n2, cb_stoch, n_stoch, beta0, lamb0, beta1, lamb1, ax, ay, b): if not n2: return no_update, no_update - if "stochastisch" not in (method2 or []): + if "on" not in (cb_stoch or []): return no_update, no_update ell = EllipsoidTriaxial(ax, ay, b) @@ -776,6 +819,8 @@ def compute_gha2_stoch(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): Output("output-gha2-approx", "children"), Output("store-gha2-approx", "data"), Input("button-calc-gha2", "n_clicks"), + State("cb-approx-2", "value"), + State("input-approx-ds-2", "value"), State("input-GHA2-beta0", "value"), State("input-GHA2-lamb0", "value"), State("input-GHA2-beta1", "value"), @@ -783,15 +828,16 @@ def compute_gha2_stoch(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), - State("method-checklist-2", "value"), prevent_initial_call=True, ) -def compute_gha2_approx(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): +def compute_gha2_approx(n2, cb_approx, ds_in, beta0, lamb0, beta1, lamb1, ax, ay, b): if not n2: return no_update, no_update - if "approx" not in (method2 or []): + if "on" not in (cb_approx or []): return no_update, no_update + ds_in = int(ds_in) if ds_in else 1000 + ell = EllipsoidTriaxial(ax, ay, b) beta0_rad = wu.deg2rad(float(beta0)) @@ -802,7 +848,7 @@ def compute_gha2_approx(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2): P0 = ell.ell2cart(beta0_rad, lamb0_rad) P1 = ell.ell2cart(beta1_rad, lamb1_rad) - a0_app, a1_app, s_app, points = gha2_approx(ell, P0, P1, ds=1000, all_points=True) + a0_app, a1_app, s_app, points = gha2_approx(ell, P0, P1, ds=ds_in, all_points=True) out = html.Div([ html.Strong("Approximiert: "), @@ -860,6 +906,6 @@ if __name__ == "__main__": HOST = "127.0.0.1" PORT = 8050 - Timer(1.0, webbrowser.open_new_tab(f"http://{HOST}:{PORT}/")).start + #Timer(1.0, webbrowser.open_new_tab(f"http://{HOST}:{PORT}/")).start app.run(host=HOST, port=PORT, debug=False)