Lorenz attractor with makie

I’m trying to reproduce the Lorenz attractor simulation from here:

feature (scroll to the third example)

and I feel like this should be easier or at least there should exist a better solution. In Gnuplot.jl we have the option of plot every #number of frames, so that things could be faster and smooth, I would like to see also that here in Makie. so far, this what I have, (How to get rid off most Nodes definitions and do everything in one call? )

``````using GLMakie, DifferentialEquations, ParameterizedFunctions
GLMakie.activate!()
let
g = @ode_def begin
dx = σ*(y - x)
dy = x*(ρ - z) - y
dz = x*y - β*z
end σ ρ β
u0 = [1.0; 0.0; 0.0]
tspan = (0.0, 30.0)
p = [10.0,28.0,8/3]
prob = ODEProblem(g, u0, tspan, p)
sol = solve(prob, Tsit5(), saveat = 0.01)
x, y, z = sol[1,:], sol[2,:], sol[3,:]
tempo = sol.t
xnodePt = Node([x[2]])
ynodePt = Node([y[2]])
znodePt = Node([z[2]])

# line
xnode = Node(x[1:2])
ynode = Node(y[1:2])
znode = Node(z[1:2])
tnode = Node(tempo[1:2])
# first frame (figure)
fig = Figure(resolution=(1000,600), fontsize = 20)
ax = Axis3(fig, aspect = (1,1,0.5), azimuth = -0.3π, elevation = π/9)
pltobj = lines!(ax, xnode, ynode, znode, color = tnode, overdraw = false,
colormap = :plasma)
scatter!(ax, xnodePt, ynodePt, znodePt, markersize = 15, color = :red)
cbar = Colorbar(fig, pltobj, label = "time", width = 15, ticksize=15,
tickalign = 1, height = Relative(0.5))
fig[1,1] = ax
fig[1,2] = cbar
# the animation is done by updating the nodes values
record(fig,joinpath(@__DIR__, "output", "animlorenzAttractor.mp4"), framerate = 24*8) do io
for i in 3:length(tempo)
push!(xnode[], x[i])
push!(ynode[], y[i])
push!(znode[], z[i])
tnode[] = tempo[1:i]
xnodePt[] = [x[i]]
ynodePt[] = [y[i]]
znodePt[] = [z[i]]
xnode[] = xnode[] # trigger all updates for the new frame, again?
autolimits!(ax)
recordframe!(io)  # record a new frame
end
end
end
``````

Bit like pseudocode:

``````all_points = Point3f0.(sol)
i = Node(1)
points = @lift(view(all_points, 1:\$i)))
scatterlines!(points)

record(...) do io
i[] += 1
recordframe!(io)
end
``````

The view is pretty neat
I guess as an alternative:

``````fig = Figure(resolution=(1000,600), fontsize = 20)
ax = Axis3(fig[1,1], aspect = (1,1,0.5), azimuth = -0.3π, elevation = π/9)
points = Observable(Point3f0[])
color = Observable(Float64[])
attr = (color=color, transparency=true, colormap=:plasma)
pltobj = lines!(ax, points; attr...)
scatter!(ax, points; markersize = 0.02, markerspace=SceneSpace, attr...)
cbar = Colorbar(fig[1,2], pltobj, label = "time", width = 15, ticksize=15, tickalign = 1, height = Relative(0.5))
# the animation is done by updating the nodes values
path = joinpath(@__DIR__, "animlorenzAttractor.mp4")
record(fig, path, enumerate(tempo), framerate = 24*8) do (i, t)
xyz = Point3f0(sol[:, i])
push!(points[], xyz)
push!(color[], t)
notify(points)
notify(color)
autolimits!(ax)
end
``````

In Gnuplot.jl we have the option of plot every #number of frames

You can just loop over the animation however you like, no?

2 Likes

BTW I have implemented trajectory animators in InteractiveDynamics.jl. This:

``````using InteractiveDynamics, DynamicalSystems, GLMakie

using OrdinaryDiffEq: Tsit5
ds = Systems.lorenz()

u0 = [10,10,10.0]
u0s =  [u0 .+ i*1e-3 for i in 1:3]

diffeq = (alg = Tsit5(), dtmax = 0.01)

figure, obs = interactive_evolution_timeseries(
ds, u0s; tail = 1000, diffeq, colors = to_color.(COLORSCHEME[1:3]),
linekwargs = (linewidth = 2.0,)
)
``````

will produce this: Trajectory Evolution · InteractiveDynamics

(can’t paste mp4 in discourse, but the animation is in the link)

The source code of the `interactive_evolution` is more convoluted than what you want though, because it is set up to run indefinitely.

3 Likes

Indeed, you loop over the animation. Also, I did not use CairoMakie because the lines overlap in the wrong order.