File size: 4,530 Bytes
e66cfb4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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)