I've been trying to make an animation of the Lorenz Attractor
being plotted using matplotlib
. I already have a successful static plot and now I am trying to animate it. I have been going off the documentation for matplotlib animation to do so but, whenever I go to run my program I get an empty box no animation, I am also using spyder ide's
plots but, I also ran it in a terminal.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
x_values = np.array([])
y_values = np.array([])
z_values = np.array([])
#^Lorenz Attractor coordinates size = 1000
fig = plt.figure(facecolor="black")
ax = fig.add_subplot(projection='3d')
ln, = ax.plot([], [], [])
#^Plot configuration.
Above is the where I make most of my variables. x-z_values is where the points for the Lorenz Attractor
points are stored
def init():
return ln,
#initializer for animation function
def update(i):
ln.set_data(x_values[i], y_values[i], z_values[i])
return ln,
#Adds next values of Lorenz Attractor to ln which will be returned to animation to be plotteed
Lorenz()
#Calls the Lorenz function to populate the arrays.
ani = FuncAnimation(fig,
update,
frames = np.arange(0, len(x_values)),
init_func = init,
interval=200,
)
plt.show()
This is where the animation is supposed to take place.
And this is what I get after running the program.
I've changed some code I am no longer using ln to collect the coordinate values, so the line below for example has been removed
ln.set_data(x_values[i], y_values[i], z_values[i])
Below is the new code including the new update function that uses the values from a separate function named Lorenz()
, the variables which are globally available. The print()
debugging suggested by Furas has validated that update()
is working as expected. The only problem left to solve is the actual animation.
`
def init():
ax.set_xlim(-100, 100)
ax.set_ylim(-100, 100)
ax.set_zlim(-100, 100)
#initializer for animation function
def update(i):
global x_values
global y_values
global z_values
#Globally available variables that are poulated by Lorenz()
print(x_values[i], y_values[i], z_values[i])
#Print debugging
return(x_values[:i], y_values[:i], z_values[:i])
#Adds next values of Lorenz Attractor to ln which will be returned to animation to be plotteed
Lorenz()
ani = FuncAnimation(fig,
update,
frames = np.arange(0, len(x_values)),
init_func=init,
interval=1,
blit=False,
repeat = False)
plt.show()
`
I never made animation for 3D
but based on example Animated 3D random walk in Matplotlib
documentation you need:
def update(i):
ln.set_data( [x_values[:i], y_values[:i]] ) # set [x, y]
ln.set_3d_properties( z_values[:i] ) # set z
return ln,
Full working code with example data:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
# --- functions ---
def Lorenz():
x = np.zeros(100)
y = np.zeros(100)
z = np.zeros(100)
for i in range(100):
x[i] = i/100
y[i] = i/100
z[i] = i/100
return x, y, z
def init():
return ln,
def update(i):
ln.set_data([ x_values[:i], y_values[:i]])
ln.set_3d_properties( z_values[:i] )
return ln,
# --- main ---
fig = plt.figure(facecolor="black")
ax = fig.add_subplot(projection='3d')
ln, = ax.plot([], [], [])
x_values, y_values, z_values = Lorenz()
ani = FuncAnimation(fig,
update,
frames=len(x_values), # you don't need range (if you don't want to skip some frames)
init_func=init,
interval=20, # make animation faster
)
plt.show()