Combine a "plot" object with a "scatter" object in an animation

I’m creating an animation by combining multiple scatter plots (using Animation() and frame()). It all works fine. But I would like my scatter plots to be overlaid on a plot that shows the trajectories I expect the particles to follow. That plot could be done before the loop that creates the frames.

But I don’t know how to overlay a scatter on top of a plot. I don’t think scatter! is the way to go because each frame needs to be a new scatter plot. That is, I don’t want the particle positions to accumulate, but to be updated in each frame.

Here is a MWE. The particle will follow a parabolic trajectory. I want to plot that parabola underneath the particle.

using Plots
x = [-1. -1. -1.] #Starting positions
δt = 0.01
anim = Animation()
tEnd = π; t = 0;
vb = [-1,+1];

while t < tEnd
    x[3] = 2x[2] - x[1] -x[2]*δt^2 #Verlet step
    # Make plot for anim fram
    scatter([x[2]] ,[V(x[2])],xlim=vb,ylim=vb,legend=:none
      ,markersize=3,frame=:box,dpi=150,aspectratio=1,markerstrokecolor="blue",
      markercolor="blue")
    # update position vector
    x[2],x[1] = x[3],x[2]
    t += δt # advance simulation time
    frame(anim)
end

I don’t know how to do that using Plots, but here’s an example using Gaston and gnuplot. I couldn’t reproduce your code exactly because I don’t know what V(x) is, but my example should be easy to adapt.

using Gaston
x = -5:0.1:5;
y = sin.(π*x);
F = plot(x, y, lc = :black);  # we need one first plot
for (idx, xx) in enumerate(x)
    # plot "trajectory"
    P = plot(x, y, lc = :black, handle = 2);
    # plot "particle"
    plot!([xx], [y[idx]], w = :points,
          marker = "fcircle", markersize = 3,
          lc = :blue, handle = 2);
    push!(F, P)  # add new frame to first plot
end
# save as gif
save(term = "gif",
     saveopts = "animate size 600,400 delay 1",
     output = "anim.gif", handle = 1)

anim

2 Likes

I can’t test this right now, but try deepcopying the trajectory plot for each frame and then use scatter! on the copy.

The really simple solution is just to plot the trajectory fresh in each loop. Thanks @mbaz.

using Plots
function V(x)
    return x^2
end    
tx = -1:0.02:+1
x = [-1. -1. -1.] #Starting positions
δt = 0.05
anim = Animation()
tEnd = 2π; t = 0; 
vb = [-1,+1];

 while t < tEnd
   x[3] = 2x[2] - x[1] -x[2]*δt^2
   plot(tx,V.(tx),legend=:none)
   scatter!([x[2]] ,[V(x[2])],xlim=vb,ylim=vb,legend=:none,ticks=:false
       ,markersize=3,frame=:box,dpi=150,aspectratio=1,markerstrokecolor="blue",
       markercolor="blue")
   x[2],x[1] = x[3],x[2]
   t += δt
   frame(anim)
end
gif(anim)
1 Like