import dash from dash import dcc, html, Input, Output import plotly.graph_objects as go import numpy as np # --- 1. ?????? --- def f(x, y): return 4 - x**2 - 2*y**2 def df_dx(x, y): # ? x ?? return -2 * x def df_dy(x, y): # ? y ?? return -4 * y # --- 2. ??? Dash App --- app = dash.Dash(__name__) # --- 3. ???? (Layout) --- app.layout = html.Div([ html.H2("????????? (Python?)", style={'textAlign': 'center'}), # ???? html.Div([ html.Div([ html.Label("?? a ?:"), dcc.Input(id='input-a', type='number', value=1, step=0.1), ], style={'marginRight': '20px', 'display': 'inline-block'}), html.Div([ html.Label("?? b ?:"), dcc.Input(id='input-b', type='number', value=1, step=0.1), ], style={'marginRight': '20px', 'display': 'inline-block'}), # ?? Checklist ?????? dcc.Checklist( id='toggle-switches', options=[ {'label': ' ???? C1 (x??)', 'value': 'show_c1'}, {'label': ' ???? T1', 'value': 'show_t1'}, {'label': ' ???? C2 (y??)', 'value': 'show_c2'}, {'label': ' ???? T2', 'value': 'show_t2'}, ], value=[], # ????? inline=True ) ], style={'padding': '20px', 'backgroundColor': '#f9f9f9'}), # ?????? html.Div(id='slope-info', style={'padding': '10px', 'fontSize': '18px', 'fontWeight': 'bold'}), # 3D ??? dcc.Graph(id='3d-surface-plot', style={'height': '80vh'}) ]) # --- 4. ???? (??????) --- @app.callback( [Output('3d-surface-plot', 'figure'), Output('slope-info', 'children')], [Input('input-a', 'value'), Input('input-b', 'value'), Input('toggle-switches', 'value')] ) def update_graph(a, b, toggles): # ?????????????????? if a is None: a = 1 if b is None: b = 1 # ?? P ??? z_val = f(a, b) # --- ?????? --- x_range = np.linspace(-3, 3, 50) y_range = np.linspace(-3, 3, 50) X, Y = np.meshgrid(x_range, y_range) Z = f(X, Y) fig = go.Figure() # 1. ??? (???) fig.add_trace(go.Surface(z=Z, x=X, y=Y, colorscale='Viridis', opacity=0.6, showscale=False, name='??')) # 2. ? P ? fig.add_trace(go.Scatter3d( x=[a], y=[b], z=[z_val], mode='markers', marker=dict(size=6, color='black'), name=f'P({a},{b})' )) # --- ?? C1 ? T1 (? x ??) --- slope_x = df_dx(a, b) info_text = [] if 'show_c1' in toggles: # C1: ?? y=b, x ?? t = np.linspace(-3, 3, 50) fig.add_trace(go.Scatter3d( x=t, y=[b]*50, z=f(t, b), mode='lines', line=dict(color='red', width=5), name='C1 (?? y=b)' )) if 'show_t1' in toggles: # T1: ?? (?????????) # ????? (1, 0, slope_x) t_tan = np.linspace(-1.5, 1.5, 10) # ???? x_tan = a + t_tan y_tan = [b] * 10 z_tan = z_val + slope_x * t_tan fig.add_trace(go.Scatter3d( x=x_tan, y=y_tan, z=z_tan, mode='lines', line=dict(color='red', width=4, dash='dash'), name=f'T1 ?? (m={slope_x:.2f})' )) info_text.append(f"x???? (fx) = {slope_x:.2f}") # --- ?? C2 ? T2 (? y ??) --- slope_y = df_dy(a, b) if 'show_c2' in toggles: # C2: ?? x=a, y ?? t = np.linspace(-3, 3, 50) fig.add_trace(go.Scatter3d( x=[a]*50, y=t, z=f(a, t), mode='lines', line=dict(color='blue', width=5), name='C2 (?? x=a)' )) if 'show_t2' in toggles: # T2 ?? # ????? (0, 1, slope_y) t_tan = np.linspace(-1.5, 1.5, 10) x_tan = [a] * 10 y_tan = b + t_tan z_tan = z_val + slope_y * t_tan fig.add_trace(go.Scatter3d( x=x_tan, y=y_tan, z=z_tan, mode='lines', line=dict(color='blue', width=4, dash='dash'), name=f'T2 ?? (m={slope_y:.2f})' )) info_text.append(f"y???? (fy) = {slope_y:.2f}") # --- ????????? --- fig.update_layout( scene=dict( xaxis=dict(range=[-3, 3]), yaxis=dict(range=[-3, 3]), zaxis=dict(range=[-5, 5]), aspectratio=dict(x=1, y=1, z=0.7) ), margin=dict(l=0, r=0, b=0, t=0) ) return fig, " | ".join(info_text) if info_text else "????????????" # --- 5. ????? --- if __name__ == '__main__': app.run(debug=True)