I am trying to make an animation with a circle moving in a 3D plot using Matplotlib and FuncAnimation(). Everything works except that I do not find a way to remove the circle already plotted in the previous frame. This leads to the formation of a cylinder as all circles plotted overlap. I only want to plot and see the circle in the current frame. This is the code that I wrote:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.patches import Circle
fig = plt.figure(figsize = (8, 8))
ax = fig.add_subplot(projection="3d")
ax.set_xlabel('X(t)')
ax.set_ylabel('Y(t)')
ax.set_zlabel('Z(t)')
x_min = -100.
x_max = 100.
y_min = -100.
y_max = 100.
z_min = -100.
z_max = 100.
ax.set_xlim3d([x_min, x_max])
ax.set_ylim3d([y_min, y_max])
ax.set_zlim3d([z_min, z_max])
x = 0.
y = 0.
# Center of the circle
center = (x, y)
# Values of z along which the circle will move
z = np.arange(0, 100, 1.)
# Initialize the circle in the 3D plot
def init():
circle = Circle(xy = center, radius = 20., color = "coral")
ax.add_patch(circle)
art3d.pathpatch_2d_to_3d(circle, z = z[0], zdir="z")
return circle
# Animation that changes the z value
def animate(iframe):
circle = Circle(xy = center, radius = 20., color = "coral")
ax.add_patch(circle)
art3d.pathpatch_2d_to_3d(circle, z = z[iframe], zdir="z")
return circle
anim = animation.FuncAnimation(fig, animate, init_func = init, frames=len(z), interval=100, blit=False, repeat = False)
Any idea how to solve this? Thanks.
Update: It works if at the end of animate() one adds:
plt.pause(0.1)
circle.remove()
However, it does not work if plt.pause() is not used. It just does nothing, it does not plot any circle.
You could use ax.patches.pop()
at the beginning of your animate
function to remove the previous circle (see here).
Adapted to your code, this would give:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.patches import Circle
fig = plt.figure(figsize = (8, 8))
ax = fig.add_subplot(projection="3d")
ax.set_xlabel('X(t)')
ax.set_ylabel('Y(t)')
ax.set_zlabel('Z(t)')
x_min = -100.
x_max = 100.
y_min = -100.
y_max = 100.
z_min = -100.
z_max = 100.
ax.set_xlim3d([x_min, x_max])
ax.set_ylim3d([y_min, y_max])
ax.set_zlim3d([z_min, z_max])
x = 0.
y = 0.
# Center of the circle
center = (x, y)
# Values of z along which the circle will move
z = np.arange(0, 100, 1.)
circle = Circle(xy = center, radius = 0., color = "coral") #Create empty circle that acts as a placeholder
ax.add_patch(circle)
art3d.pathpatch_2d_to_3d(circle, z = z[0], zdir="z")
# Animation that changes the z value
def animate(iframe):
ax.patches.pop() #remove previous circle
circle = Circle(xy = center, radius = 20., color = "coral")
ax.add_patch(circle)
art3d.pathpatch_2d_to_3d(circle, z = z[iframe], zdir="z")
return circle
anim = animation.FuncAnimation(fig, animate,frames=len(z), interval=100, blit=False, repeat = False)