Matplotlib:通过跟踪保存的动画

问题描述 投票:0回答:1

[在下面的Python代码中,我试图制作一个围绕原点旋转2个向量的动画。我在Ubuntu 20.04上使用matplotlib 3.2.1和Python 3.8.2。


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()

上面的代码运行流畅,没有任何问题。这是动画的屏幕截图:

enter image description here

但是,当我尝试将动画保存到mp4视频中时:

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

视频中的动画带有痕迹,类似于此屏幕截图:

enter image description here

有人可以帮我解决视频动画的问题吗?

感谢您的帮助。

编辑1:根据this answer,这归因于blit=True。但这并不能解决问题,因为箭头没有set_position方法。

Edit 2:我发现了另一个related question,具有与上述相同的问题,但我不知道如何修改我的代码以使其在两种情况下均能正常工作(plt.showanim.save )。

python-3.x matplotlib animation ffmpeg
1个回答
0
投票

更新箭头的位置非常棘手。最简单的解决方案的确是在每个帧上创建新箭头,但是必须确保先删除先前的箭头

完整代码:

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

© www.soinside.com 2019 - 2024. All rights reserved.