Makie - improving performance with animations?

I’m looking into animating results from a kinetic simulation using makie and got some basic animations going. Now I’m trying to improve about performance.
This script kinetic_anim.jl · GitHub animates the trajectories, of length 20,000, for 1,000 particles in the simulation mesh.

The final record loop runs at about 25 iterations per second on my laptop Corei5-8350U CPU @ 1.70GHz, and cpu utilization is at 60-70%, using only a single core. Does someone maybe have an idea how to increase performance here?

You could try to profile the recording to see where most time is spent.

Good idea, here is the trace: profile.txt · GitHub

Line 1363 of the trace tells me that a large fraction of backtraces are taken in 11613 @Observables/src/Observables.jl:86; setindex!(observable::Observable, val::Any)
Probably when the animation loop mutates all observables:

    for (idx, traj) in enumerate(traj_list)
       traj[] = push!(traj[], anim_step(t, idx))

Right now I define each particle as an independent observable, which leads me to 1,000 observables.
Is there maybe a smarter way of plotting the particle trajectories?

Oh yeah 1000 observables are rarely a good sign… You could try the series plot type, it is just a layer on top of lines but makes it easier to plot multiple lines in one call. It condenses the data down to just one array, which is most efficient in terms of interfacing with the GPU. You can also build such a vector yourself, though, it’s just a NaN separated list of points.

I’d assume you could get pretty good performance by:

  • make one arr = Vector{Point3f} of length 20,000 * 1,000 + 999 NaN points in between
  • make one obs = Observable(points)
  • plot that via lines!(ax_anim, obs)
  • when updating, mutate the original arr and update the points
  • then just notify(obs) to update the lines

Thanks, that gives me a much more performant skeleton to build my animation on.
Here is some basic code:

num_anim_step = 100
num_anim_ptl = 10
# Fill this array consecutively with particle values at different time-steps
# At the last time-step, a NaN separates the values of different particles
# For example when num_anim_step = 10:
# ptl1:  1...10
# ptl2: 12...21
# ptl3: 23...32
# etc.
arr = [CairoMakie.Point2f(NaN, NaN) for i in 1:(num_anim_ptl * (num_anim_step + 1))]
obs = Observable(arr)

f_anim, a_anim, p_anim = lines(arr)

record(f_anim, "test.mp4", 1:num_anim_step; framerate=1) do t
    for ptl in 1:num_anim_ptl
        # Replace the NaN in the array with particle trajectory up to current time step
        arr[(ptl - 1) * num_anim_step + t] = CairoMakie.Point2f(t, ptl + 0.1 * t)