from dash import Dash, html, dcc, Input, Output, State, no_update import plotly.graph_objects as go import numpy as np from ellipsoide import EllipsoidTriaxial import winkelumrechnungen as wu import ausgaben as aus from GHA_triaxial.panou import gha1_ana from GHA_triaxial.panou import gha1_num from GHA_triaxial.approx_gha1 import gha1_approx from GHA_triaxial.panou_2013_2GHA_num import gha2_num from GHA_triaxial.ES_gha2 import gha2_ES from GHA_triaxial.approx_gha2 import gha2_approx app = Dash(__name__, suppress_callback_exceptions=True) app.title = "Geodätische Hauptaufgaben" def inputfeld(left_text, input_id, right_text="", width=200, min=None, max=None): return html.Div( [ html.Span(f"{left_text} =", style={"minWidth": 36, "textAlign": "right", "marginRight": 5}), dcc.Input(id=input_id, type="number", placeholder=f"{left_text}...[{right_text}]", min=min, max=max, style={"width": width, "display": "block",}), html.Span(right_text, style={"marginLeft": 5}) if right_text else html.Span() ], style={"display": "flex", "alignItems": "center", "marginBottom": "10px"} ) def ellipsoid_figure(ell: EllipsoidTriaxial, title="Dreiachsiges Ellipsoid"): fig = go.Figure() # Darstellung rx, ry, rz = 1.05*ell.ax, 1.05*ell.ay, 1.05*ell.b fig.update_layout( title=title, scene=dict( xaxis=dict(range=[-rx, rx], title="X [m]"), yaxis=dict(range=[-ry, ry], title="Y [m]"), zaxis=dict(range=[-rz, rz], title="Z [m]"), aspectmode="data" ), margin=dict(l=0, r=0, t=10, b=0), ) # Ellipsoid u = np.linspace(-np.pi/2, np.pi/2, 80) v = np.linspace(-np.pi, np.pi, 160) U, V = np.meshgrid(u, v) X, Y, Z = ell.para2cart(U, V) fig.add_trace(go.Surface( x=X, y=Y, z=Z, showscale=False, opacity=0.7, surfacecolor=np.zeros_like(X), colorscale=[[0, "rgb(200,220,255)"], [1, "rgb(200,220,255)"]], name="Ellipsoid" )) return fig def figure_constant_lines(fig, ell: EllipsoidTriaxial, coordsystem: str = "para"): if coordsystem == "para": constants_u = wu.deg2rad(np.arange(-90, 91, 15)) all_v = wu.deg2rad(np.arange(-180, 180, 1)) for u in constants_u: xm, ym, zm = ell.para2cart(u, all_v) fig.add_trace(go.Scatter3d( x=xm, y=ym, z=zm, mode="lines", line=dict(width=1, color="black"), showlegend=False )) all_u = wu.deg2rad(np.arange(-90, 91, 1)) constants_v = wu.deg2rad(np.arange(-180, 180, 15)) for v in constants_v: x, y, z = ell.para2cart(all_u, v) fig.add_trace(go.Scatter3d( x=x, y=y, z=z, mode="lines", line=dict(width=1, color="black"), showlegend=False )) elif coordsystem == "ell": constants_beta = wu.deg2rad(np.arange(-90, 91, 15)) all_lamb = wu.deg2rad(np.arange(-180, 180, 1)) for beta in constants_beta: xyz = ell.ell2cart(beta, all_lamb) fig.add_trace(go.Scatter3d( x=xyz[:, 0], y=xyz[:, 1], z=xyz[:, 2], mode="lines", line=dict(width=1, color="black"), showlegend=False )) all_beta = wu.deg2rad(np.arange(-90, 91, 1)) all_beta[0] += 1e-8 all_beta[-1] -= 1e-8 constants_lamb = wu.deg2rad(np.arange(-180, 180, 15)) for lamb in constants_lamb: if lamb != 0 and abs(lamb) != np.pi: xyz = ell.ell2cart(all_beta, lamb) fig.add_trace(go.Scatter3d( x=xyz[:, 0], y=xyz[:, 1], z=xyz[:, 2], mode="lines", line=dict(width=1, color="black"), showlegend=False )) else: x, y, z = ell.para2cart(wu.deg2rad(np.arange(-90, 91, 1)), lamb) fig.add_trace(go.Scatter3d( x=x, y=y, z=z, mode="lines", line=dict(width=1, color="black"), showlegend=False )) elif coordsystem == "geod": constants_phi = wu.deg2rad(np.arange(-90, 91, 15)) all_lamb = wu.deg2rad(np.arange(-180, 180, 1)) for phi in constants_phi: x, y, z = ell.geod2cart(phi, all_lamb, 0) fig.add_trace(go.Scatter3d( x=x, y=y, z=z, mode="lines", line=dict(width=1, color="black"), showlegend=False )) all_phi = wu.deg2rad(np.arange(-90, 91, 1)) constants_lamb = wu.deg2rad(np.arange(-180, 180, 15)) for lamb in constants_lamb: x, y, z = ell.geod2cart(all_phi, lamb, 0) fig.add_trace(go.Scatter3d( x=x, y=y, z=z, mode="lines", line=dict(width=1, color="black"), showlegend=False )) return fig def figure_points(fig, points): """ :param fig: plotly.graph_objects.Figure :param points: Punktliste [(name, (x,y,z), color)] :return: plotly.graph_objects.Figure """ for name, (px, py, pz), color in points: fig.add_trace(go.Scatter3d( x=[px], y=[py], z=[pz], mode="markers+text", marker=dict(size=6, color=color), text=[name], textposition="top center", name=name, showlegend=False )) return fig def figure_lines(fig, line, color): """ :param fig: plotly.graph_objects.Figure :param line: Punktliste [[x1,y1,z1], [x2,y2,z2]] :param color: Farbe :return: plotly.graph_objects.Figure """ points = np.array(line, dtype=float) fig.add_trace(go.Scatter3d( x=points[:, 0], y=points[:, 1], z=points[:, 2], mode="lines", line=dict(width=4, color=color), name="Strecke", showlegend=False )) return fig # HTML-Elemente app.layout = html.Div( style={"fontFamily": "Arial", "padding": "10px", "width": "95%", "margin": "0 auto"}, children=[ html.H1("Geodätische Hauptaufgaben"), html.H2("für dreiachsige Ellipsoide"), html.Div( style={ "display": "flex", "alignItems": "flex-start", "gap": "24px", "flexWrap": "nowrap" }, children=[ html.Div( style={"flex": "1 1 420px", "maxWidth": "640px"}, children=[ html.Label("Ellipsoid wählen:"), dcc.Dropdown( id="dropdown-ellipsoid", options=[ {"label": "BursaFialova1993", "value": "BursaFialova1993"}, {"label": "BursaSima1980", "value": "BursaSima1980"}, {"label": "BursaSima1980round", "value": "BursaSima1980round"}, {"label": "Eitschberger1978", "value": "Eitschberger1978"}, {"label": "Bursa1972", "value": "Bursa1972"}, {"label": "Bursa1970", "value": "Bursa1970"}, {"label": "BesselBiaxial", "value": "BesselBiaxial"}, {"label": "KarneyTest2024", "value": "KarneyTest2024"}, {"label": "Fiction", "value": "Fiction"}, ], value="", style={"width": "300px", "marginBottom": "16px"}, ), html.P("Halbachsen:", style={"marginBottom": "10px"}), inputfeld("aₓ", "input-ax", "m", min=0), inputfeld("aᵧ", "input-ay", "m", min=0), inputfeld("b", "input-b", "m", min=0), dcc.Tabs( id="tabs-GHA", value="tab-GHA1", style={"margin": "20px 0 15px", "width": "100%"}, children=[ dcc.Tab(label="Erste Hauptaufgabe", value="tab-GHA1"), dcc.Tab(label="Zweite Hauptaufgabe", value="tab-GHA2"), ], ), html.Div(id="tabs-GHA-out", style={"marginBottom": "10px"}), dcc.Loading(html.Div(id="output-gha1-ana")), dcc.Loading(html.Div(id="output-gha1-num")), dcc.Loading(html.Div(id="output-gha1-stoch")), dcc.Loading(html.Div(id="output-gha1-approx")), dcc.Loading(html.Div(id="output-gha2-num")), dcc.Loading(html.Div(id="output-gha2-stoch")), dcc.Loading(html.Div(id="output-gha2-approx")), dcc.Store(id="store-gha1-ana"), dcc.Store(id="store-gha1-num"), dcc.Store(id="store-gha1-stoch"), dcc.Store(id="store-gha1-approx"), dcc.Store(id="store-gha2-num"), dcc.Store(id="store-gha2-stoch"), dcc.Store(id="store-gha2-approx"), ], ), html.Div( style={ "flex": "1 1 750px", "minWidth": "520px", "position": "sticky", "top": "0", "marginTop": "-50px", }, children=[ html.Label("Koordinatenart wählen:"), dcc.Dropdown( id="dropdown-coors-type", options=[ {"label": "Ellipsoidisch", "value": "ell"}, {"label": "Parametrisch", "value": "para"}, {"label": "Geodätisch", "value": "geod"}, ], value="ell", clearable=False, style={"width": "300px"}, ), dcc.Graph( id="ellipsoid-plot", style={"height": "85vh", "width": "100%"}, config={"responsive": True} ) ], ), ], ), #html.P("© 2026", style={"fontSize": "10px", "color": "gray", "textAlign": "center", "marginTop": "16px"}), ], ) # Funktion zur Wahl der Halbachsen @app.callback( Output("input-ax", "value"), Output("input-ay", "value"), Output("input-b", "value"), Input("dropdown-ellipsoid", "value"), ) 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 b = ell.b return ax, ay, b # Funktion zur Generierung der Tab-Inhalte @app.callback( Output("tabs-GHA-out", "children"), Input("tabs-GHA", "value"), ) def render_content(tab): show1 = {"display": "block"} if tab == "tab-GHA1" else {"display": "none"} show2 = {"display": "block"} if tab == "tab-GHA2" else {"display": "none"} pane_gha1 = html.Div( [ inputfeld("β₀", "input-GHA1-beta0", "°", min=-90, max=90), inputfeld("λ₀", "input-GHA1-lamb0", "°", min=-180, max=180), 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": "Stochastisch (ES)", "value": "stochastisch"}, {"label": "Approximiert", "value": "approx"}, ], value=[], style={"marginBottom": "10px", "marginLeft": "10px"}, ), html.Div( [ html.Button( "Berechnen", id="button-calc-gha1", n_clicks=0, style={"marginRight": "10px", "marginLeft": "10px"}, ), ], style={"marginBottom": "20px"}, ), ], id="pane-gha1", style=show1, ) pane_gha2 = html.Div( [ inputfeld("β₀", "input-GHA2-beta0", "°", min=-90, max=90), inputfeld("λ₀", "input-GHA2-lamb0", "°", min=-180, max=180), 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"}, ), html.Div( [ html.Button( "Berechnen", id="button-calc-gha2", n_clicks=0, style={"marginRight": "10px", "marginLeft": "10px"}, ), ], style={"marginBottom": "20px"}, ), ], id="pane-gha2", style=show2, ) return html.Div([pane_gha1, pane_gha2]) # -- GHA 1 --- @app.callback( Output("output-gha1-ana", "children"), Output("store-gha1-ana", "data"), Input("button-calc-gha1", "n_clicks"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), State("input-GHA1-a", "value"), 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): out = html.Div([ html.H4("Erste Hauptaufgabe"), ]) 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 "analytisch" not in (method1 or []): return out, no_update ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) alpha_rad = wu.deg2rad(float(a0)) s_val = float(s) P0 = ell.ell2cart(beta_rad, lamb_rad) P1_ana, alpha2 = gha1_ana(ell, P0, alpha_rad, s_val, 70) 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"), html.Br(), html.Span(f"elliptisch: {aus.gms('β₁', beta2_ana, 4)}, {aus.gms('λ₁', lamb2_ana, 4)}"), html.Br(), ]) store = { "points": [("P0", P0, "black"), ("P1", P1_ana, "red")], "polyline": None, "color": "#d62728" } return out, store @app.callback( Output("output-gha1-num", "children"), Output("store-gha1-num", "data"), Input("button-calc-gha1", "n_clicks"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), State("input-GHA1-a", "value"), 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): if not n1: return no_update, no_update if "numerisch" not in (method1 or []): return no_update, no_update ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) alpha_rad = wu.deg2rad(float(a0)) s_val = float(s) P0 = ell.ell2cart(beta_rad, lamb_rad) P1_num, alpha1, werte = gha1_num(ell, P0, alpha_rad, s_val, 10000, all_points=True) beta2_num, lamb2_num = ell.cart2ell(P1_num) out = html.Div([ html.Strong("Numerisch: "), html.Br(), html.Span(f"kartesisch: x₁={P1_num[0]:.4f} m, y₁={P1_num[1]:.4f} m, z₁={P1_num[2]:.4f} m"), html.Br(), html.Span(f"elliptisch: {aus.gms('β₁', beta2_num, 4)}, {aus.gms('λ₁', lamb2_num, 4)}"), html.Br(), ]) polyline = [[x1, y1, z1] for x1, _, y1, _, z1, _ in werte] store = { "points": [("P0", P0, "black"), ("P1", P1_num, "#ff8c00")], "polyline": polyline, "color": "#ff8c00" } return out, store @app.callback( Output("output-gha1-stoch", "children"), Output("store-gha1-stoch", "data"), Input("button-calc-gha1", "n_clicks"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), State("input-GHA1-a", "value"), State("input-ax", "value"), State("input-ay", "value"), State("input-b", "value"), State("method-checklist-1", "value"), prevent_initial_call=True, ) def compute_gha1_stoch(n1, beta0, lamb0, s, a0, ax, ay, b, method1): if not n1: return no_update, no_update if "stochastisch" not in (method1 or []): return no_update, no_update ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) alpha_rad = wu.deg2rad(float(a0)) s_val = float(s) betas, lambs, alphas, S_real = gha1_es( beta_rad, lamb_rad, alpha_rad, s_val, 10000, ell ) beta1_stoch = betas[-1] lamb1_stoch = lambs[-1] P0 = ell.ell2cart(beta_rad, lamb_rad) P1_stoch = ell.ell2cart(beta1_stoch, lamb1_stoch) out = html.Div([ html.Strong("Stochastisch: "), html.Br(), html.Span(f"kartesisch: x₁={P1_stoch[0]:.4f} m, y₁={P1_stoch[1]:.4f} m, z₁={P1_stoch[2]:.4f} m"), html.Br(), html.Span(f"elliptisch: {aus.gms('β₁', beta1_stoch, 4)}, {aus.gms('λ₁', lamb1_stoch, 4)}"), ]) store = { "points": [("P0", P0, "black"), ("P1", P1_stoch, "red")], "polyline": None, "color": "#d62728" } return out, store @app.callback( Output("output-gha1-approx", "children"), Output("store-gha1-approx", "data"), Input("button-calc-gha1", "n_clicks"), State("input-GHA1-beta0", "value"), State("input-GHA1-lamb0", "value"), State("input-GHA1-s", "value"), State("input-GHA1-a", "value"), 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): if not n1: return no_update, no_update if "approx" not in (method1 or []): return no_update, no_update ell = EllipsoidTriaxial(ax, ay, b) beta_rad = wu.deg2rad(float(beta0)) lamb_rad = wu.deg2rad(float(lamb0)) alpha_rad = wu.deg2rad(float(a0)) s_val = float(s) P0 = ell.ell2cart(beta_rad, lamb_rad) P1_app, alpha1_app, points = gha1_approx(ell, P0, alpha_rad, s_val, ds=5000, all_points=True) beta1_app, lamb1_app = ell.cart2ell(P1_app) out = html.Div([ html.Strong("Approximiert: "), html.Br(), html.Span(f"kartesisch: x₁={P1_app[0]:.4f} m, y₁={P1_app[1]:.4f} m, z₁={P1_app[2]:.4f} m"), html.Br(), html.Span(f"elliptisch: {aus.gms('β₁', beta1_app, 4)}, {aus.gms('λ₁', lamb1_app, 4)}"), ]) store = { "points": [("P0", P0, "black"), ("P1", P1_app, "red")], "polyline": None, "color": "#d62728" } return out, store # --- GHA 2 --- @app.callback( Output("output-gha2-num", "children"), Output("store-gha2-num", "data"), Input("button-calc-gha2", "n_clicks"), State("input-GHA2-beta0", "value"), State("input-GHA2-lamb0", "value"), State("input-GHA2-beta1", "value"), State("input-GHA2-lamb1", "value"), 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): out = html.Div([ html.H4("Zweite Hauptaufgabe"), ]) if not n2: 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, 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 ell = EllipsoidTriaxial(ax, ay, b) beta0_rad = wu.deg2rad(float(beta0)) lamb0_rad = wu.deg2rad(float(lamb0)) beta1_rad = wu.deg2rad(float(beta1)) lamb1_rad = wu.deg2rad(float(lamb1)) 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) polyline = [] for b_rad, l_rad in zip(beta_arr, lamb_arr): x, y, z = ell.ell2cart(b_rad, l_rad) 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"), ]) store = { "points": [("P0", P0, "black"), ("P1", P1, "#1f77b4")], "polyline": polyline, "color": "#1f77b4", } return out, store @app.callback( Output("output-gha2-stoch", "children"), Output("store-gha2-stoch", "data"), Input("button-calc-gha2", "n_clicks"), State("input-GHA2-beta0", "value"), State("input-GHA2-lamb0", "value"), State("input-GHA2-beta1", "value"), State("input-GHA2-lamb1", "value"), 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): if not n2: return no_update, no_update if "stochastisch" not in (method2 or []): return no_update, no_update ell = EllipsoidTriaxial(ax, ay, b) beta0_rad = wu.deg2rad(float(beta0)) lamb0_rad = wu.deg2rad(float(lamb0)) beta1_rad = wu.deg2rad(float(beta1)) lamb1_rad = wu.deg2rad(float(lamb1)) 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, all_points=True) out = html.Div([ html.Strong("Stochastisch (ES): "), html.Span(f"{aus.gms('α₀', a0_stoch, 4)}, α₁ = {a1_stoch}, s = {s_stoch:.4f} m"), ]) return out, {"points": None, "polyline": None, "color": "#9467bd"} @app.callback( Output("output-gha2-approx", "children"), Output("store-gha2-approx", "data"), Input("button-calc-gha2", "n_clicks"), State("input-GHA2-beta0", "value"), State("input-GHA2-lamb0", "value"), State("input-GHA2-beta1", "value"), State("input-GHA2-lamb1", "value"), 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): if not n2: return no_update, no_update if "approx" not in (method2 or []): return no_update, no_update ell = EllipsoidTriaxial(ax, ay, b) beta0_rad = wu.deg2rad(float(beta0)) lamb0_rad = wu.deg2rad(float(lamb0)) beta1_rad = wu.deg2rad(float(beta1)) lamb1_rad = wu.deg2rad(float(lamb1)) 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=1e-4, all_points=True) out = html.Div([ html.Strong("Approximiert: "), html.Span(f"{aus.gms('α₀', a0_app, 4)}, {aus.gms('α₁', a1_app, 4)}, s = {s_app:.4f} m"), ]) return out, {"points": None, "polyline": None, "color": "#94cccc"} # --- Plot --- @app.callback( Output("ellipsoid-plot", "figure"), Input("input-ax", "value"), Input("input-ay", "value"), Input("input-b", "value"), Input("dropdown-coors-type", "value"), Input("store-gha1-ana", "data"), Input("store-gha1-num", "data"), Input("store-gha1-stoch", "data"), Input("store-gha1-approx", "data"), Input("store-gha2-num", "data"), Input("store-gha2-stoch", "data"), Input("store-gha2-approx", "data"), ) def render_all(ax, ay, b, coords_type, store_gha1_ana, store_gha1_num, store_gha1_stoch, store_gha1_approx, store_gha2_num, store_gha2_stoch, store_gha2_approx): if None in (ax, ay, b): return go.Figure() ell = EllipsoidTriaxial(ax, ay, b) fig = ellipsoid_figure(ell, title="") fig = figure_constant_lines(fig, ell, coords_type) def add_from_store(fig, store): if not store: return fig 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("color", "#ff8c00")) return fig for st in (store_gha1_ana, store_gha1_num, store_gha1_stoch, store_gha1_approx, store_gha2_num, store_gha2_stoch, store_gha2_approx): fig = add_from_store(fig, st) return fig if __name__ == "__main__": app.run(debug=False)