initial
This commit is contained in:
9
CwJ/makie-demos/Project.toml
Normal file
9
CwJ/makie-demos/Project.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[deps]
|
||||
AbstractPlotting = "537997a7-5e4e-5d89-9595-2241ea00577e"
|
||||
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
|
||||
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
|
||||
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
|
||||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
|
||||
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
|
||||
WGLMakie = "276b4fcb-3e11-5398-bf8b-a0c2d153d008"
|
||||
15
CwJ/makie-demos/README.md
Normal file
15
CwJ/makie-demos/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Demos
|
||||
|
||||
A collection of little demos made using Makie graphics, which allows interactivity through the dragging of points or the use of simple controls.
|
||||
|
||||
* `tangent-line`: see how the slope of secant line converges to the slope of the tangent line as `h` goes to 0
|
||||
|
||||
* `optimization`: Identify the optimal crossing point to minimize time when there are different velocities north and south of the x axis.
|
||||
|
||||
* `inscribed-area`: Identify the maximal inscribed rectangle
|
||||
|
||||
* `integration`: Compare visually the left Riemann approximation, the trapezoid method, and Simpson's method for different values of `n`.
|
||||
|
||||
* `spirograph`: adjust parameters for the plotting of spirograph(https://en.wikipedia.org/wiki/Spirograph) patterns.
|
||||
|
||||
* `bezier`: create Bezier curves by dragging control points.
|
||||
112
CwJ/makie-demos/bezier.jl
Normal file
112
CwJ/makie-demos/bezier.jl
Normal file
@@ -0,0 +1,112 @@
|
||||
using AbstractPlotting
|
||||
using AbstractPlotting.MakieLayout
|
||||
using GLMakie
|
||||
|
||||
using LinearAlgebra
|
||||
|
||||
|
||||
function bezier()
|
||||
descr = """
|
||||
Bezier Curves: B(t) = ∑(binomial(n,i) * tⁱ * (1-t)⁽ⁿ⁻¹⁾ * Pᵢ)
|
||||
"""
|
||||
|
||||
## 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[]))
|
||||
|
||||
# very wierd, but we work with components
|
||||
# not vector
|
||||
z = zero(eltype(pos))
|
||||
x,y = pos
|
||||
|
||||
ptidx = idx[]
|
||||
|
||||
x = clamp(x, -1, 1)
|
||||
y = clamp(y, -1, 1)
|
||||
|
||||
points[][idx[]] = [x,y]
|
||||
points[] = points[]
|
||||
end
|
||||
else
|
||||
dragstart[] = false
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
upperpoints = Point2f0[(0,0), (5, 0), (5, 5), (0,5)]
|
||||
lowerpoints = (Point2f0[(0,0), (5, 0), (5, -5), (0,-5)])
|
||||
|
||||
points = Node(Point2f0[(1, 4), (3, 0), (4,-4.0)])
|
||||
|
||||
# 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))
|
||||
colsize!(layout, 2, Auto(1))
|
||||
|
||||
npts = layout[2,1:2] = LSlider(scene, range=3:12, startvalue=4)
|
||||
layout[3,1:2] = LText(scene, chomp(descr))
|
||||
|
||||
# points = Node(Point2f0[(-1/2, -1/2),
|
||||
# (-1/2, 1/2),
|
||||
# (1/2, 1/2),
|
||||
# (1/2, -1/2)])
|
||||
|
||||
#npts = 6
|
||||
#ts = range(3pi/2, -pi/2, length=npts+2)
|
||||
#points = Node(Point2f0[(cos(t),sin(t)) for t in ts[2:end-1]])
|
||||
|
||||
points = lift(npts.value) do val
|
||||
ts = range(3pi/2, -pi/2, length=val+2)
|
||||
Point2f0[(cos(t),sin(t)) for t in ts[2:end-1]]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bcurve = lift(points) do pts
|
||||
n = length(pts) - 1
|
||||
B = t -> begin
|
||||
tot = 0.0
|
||||
for (i′, Pᵢ) in enumerate(pts)
|
||||
i = i′ - 1
|
||||
tot += binomial(n, i) * t^i * (1-t)^(n-i) * Pᵢ
|
||||
end
|
||||
tot
|
||||
end
|
||||
ts = range(0, 1, length=200)
|
||||
Point2f0[B(t) for t in ts]
|
||||
end
|
||||
|
||||
|
||||
|
||||
lines!(p.scene, bcurve, strokecolor=:black, strokewidth=15)
|
||||
lines!(p.scene, points, strokecolor=:gray90, strokewidth=5, linestyle=:dash)
|
||||
scatter!(p.scene, points)
|
||||
xlims!(p.scene, (-1,1))
|
||||
ylims!(p.scene, (-1,1))
|
||||
add_move!(p.scene, points, p.scene[end])
|
||||
|
||||
|
||||
|
||||
scene
|
||||
|
||||
end
|
||||
128
CwJ/makie-demos/inscribed-area.jl
Normal file
128
CwJ/makie-demos/inscribed-area.jl
Normal file
@@ -0,0 +1,128 @@
|
||||
using AbstractPlotting
|
||||
using AbstractPlotting.MakieLayout
|
||||
using GLMakie
|
||||
|
||||
using Roots
|
||||
|
||||
## Assumes f(a), f(b) are zero
|
||||
## only 1 or 2 solutions for f(x) = f(c) for any c in [a,b]
|
||||
f(x) = 1 - x^4
|
||||
a = -1
|
||||
b = 1
|
||||
|
||||
descr = """
|
||||
Adjust the point (c, f(c)) with c > 0 to find the inscribed rectangle with maximal area
|
||||
"""
|
||||
|
||||
|
||||
function _inscribed_area(c)
|
||||
zs = fzeros(u -> f(u) - f(c), a, b)
|
||||
length(zs) <= 1 ? 0 : abs(zs[1] - zs[2]) * f(c)
|
||||
end
|
||||
D(f) = c -> (f(c + 1e-4) - f(c))/1e-4
|
||||
function answer()
|
||||
h = 1e-4
|
||||
zs = fzeros(D(_inscribed_area), 0, b-h)
|
||||
a,i = findmax(_inscribed_area.(zs))
|
||||
a
|
||||
end
|
||||
|
||||
Answer = answer()
|
||||
|
||||
|
||||
## 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[])
|
||||
|
||||
if idx[] == 3
|
||||
pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
|
||||
|
||||
# we work with components not vector
|
||||
x,y = pos
|
||||
c = clamp(x, a, b)
|
||||
zs = fzeros(u -> f(u) - f(c), a , b)
|
||||
|
||||
if length(zs) == 1
|
||||
c′ = c = first(zs)
|
||||
else
|
||||
c′, c = zs
|
||||
end
|
||||
|
||||
|
||||
points[][1] = [c′, 0]
|
||||
points[][2] = [c′, f(c′)]
|
||||
points[][3] = [c, f(c)]
|
||||
points[][4] = [c, 0]
|
||||
points[] = points[]
|
||||
end
|
||||
end
|
||||
else
|
||||
dragstart[] = false
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
c = b/2
|
||||
c′ = first(fzeros(u -> f(u) - f(c), a , b))
|
||||
area = round(abs(c - c′) * f(c), digits=4)
|
||||
|
||||
points = Node(Point2f0[(c′,0), (c′, f(c′)), (c, f(c)), (c, 0)])
|
||||
|
||||
|
||||
|
||||
# where we lay our scene:
|
||||
scene, layout = layoutscene()
|
||||
layout.halign = :left
|
||||
layout.valign = :top
|
||||
|
||||
p = layout[0,0] = LScene(scene)
|
||||
|
||||
colsize!(layout, 1, Auto(1))
|
||||
rowsize!(layout, 1, Auto(1))
|
||||
|
||||
label = layout[end, 1] = LText(scene, "Area = $area")
|
||||
layout[end+1,1] = LText(scene, chomp(descr))
|
||||
|
||||
polycolor = lift(points) do pts
|
||||
c′ = pts[1][1]
|
||||
c = pts[3][1]
|
||||
area = round(abs(c - c′)*f(c), digits=4)
|
||||
|
||||
lbl = "Area = $area"
|
||||
label.text[] = lbl
|
||||
|
||||
if abs(area - Answer) <= 1e-4
|
||||
:green
|
||||
else
|
||||
:gray75
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
lines!(p.scene, a..b, f, strokecolor=:red, strokewidth=15)
|
||||
lines!(p.scene, a..b, zero, strokecolor=:black, strokewidth=10)
|
||||
poly!(p.scene, points, color = polycolor)
|
||||
scatter!(p.scene, points, color = :white, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
|
||||
xlims!(p.scene, (a, b))
|
||||
|
||||
|
||||
add_move!(p.scene, points, p.scene[end])
|
||||
|
||||
|
||||
|
||||
|
||||
scene
|
||||
142
CwJ/makie-demos/integration.jl
Normal file
142
CwJ/makie-demos/integration.jl
Normal file
@@ -0,0 +1,142 @@
|
||||
using AbstractPlotting
|
||||
using AbstractPlotting.MakieLayout
|
||||
using GLMakie
|
||||
|
||||
using QuadGK
|
||||
|
||||
function riemann(f::Function, a::Real, b::Real, n::Int; method="right")
|
||||
if method == "right"
|
||||
meth = f -> (lr -> begin l,r = lr; f(r) * (r-l) end)
|
||||
elseif method == "left"
|
||||
meth = f -> (lr -> begin l,r = lr; f(l) * (r-l) end)
|
||||
elseif method == "trapezoid"
|
||||
meth = f -> (lr -> begin l,r = lr; (1/2) * (f(l) + f(r)) * (r-l) end)
|
||||
elseif method == "simpsons"
|
||||
meth = f -> (lr -> begin l,r=lr; (1/6) * (f(l) + 4*(f((l+r)/2)) + f(r)) * (r-l) end)
|
||||
end
|
||||
|
||||
xs = a .+ (0:n) * (b-a)/n
|
||||
|
||||
sum(meth(f), zip(xs[1:end-1], xs[2:end]))
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
integration(f)
|
||||
|
||||
Show graphically the left Riemann approximation, the trapezoid approximation, and Simpson's approximation to the integral of `f` over [-1,1].
|
||||
|
||||
Assumes `f` is non-negative.
|
||||
"""
|
||||
function integration(f=nothing)
|
||||
if f == nothing
|
||||
f = x -> x^2*exp(-x/3)
|
||||
end
|
||||
|
||||
a, b = -1, 1
|
||||
|
||||
|
||||
function left_riemann_pts(n)
|
||||
xs = range(a, b, length=n+1)
|
||||
pts = Point2f0[(xs[1], 0)]
|
||||
for i in 1:n
|
||||
xᵢ, xᵢ₊₁ = xs[i], xs[i+1]
|
||||
fᵢ = f(xᵢ)
|
||||
push!(pts, (xᵢ, fᵢ))
|
||||
push!(pts, (xᵢ₊₁, fᵢ))
|
||||
end
|
||||
push!(pts, (xs[end], 0))
|
||||
pts
|
||||
end
|
||||
|
||||
|
||||
function trapezoid_pts(n)
|
||||
xs = range(a, b, length=n+1)
|
||||
pts = Point2f0[(xs[1], 0)]
|
||||
for i in 1:n
|
||||
xᵢ, xᵢ₊₁ = xs[i], xs[i+1]
|
||||
fᵢ = f(xᵢ)
|
||||
push!(pts, (xᵢ, f(xᵢ)))
|
||||
end
|
||||
push!(pts, (xs[end], f(xs[end])))
|
||||
push!(pts, (xs[end], 0))
|
||||
pts
|
||||
end
|
||||
|
||||
function simpsons_pts(n)
|
||||
xs = range(a, b, length=n+1)
|
||||
pts = Point2f0[(xs[1], 0), (xs[1], f(xs[1]))]
|
||||
|
||||
for i in 1:n
|
||||
xi, xi1 = xs[i], xs[i+1]
|
||||
m = xi/2 + xi1/2
|
||||
p = x -> f(xi)*(x-m)*(x - xi1)/(xi-m)/(xi-xi1) + f(m) * (x-xi)*(x-xi1)/(m-xi)/(m-xi1) + f(xi1) * (x-xi)*(x-m) / (xi1-xi) / (xi1-m)
|
||||
|
||||
xs′ = range(xi, xi1, length=10)
|
||||
for j in 2:10
|
||||
x = xs′[j]
|
||||
push!(pts, (x, p(x)))
|
||||
end
|
||||
end
|
||||
push!(pts, (xs[end], 0))
|
||||
pts
|
||||
end
|
||||
|
||||
|
||||
# where we lay our scene:
|
||||
scene, layout = layoutscene()
|
||||
layout.halign = :left
|
||||
layout.valign = :top
|
||||
|
||||
|
||||
p1 = layout[1,1] = LScene(scene)
|
||||
p2 = layout[1,2] = LScene(scene)
|
||||
p3 = layout[1,3] = LScene(scene)
|
||||
|
||||
n = layout[2,1] = LSlider(scene, range=2:25, startvalue=2)
|
||||
output = layout[2, 2:3] = LText(scene, "...")
|
||||
|
||||
lpts = lift(n.value) do n
|
||||
left_riemann_pts(n)
|
||||
end
|
||||
|
||||
poly!(p1.scene, lpts, color=:gray75)
|
||||
lines!(p1.scene, a..b, f, color=:black, strokewidth=10)
|
||||
title(p1.scene, "Left Riemann")
|
||||
|
||||
|
||||
tpts = lift(n.value) do n
|
||||
trapezoid_pts(n)
|
||||
end
|
||||
poly!(p2.scene, tpts, color=:gray75)
|
||||
lines!(p2.scene, a..b, f, color=:black, strokewidth=10)
|
||||
title(p2.scene, "Trapezoid")
|
||||
|
||||
spts = lift(n.value) do n
|
||||
simpsons_pts(n)
|
||||
end
|
||||
poly!(p3.scene, spts, color=:gray75)
|
||||
lines!(p3.scene, a..b, f, color=:black, strokewidth=10)
|
||||
title(p3.scene, "Simpson's")
|
||||
|
||||
on(n.value) do n
|
||||
actual,err = quadgk(f, -1, 1)
|
||||
lrr = riemann(f, -1, 1, n, method="left")
|
||||
trap = riemann(f, -1, 1, n, method="trapezoid")
|
||||
simp = riemann(f, -1, 1, n, method="simpsons")
|
||||
|
||||
Δleft = round(abs(lrr - actual), digits=8)
|
||||
Δtrap = round(abs(trap - actual), digits=8)
|
||||
Δsimp = round(abs(simp - actual), digits=8)
|
||||
|
||||
txt = "Riemann: $Δleft, Trapezoid: $Δtrap, Simpson's: $Δsimp"
|
||||
output.text[] = txt
|
||||
end
|
||||
n.value[] = n.value[]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
scene
|
||||
end
|
||||
151
CwJ/makie-demos/optimization.jl
Normal file
151
CwJ/makie-demos/optimization.jl
Normal file
@@ -0,0 +1,151 @@
|
||||
using AbstractPlotting
|
||||
using AbstractPlotting.MakieLayout
|
||||
using GLMakie
|
||||
|
||||
using LinearAlgebra
|
||||
using Roots
|
||||
using ForwardDiff
|
||||
D(f) = x -> ForwardDiff.derivative(f, float(x))
|
||||
|
||||
descr = """
|
||||
An old optimization problem is to find the shortest distance between two
|
||||
points when the rate of travel differs due to some medium (darker means slower).
|
||||
In this example, the relative rate can be adjusted (with the slider), and the
|
||||
various points (by clicking on and dragging a point). From there, the
|
||||
user can adjust the crossing point to identify the time.
|
||||
"""
|
||||
|
||||
## 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[]))
|
||||
|
||||
# very wierd, but we work with components
|
||||
# not vector
|
||||
z = zero(eltype(pos))
|
||||
x,y = pos
|
||||
|
||||
ptidx = idx[]
|
||||
|
||||
x = clamp(x, 0, 5)
|
||||
|
||||
if ptidx == 1
|
||||
y = clamp(y, z, 5)
|
||||
elseif ptidx == 2
|
||||
y = z
|
||||
elseif ptidx == 3
|
||||
y = clamp(y, -5, z)
|
||||
end
|
||||
|
||||
points[][idx[]] = [x,y]
|
||||
points[] = points[]
|
||||
end
|
||||
else
|
||||
dragstart[] = false
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
upperpoints = Point2f0[(0,0), (5, 0), (5, 5), (0,5)]
|
||||
lowerpoints = (Point2f0[(0,0), (5, 0), (5, -5), (0,-5)])
|
||||
|
||||
points = Node(Point2f0[(1, 4), (3, 0), (4,-4.0)])
|
||||
|
||||
# where we lay our scene:
|
||||
scene, layout = layoutscene()
|
||||
layout.halign = :left
|
||||
layout.valign = :top
|
||||
|
||||
|
||||
p = layout[1:3, 1] = LScene(scene)
|
||||
rowsize!(layout, 1, Auto(1))
|
||||
colsize!(layout, 1, Auto(1))
|
||||
|
||||
|
||||
flayout = GridLayout()
|
||||
layout[1,2] = flayout
|
||||
|
||||
flayout[1,1] = LText(scene, chomp(descr))
|
||||
|
||||
details = flayout[2, 1] = LText(scene, "...")
|
||||
|
||||
λᵣ = flayout[3,1] = LText(scene, "λ = v₁/v₂ = 1")
|
||||
λ = flayout[4,1] = LSlider(scene, range = -3:0.2:3, startvalue = 0.0)
|
||||
|
||||
|
||||
|
||||
|
||||
tm = lift(λ.value, points) do λ, pts
|
||||
x0,y0 = pts[1]
|
||||
x, y = pts[2]
|
||||
x1, y1 = pts[3]
|
||||
|
||||
v1 = 1
|
||||
v2 = v1/2.0^λ
|
||||
|
||||
t(x) = sqrt((x-x0)^2 + y0^2)/v1 + sqrt((x1-x)^2 + y1^2)/v2
|
||||
val = t(x)
|
||||
|
||||
details.text[] = "Time: $(round(val, digits=2)) units"
|
||||
|
||||
val
|
||||
|
||||
end
|
||||
|
||||
a = lift(λ.value, points) do λ, pts
|
||||
x0,y0 = pts[1]
|
||||
x1, y1 = pts[3]
|
||||
v1 = 1
|
||||
v2 = v1/2.0^λ
|
||||
|
||||
t(x) = sqrt((x-x0)^2 + y0^2)/v1 + sqrt((x1-x)^2 + y1^2)/v2
|
||||
x′ = fzero(D(t), x0, x1)
|
||||
t(x′)
|
||||
end
|
||||
|
||||
λcolor = lift(λ.value) do val
|
||||
# val = v1/v2 ∈ [1/8, 8]
|
||||
n = floor(Int, 50 - val/3 * 25)
|
||||
Symbol("gray" * string(n))
|
||||
end
|
||||
|
||||
linecolor = lift(a) do val
|
||||
abs(val - tm[]) <= 1e-2 ? :green : :white
|
||||
end
|
||||
|
||||
|
||||
on(λ.value) do val
|
||||
v = round(2.0^(val), digits=2)
|
||||
txt = "λ = v₁/v₂ = $v"
|
||||
λᵣ.text[] = txt
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
poly!(p.scene, upperpoints, color = :gray50) # neutral color
|
||||
poly!(p.scene, lowerpoints, color = λcolor) # color depends on λ
|
||||
|
||||
lines!(p.scene, Point2f0[(0,0), (5, 0)], color=:black, strokewidth=5, strokecolor=:black, raw=true)
|
||||
lines!(p.scene, points, color = linecolor, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
|
||||
scatter!(p.scene, points, color = linecolor, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
|
||||
xlims!(p.scene, (0,5))
|
||||
ylims!(p.scene, (-5,5))
|
||||
|
||||
add_move!(p.scene, points, p.scene[end])
|
||||
|
||||
|
||||
|
||||
scene
|
||||
|
||||
49
CwJ/makie-demos/spirograph.jl
Normal file
49
CwJ/makie-demos/spirograph.jl
Normal file
@@ -0,0 +1,49 @@
|
||||
using AbstractPlotting
|
||||
using AbstractPlotting.MakieLayout
|
||||
using GLMakie
|
||||
|
||||
# GUI for spirograph
|
||||
# https://en.wikipedia.org/wiki/Spirograph
|
||||
|
||||
function x(t; R=1, k=1/4, l=1/4)
|
||||
R*[(1-k)*cos(t) + l*k*cos((1-k)/k*t), (1-k)*sin(t) - l*k*sin((1-k)/k*t)]
|
||||
end
|
||||
|
||||
# where we lay our scene:
|
||||
scene, layout = layoutscene()
|
||||
|
||||
flyt = GridLayout()
|
||||
flyt.halign[] = :left # fails?
|
||||
flyt.valign[] = :top
|
||||
|
||||
layout[1,1] = flyt
|
||||
p = layout[1,2] = LAxis(scene)
|
||||
rowsize!(layout, 1, Relative(1))
|
||||
colsize!(layout, 2, Relative(2/3))
|
||||
|
||||
flyt[1,1] = LText(scene, "t")
|
||||
ts = flyt[1,2] = LSlider(scene, range = 2pi:pi/8:40pi)
|
||||
|
||||
flyt[2, 1] = LText(scene, "k = r/R")
|
||||
k = flyt[2,2] = LSlider(scene, range = 0.01:0.01:1.0, startvalue=1/4)
|
||||
|
||||
flyt[3,1] = LText(scene, "l=ρ/r")
|
||||
l = flyt[3,2] = LSlider(scene, range = 0.01:0.01:1.0, startvalue=1/4)
|
||||
|
||||
|
||||
data = lift(ts.value, k.value, l.value) do ts,k,l
|
||||
|
||||
ts′ = range(0, ts, length=1000)
|
||||
xys = Point2f0.(x.(ts′, R=1, k=k, l=l))
|
||||
|
||||
end
|
||||
|
||||
lines!(p, data)
|
||||
xlims!(p, (-1, 1))
|
||||
ylims!(p, (-1, 1))
|
||||
|
||||
|
||||
|
||||
|
||||
scene
|
||||
|
||||
102
CwJ/makie-demos/tangent-line.jl
Normal file
102
CwJ/makie-demos/tangent-line.jl
Normal file
@@ -0,0 +1,102 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user