Skip to content

Commit b376625

Browse files
Merge pull request #217 from Speedrunyourknowledge/develop
Add Visible Axis Lines to Graphs
2 parents e00552a + 55fca6e commit b376625

27 files changed

+2157
-1726
lines changed

calc-backend/graph-gen/graph-deriv.py

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,50 @@ def derivative(func, x, h=1e-5):
4141
x_vals = np.linspace(x_range[0], x_range[1], num=51)
4242
f_vals = f(x_vals)
4343

44-
# Initialize the Plotly figure and plot the original function.
44+
# Initialize the Plotly figure
4545
fig = go.Figure()
46-
fig.add_trace(go.Scatter(x=x_vals, y=f_vals, mode='lines', name='Function'))
46+
47+
# Adjust padding for final layout
48+
pad = min(np.abs(np.min(f_vals)), np.abs(np.max(f_vals))) + (max(np.abs(np.min(f_vals)), np.abs(np.max(f_vals))) // 20)
49+
50+
# Set the final y-axis range with padding
51+
y_min = np.min(f_vals) - pad
52+
y_max = np.max(f_vals) + pad
53+
54+
# Vertical line at x=0 (y-axis)
55+
if x_range[0] < 0 < x_range[1]:
56+
fig.add_trace(go.Scatter(
57+
x=[0, 0],
58+
y=[y_min, y_max],
59+
mode='lines',
60+
line=dict(color='silver', width=2),
61+
showlegend=False
62+
))
63+
64+
# Horizontal line at y=0 (x-axis)
65+
if y_min < 0 < y_max:
66+
fig.add_trace(go.Scatter(
67+
x=[x_range[0], x_range[1]],
68+
y=[0, 0],
69+
mode='lines',
70+
line=dict(color='silver', width=2),
71+
showlegend=False
72+
))
73+
74+
# Plot the original function
75+
fig.add_trace(go.Scatter(x=x_vals, y=f_vals, mode='lines', name='Function', line=dict(color='#6570f9', width=2)))
4776

4877
# Calculate the tangent line at the starting point x_range[0].
4978
x0 = x_range[0]
5079
tangent_y = derivative(f, x0) * (x_vals - x0) + f(x0)
51-
fig.add_trace(go.Scatter(x=x_vals, y=tangent_y, mode='lines', name='Tangent'))
80+
fig.add_trace(go.Scatter(x=x_vals, y=tangent_y, mode='lines', name='Tangent', line=dict(color='#eb553d', width=2)))
5281

5382
# Add a marker for the point of tangency.
5483
fig.add_trace(go.Scatter(x=[x0], y=[f(x0)],
55-
mode='markers',
56-
marker=dict(size=12, color='green'),
57-
name='Point'))
84+
mode='markers',
85+
marker=dict(size=12, color='green'),
86+
name='Point')
87+
)
5888

5989
# Set the initial layout title with the slope at the starting point.
6090
fig.update_layout(title=(f'Slope Value = {derivative(f, x0):.4f}'), title_font_size=16)
@@ -65,18 +95,30 @@ def derivative(func, x, h=1e-5):
6595
# Create frames for the animation slider.
6696
frames = []
6797
for slider_val in x_vals:
68-
# Compute the tangent line at each slider value using our numerical derivative.
69-
save_deriv = derivative(f, slider_val)
70-
tan_y = save_deriv * (x_vals - slider_val) + f(slider_val)
71-
frames.append(go.Frame(
72-
data=[
73-
go.Scatter(), # Placeholder for the function trace (remains unchanged).
74-
go.Scatter(x=x_vals, y=tan_y), # Tangent line.
75-
go.Scatter(x=[slider_val], y=[f(slider_val)]) # Point of tangency.
76-
],
77-
layout=go.Layout(title=(f'Slope Value = {save_deriv:.4f}'), yaxis_range= initial_yaxis, yaxis={'autorange':False}),
78-
name=str(slider_val)
79-
))
98+
# Compute the tangent line at each slider value using our numerical derivative.
99+
save_deriv = derivative(f, slider_val)
100+
tan_y = save_deriv * (x_vals - slider_val) + f(slider_val)
101+
frame_data=[]
102+
103+
# Conditionally add vertical line at x=0
104+
if x_range[0] < 0 < x_range[1]:
105+
frame_data.append(go.Scatter(x=[0, 0], y=[y_min, y_max]))
106+
107+
# Conditionally add horizontal line at y=0
108+
if y_min < 0 < y_max:
109+
frame_data.append(go.Scatter(x=[x_range[0], x_range[1]]))
110+
111+
# Placeholder for the function trace (remains unchanged)
112+
frame_data.append(go.Scatter())
113+
frame_data.append(go.Scatter(x=x_vals, y=tan_y)) # Tangent line
114+
frame_data.append(go.Scatter(x=[slider_val], y=[f(slider_val)])) # Point of tangency
115+
116+
frames.append(go.Frame(
117+
data=frame_data,
118+
layout=go.Layout(title=(f'Slope Value = {save_deriv:.4f}'), yaxis_range= initial_yaxis, yaxis={'autorange':False}),
119+
name=str(slider_val)
120+
))
121+
80122
fig.frames = frames
81123

