# 3d animation plot of 2 ode solutions

Hi, I’m very new to Julia and the plots package. I’d like to plot 2 ode solutions within the same gif. For example, say I’m solving the lorenz function and want to plot two solutions with different parameters in the same animation.

``````#lorenz solver
function simulate(params)

function lorenz(du, u, p, t)
du = p*(u-u)
du = u*(p-u) - u
du = u*u - p*u
end

u0 = [1.; 5.; 10.]
tspan = (0, 100)
p = params
prob = ODEProblem(lorenz, u0, tspan, p)
sol = solve(prob)
return sol
end

#two different solutions
sol1 = simulate([10; 28; 8/3])
sol2 = simulate([5;32;10])

#animate
n = length(sol1.t)
plt = plot3d(1, xaxis = ("x" ,(-30, 30)), yaxis = ("y", (-30,30)), zaxis=("z", (0, 60)))
anim = @animate for i in 1:n
push!(plt, sol1[1,i], sol1[2,i], sol1[3,i])
end

gif(anim, "myGif.gif")
``````

I can’t seem to figure out an elegant way to allow both solutions to be in the same gif. Please let me know of any ideas! Thank you in advance

This is what I typically do.

``````nframes = 300
anim = @animate for t in LinRange(first(sol1.t), last(sol1.t), nframes)
plot(sol1, vars = (1,2,3), tspan = (0.0, t), lab = "Solution 1")
plot!(sol2, vars = (1,2,3), tspan = (0.0, t), lab = "Solution 2")

#current time marker
scatter!(sol1, vars = (1,2,3), tspan = (t, t), lab = nothing, color = 1)
scatter!(sol2, vars = (1,2,3), tspan = (t, t), lab = nothing, color = 2)

# axis setting... need to be last b/c DiffEq recipes will overwrite.
plot!(xaxis = ("x" ,(-30, 30)), yaxis = ("y", (-30,30)), zaxis=("z", (0, 60)),
title = "t = \$(round(t, digits = 2))")
end

gif(anim, "myGif.gif"; fps = 30)
``````

A couple things of note

• Inside each @animate loop you need to create a new figure, not push to an existing one. Each loop will be a frame.
• I am using a plot recipe for DiffEq. see Plot Functions · DifferentialEquations.jl
• `vars = (1,2,3)` indicates to make a 3D plot of the states, 1,2,and 3. You use “0” for time. So, if you just wanted a 2D plot of x vs t you use `vars = (0, 1)`
• `tspan = (0,t)` will interpolate the solution only in that time horizon. Because `t` is our loop variable it keeps growing
• I also show using this for adding a scatter pt for the current time for the frame. Note how I used `tspan = (t,t)` so only plotting for that time.
• Plot color can be specified various ways, by giving a number as `color = 1`, you specify the first in the cycle of colors. So, here I ensure the scatter colors match the other plots
• Note that the DiffEq plot recipes will overwrite things like `xaxis`, so I specify them last.
• Plotting functions appended with `!` will add a new series to the previous plot.
• The `fps = 30` kwarg in `gif` specifies the frames / s

A big advantage of this approach is the each frame will be linearly spaced in time. Depending on the integrator you use, variable time steps may be used. So, by indexing directly in the solution like you were, the animation may not look smooth in time depending on the system and integrator.

3 Likes

My pleasure. Welcome to the Julia community.

As a bonus answer, here is how to do it with subplots

``````anim = @animate for t in LinRange(first(sol1.t), last(sol1.t), nframes)
plt1 = plot(sol1, vars = (1,2,3), tspan = (0.0, t), title = "Solution 1", lab = false)
scatter!(sol1, vars = (1,2,3), tspan = (t, t), lab = nothing)

plt2 = plot(sol2, vars = (1,2,3), tspan = (0.0, t), title = "Solution 2", lab = false)
scatter!(sol2, vars = (1,2,3), tspan = (t, t), lab = nothing)

# combine into a single plot of layout 1 row 2 colums
plot(plt1, plt2, layout = (1,2),
xaxis = ("x" ,(-30, 30)), yaxis = ("y", (-30,30)), zaxis=("z", (0, 60)),
plot_title = "t = \$(round(t, digits = 2))")
end
``````

The key difference here is I create two figures with `plot()` vs a single `plot()` and `plot!()` is the previous example. I then combine them into a new plot with `plot(plt1, plt2, ...)` The `layout` kwarg specifies the number of rows/colums. Any setting like `xaxis` passed in this call will get assigned to all of the subplots. Note the usage of `plot_title` vs `title`. If I used `title`, it would have those titles for each subplot vs, as a “supertitle” for the entire figure.

1 Like

Great! Thank you so much for the welcome and the very thorough explanation