Interactive Differential Equation


using OrdinaryDiffEq, ParameterizedFunctions
import AbstractPlotting: textslider

using Makie

lorenz = @ode_def Lorenz begin           # define the system
    dx = σ * (y - x)
    dy = x * (ρ - z) - y
    dz = x * y - β*z
end σ ρ β

u0 = [1.0,0.0,0.0]                       # initial conditions
tspan0 = (0.0,100.0)                      # initial timespan
p0 = [10.0,28.0,8/3]                      # initial parameters
prob = ODEProblem(lorenz, u0, tspan0, p0)  # define the problem

## setup sliders and plotting

"The order of magnitude to range between."
OME = 8

,  = textslider(exp10.(-OME:0.001:OME), "σ", start = p0[1]);

,  = textslider(exp10.(-OME:0.001:OME), "ρ", start = p0[2]);

,  = textslider(exp10.(-OME:0.001:OME), "β", start = p0[3]);

st, ot = textslider(exp10.(-OME:0.001:OME), "tₘₐₓ", start = tspan0[end]);

sr, or = textslider(100:10000, "resolution", start = 2000);

trange = lift(ot, or) do tmax, resolution
    LinRange(0.0, tmax, resolution)
end

data = lift(, , , trange) do σ, ρ, β, ts
    Point3f0.(
        solve(
            remake(
                prob;
                p = [σ, ρ, β],
                tspan = (ts[1], ts[end])
            ),
            Tsit5(),
        )(ts).u
    )  # change to fit the dimensionality - maybe even return 2 arrays, or a set of `Point2`s...
end
parent = Scene(resolution = (1000, 500))

three = lines(
    data, linewidth = 2,
    transparency = true, color = ("#fe4a49", 0.4),
    show_axis = false
)

scatter!(
    three, data, markersize = 0.3, color = (:white, 0.3),
    strokecolor = :black, strokewidth = 1
)
on(data) do x
    # center camera etc
    update!(three)
end
scene = vbox(hbox(, , , st, sr), three, parent = parent)

RecordEvents(scene, "output")