82124
# Create a slider to control the animation.
@@ -104,13 +146,11 @@ def derivative(func, x, h=1e-5):
104146
pad={"t": 10, "b": 10},
105147
)]
106148

107-
# Adjust padding and final layout settings.
108-
pad = min(np.abs(np.min(f_vals)), np.abs(np.max(f_vals))) + (max(np.abs(np.min(f_vals)), np.abs(np.max(f_vals))) // 20)
109149
fig.update_layout(
110150
xaxis_title='x-axis',
111151
yaxis_title='y-axis',
112152
xaxis=dict(range=[x_range[0], x_range[1]], fixedrange=True),
113-
yaxis=dict(range=[np.min(f_vals) - pad, np.max(f_vals) + pad], fixedrange=True),
153+
yaxis=dict(range=[y_min, y_max], fixedrange=True),
114154
sliders=sliders,
115155
uirevision='static',
116156
margin=dict(t=50, r=0,l=60),

calc-backend/graph-gen/graph-integral.py

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,29 @@ def generate_bars(n_bars):
5555
initial_bars = 10
5656
x_bar, y_bar, width = generate_bars(initial_bars)
5757

58-
fig = px.line(x=x_line, y=y_line)
59-
60-
# adds a line at x = 0 if the lower bound is negative
61-
if a < 0:
62-
fig.add_vline(x=0, line_width=2, line_color="#a5adad")
58+
# Function graph
59+
fig = px.line(x=x_line, y=y_line, color_discrete_sequence=['#6570f9'])
6360

6461
fig.update_traces(hovertemplate="(%{x:.2f}, %{y:.2f})", name="Function", showlegend=False)
6562

63+
# Adjust padding for final layout
64+
pad = min(np.abs(np.min(y_line)), np.abs(np.max(y_line))) + (max(np.abs(np.min(y_line)), np.abs(np.max(y_line))) // 20)
65+
66+
# Set the final y-axis range with padding
67+
y_min = np.min(y_line) - pad
68+
y_max = np.max(y_line) + pad
69+
70+
# Vertical line at x=0 (y-axis)
71+
if a < 0 < b:
72+
fig.add_trace(go.Scatter(
73+
x=[0, 0],
74+
y=[y_min, y_max],
75+
mode='lines',
76+
line=dict(color='silver', width=2),
77+
showlegend=False
78+
))
79+
80+
# Bar graph
6681
bar_trace = go.Bar(
6782
x=x_bar,
6883
y=y_bar,
@@ -105,28 +120,59 @@ def generate_bars(n_bars):
105120
f'Approx. Area = {np.round(midpoint_integrate(func, a, b, initial_bars), 9)}'
106121
f'<br> True Area = {np.round(area, 9)}'), title_font_size=14, title_pad_b=2)
107122

123+
# Create steps for the slider
108124
steps = []
109125
for n_bars in range(initial_bars, 101, 5):
110-
x_bar, y_bar, width = generate_bars(n_bars)
111-
step = dict(
112-
method="update",
113-
args=[
114-
{"x": [x_line, x_bar], "y": [y_line, y_bar], "width": [None, [width] * len(x_bar)],
115-
"marker": dict(color=['#31b500' if value > 0 else '#ff3c00' for value in y_bar],
116-
line=dict(color='black', width=1))},
117-
{"title.text": f'Approx. Area = {np.round(midpoint_integrate(func, a, b, n_bars), 9)}'
118-
f'<br> True Area = {np.round(area, 9)}'}
119-
],
120-
label=f"{n_bars}"
121-
)
122-
steps.append(step)
126+
x_bar, y_bar, width = generate_bars(n_bars)
127+
x_args=[]
128+
y_args=[]
129+
width_args = []
130+
marker_args = []
131+
line_args = []
132+
133+
# Conditionally add axis line trace args
134+
if a < 0 < b:
135+
x_args.append([0, 0])
136+
y_args.append([y_min, y_max])
137+
width_args.append(None)
138+
line_args.append(dict(color='silver', width=2))
139+
140+
# Function trace args
141+
x_args.append(x_line)
142+
y_args.append(y_line)
143+
width_args.append(None)
144+
line_args.append(dict(color='#6570f9', width=2))
145+
146+
# Bar trace args
147+
x_args.append(x_bar)
148+
y_args.append(y_bar)
149+
width_args.append([width] * len(x_bar))
150+
marker_args.append(dict(
151+
color=['#31b500' if value > 0 else '#ff3c00' for value in y_bar],
152+
line=dict(color='black', width=1)
153+
))
154+
155+
step = dict(
156+
method="update",
157+
args=[
158+
{
159+
"x": x_args, "y": y_args, "width": width_args, "marker": marker_args, "line": line_args
160+
},
161+
{
162+
"title.text": f'Approx. Area = {np.round(midpoint_integrate(func, a, b, n_bars), 9)}'
163+
f'<br> True Area = {np.round(area, 9)}'
164+
}
165+
],
166+
label=f"{n_bars}"
167+
)
168+
steps.append(step)
123169

124170
sliders = [dict(
125-
active=0,
126-
currentvalue={"prefix": "n = ", "font":{'size':14}},
127-
pad={"t": 30},
128-
bordercolor='#949fb3',
129-
steps=steps
171+
active=0,
172+
currentvalue={"prefix": "n = ", "font":{'size':14}},
173+
pad={"t": 30},
174+
bordercolor='#949fb3',
175+
steps=steps
130176
)]
131177

132178
fig.update_layout(
@@ -136,7 +182,7 @@ def generate_bars(n_bars):
136182
xaxis_title="x-axis",
137183
yaxis_title="y-axis",
138184
xaxis=dict(range=[a, b], fixedrange=True, showgrid=True),
139-
yaxis=dict(fixedrange=True),
185+
yaxis=dict(range=[y_min, y_max], fixedrange=True),
140186
)
141187

142188
fig_json = fig.to_json(pretty=True)

calc-frontend/public/cosineDeriv.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@
749749
"title": {
750750
"standoff": 15
751751
},
752-
"zerolinecolor": "white",
752+
"zerolinecolor": "silver",
753753
"automargin": true,
754754
"zerolinewidth": 2
755755
},
@@ -760,7 +760,7 @@
760760
"title": {
761761
"standoff": 15
762762
},
763-
"zerolinecolor": "white",
763+
"zerolinecolor": "silver",
764764
"automargin": true,
765765
"zerolinewidth": 2
766766
},
@@ -771,7 +771,7 @@
771771
"linecolor": "white",
772772
"showbackground": true,
773773
"ticks": "",
774-
"zerolinecolor": "white",
774+
"zerolinecolor": "silver",
775775
"gridwidth": 2
776776
},
777777
"yaxis": {
@@ -780,7 +780,7 @@
780780
"linecolor": "white",
781781
"showbackground": true,
782782
"ticks": "",
783-
"zerolinecolor": "white",
783+
"zerolinecolor": "silver",
784784
"gridwidth": 2
785785
},
786786
"zaxis": {
@@ -789,7 +789,7 @@
789789
"linecolor": "white",
790790
"showbackground": true,
791791
"ticks": "",
792-
"zerolinecolor": "white",
792+
"zerolinecolor": "silver",
793793
"gridwidth": 2
794794
}
795795
},

