-1

In the following Python code, I am trying to make an animation of a 2 rotating vectors around the origin. I am using matplotlib 3.2.1 and Python 3.8.2 on Ubuntu 20.04.


import numpy as np
import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation


r = 2.0

def circle(phi):
    return np.array([r*np.cos(phi), r*np.sin(phi)])

fig, ax = plt.subplots(figsize=(10,6))
ax.axis([-3.5*r,3.5*r,-2.5*r,2.5*r])
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

# set equal aspect
ax.set_aspect("equal")

point, = ax.plot(0, r, marker="o")


traj = plt.Circle((0,0), r, fill=False, color='black')
ax.add_artist(traj) # draw the circular trajectory

def update(phi):

    x, y = circle(phi)
    point.set_data([x], [y])
    er_vec = np.array([0.5*x, 0.5*y])
    eθ_vec = np.array([-0.5*y, 0.5*x])


    er_arr = plt.arrow(x, y, dx=er_vec[0], dy=er_vec[1], head_width=0.1, head_length=0.2, color='gray')
    eθ_arr = plt.arrow(x, y, dx=eθ_vec[0], dy=eθ_vec[1], head_width=0.1, head_length=0.2, color='grey')

    annot_er = plt.text(1.7*x, 1.7*y, r'$\mathbf{e}_r$', fontsize=11)
    annot_eθ = plt.text(1.1*(x-0.5*y), 1.1*(y+0.5*x), r'$\mathbf{e}_\theta$', fontsize=11) 

    ax.add_artist(er_arr)    
    ax.add_artist(eθ_arr)
    ax.add_artist(annot_er)
    ax.add_artist(annot_eθ)
    return point, er_arr, eθ_arr, annot_er, annot_eθ

anim = FuncAnimation(fig, update, interval=10, blit=True, repeat=False, frames=np.linspace(0, 2.0*np.pi, 360, endpoint=False))
plt.show()

The code above runs smoothly and without any issues. This is a screenshot of the animation:

enter image description here

However, when I try to save the animation to an mp4 video:

anim.save('anim-issue.mp4', writer='ffmpeg')

the animation in the video appears with traces which, something like this screenshot:

enter image description here

Could someone help me fix that issue with the video animation?

I appreciate your help.

Edit 1: According to this answer this is due to blit=True. But that doesn't solve the issue here, since the arrows have no set_position method.

Edit 2: I found another related question with the same issue I described above but I don't know how to adapt my code to make it work as expected in both cases (plt.show, anim.save).

  • Have you tried to save it with `blit=False` to see if that is the culprit? – Diziet Asahi May 25 '20 at 08:06
  • @DizietAsahi: Yes, I have already updated my question, the problem is with the `blitting`. But I wonder how to solve that. –  May 25 '20 at 08:07

1 Answers1

0

Updating the position of an arrow would be quite tricky. The easiest solution is indeed to create new arrows at each frame, but you have to make sure you remove the previous arrows first

full code:

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation


r = 2.0

def circle(phi):
    return np.array([r*np.cos(phi), r*np.sin(phi)])

fig, ax = plt.subplots(figsize=(10,6))
ax.axis([-3.5*r,3.5*r,-2.5*r,2.5*r])
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

# set equal aspect
ax.set_aspect("equal")

point, = ax.plot(0, r, marker="o")
traj = plt.Circle((0,0), r, fill=False, color='black')
ax.add_artist(traj) # draw the circular trajectory
er_arr = None
eθ_arr = None
annot_er = None
annot_eθ = None


def init():
    global er_arr, eθ_arr, annot_er, annot_eθ
    x,y = 0,0
    er_vec = np.array([0.5*x, 0.5*y])
    eθ_vec = np.array([-0.5*y, 0.5*x])
    er_arr = plt.arrow(x, y, dx=er_vec[0], dy=er_vec[1], head_width=0.1, head_length=0.2, color='gray')
    eθ_arr = plt.arrow(x, y, dx=eθ_vec[0], dy=eθ_vec[1], head_width=0.1, head_length=0.2, color='grey')
    annot_er = plt.text(1.7*x, 1.7*y, r'$\mathbf{e}_r$', fontsize=11)
    annot_eθ = plt.text(1.1*(x-0.5*y), 1.1*(y+0.5*x), r'$\mathbf{e}_\theta$', fontsize=11)
    return er_arr, eθ_arr, annot_er, annot_eθ


def update(phi):
    global er_arr, eθ_arr, annot_er, annot_eθ

    x, y = circle(phi)
    point.set_data([x], [y])
    er_vec = np.array([0.5*x, 0.5*y])
    eθ_vec = np.array([-0.5*y, 0.5*x])

    #remove previous artists
    er_arr.remove()
    eθ_arr.remove()

    er_arr = plt.arrow(x, y, dx=er_vec[0], dy=er_vec[1], head_width=0.1, head_length=0.2, color='gray')
    eθ_arr = plt.arrow(x, y, dx=eθ_vec[0], dy=eθ_vec[1], head_width=0.1, head_length=0.2, color='grey')

    annot_er.set_position((1.7*x, 1.7*y))
    annot_eθ.set_position((1.1*(x-0.5*y), 1.1*(y+0.5*x)))

    return point, er_arr, eθ_arr, annot_er, annot_eθ

anim = FuncAnimation(fig, update, init_func=init, interval=10, blit=True, repeat=False, frames=np.linspace(0, 2.0*np.pi, 360, endpoint=False))
plt.show()

enter image description here

Diziet Asahi
  • 38,379
  • 7
  • 60
  • 75