CalculusWithJuliaNotes.jl/CwJ/makie-demos/tangent-line.jl
2022-05-24 13:51:49 -04:00

103 lines
2.5 KiB
Julia

using AbstractPlotting
using AbstractPlotting.MakieLayout
using GLMakie
using ForwardDiff
Base.adjoint(f::Function) = x -> ForwardDiff.derivative(f, float(x))
function tangent_line(f=nothing, a=0, b=pi)
if f == nothing
f = x -> sin(x)
end
descr = """
The tangent line has a slope approximated by the slope of secant lines.
This demo allows the points c and c+h to be adjusted to see the two lines"""
## From http://juliaplots.org/MakieReferenceImages/gallery//edit_polygon/index.html:
function add_move!(scene, points, pplot)
idx = Ref(0); dragstart = Ref(false); startpos = Base.RefValue(Point2f0(0))
on(events(scene).mousedrag) do drag
if ispressed(scene, Mouse.left)
if drag == Mouse.down
plot, _idx = mouse_selection(scene)
if plot == pplot
idx[] = _idx; dragstart[] = true
startpos[] = to_world(scene, Point2f0(scene.events.mouseposition[]))
end
elseif drag == Mouse.pressed && dragstart[] && checkbounds(Bool, points[], idx[])
pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
# we work with components not vector
x,y = pos
x = clamp(x, a, b)
y = f(x)
points[][idx[]] = [x,y]
points[] = points[]
end
else
dragstart[] = false
end
return
end
end
c, h = pi/4, .5
points = Node(Point2f0[(c, f(c)), (c+h, f(c+h))])
# where we lay our scene:
scene, layout = layoutscene()
layout.halign = :left
layout.valign = :top
p = layout[1,1:2] = LScene(scene)
rowsize!(layout, 1, Auto(1))
colsize!(layout, 1, Auto(1))
layout[2,1:2] = LText(scene, descr)
secline = lift(points) do pts
c, ch = pts
x0, y0 = c
x1, y1 = ch
m = (y1 - y0)/(x1 - x0)
sl = x -> y0 + m * (x - x0)
Point2f0[(a, sl(a)), (b, sl(b))]
end
tangentline = lift(points) do pts
c, ch = pts
x0, y0 = c
m = f'(x0)
tl = x -> y0 + m * (x - x0)
Point2f0[(a, tl(a)), (b, tl(b))]
end
lines!(p.scene, a..b, f, strokecolor=:red, strokewidth=15)
lines!(p.scene, secline, color = :blue, strokewidth = 10, raw=true)
lines!(p.scene, tangentline, color = :red, strokewidth = 10, raw=true)
scatter!(p.scene, points, color = :white, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
xlims!(p.scene, (a, b))
#ylims!(p.scene, (0, 1.5))
add_move!(p.scene, points, p.scene[end])
scene
end
tangent_line()