calc-frontend/public/cosineLim.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"data": [
33
{
44
"line": {
5-
"color": "lightgray",
6-
"width": 2
5+
"color": "gainsboro",
6+
"width": 3
77
},
88
"mode": "lines",
99
"name": "f(x)",
@@ -20,7 +20,7 @@
2020
{
2121
"line": {
2222
"color": "black",
23-
"width": 4
23+
"width": 3
2424
},
2525
"mode": "lines",
2626
"name": "From Left",
@@ -37,7 +37,7 @@
3737
{
3838
"line": {
3939
"color": "#FFCC00",
40-
"width": 4
40+
"width": 3
4141
},
4242
"mode": "lines",
4343
"name": "From Right",
@@ -775,7 +775,7 @@
775775
"title": {
776776
"standoff": 15
777777
},
778-
"zerolinecolor": "white",
778+
"zerolinecolor": "silver",
779779
"automargin": true,
780780
"zerolinewidth": 2
781781
},
@@ -786,7 +786,7 @@
786786
"title": {
787787
"standoff": 15
788788
},
789-
"zerolinecolor": "white",
789+
"zerolinecolor": "silver",
790790
"automargin": true,
791791
"zerolinewidth": 2
792792
},
@@ -797,7 +797,7 @@
797797
"linecolor": "white",
798798
"showbackground": true,
799799
"ticks": "",
800-
"zerolinecolor": "white",
800+
"zerolinecolor": "silver",
801801
"gridwidth": 2
802802
},
803803
"yaxis": {
@@ -806,7 +806,7 @@
806806
"linecolor": "white",
807807
"showbackground": true,
808808
"ticks": "",
809-
"zerolinecolor": "white",
809+
"zerolinecolor": "silver",
810810
"gridwidth": 2
811811
},
812812
"zaxis": {
@@ -815,7 +815,7 @@
815815
"linecolor": "white",
816816
"showbackground": true,
817817
"ticks": "",
818-
"zerolinecolor": "white",
818+
"zerolinecolor": "silver",
819819
"gridwidth": 2
820820
}
821821
},

0 commit comments

Comments
 (0)