在 matplotlib 中以交互方式更改动画参数

Changing animation parameters interactively in matplotlib

我需要制作一些相当简单的动画,但我确实还需要一个滑块来让用户以交互方式更改动画的参数。我希望它发生在网上;即,如果用户在播放动画时更改参数,则动画应从其旧动态平稳过渡到新动态。

到目前为止,我已经编写了一个接受参数并制作动画的函数。但它不是我之前提到的意义上的交互式。我的代码中没有滑块或任何真正交互的东西。不过动画部分至少运行流畅。

这是我的代码的简化版本:一个点围绕中心旋转,距中心的指定距离为 r,速度为 angular w。用户可以将它们作为参数来查看动画。 (如果您在代码中看到一些从未使用过的东西,请不要为它烦恼,这可能是因为我忘记 trim 它比原始代码长得多。)

import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def simplified_code(w,r):

    fps = 36
    M = int(.75*fps*2*np.pi/w) 
    T_final = 2*np.pi/w*16

    def positions(t):
        x = r*np.cos(w*t) 
        y = r*np.sin(w*t) 
        return x,y

    fig = plt.figure()
    ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, )
    ax.grid()

    # position
    x_e, y_e = [], []  

    # trajectory and center 
    traj_e, = plt.plot([],[],'-g',lw=1)
    e, = plt.plot([], [], 'ok')

    # time
    time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes)

    def init():
        ax.set_xlim(-(r+0.5), (r+0.5))
        ax.set_ylim(-(r+0.5), (r+0.5))    
        ax.plot([0], ms=7, c='k',marker='o')
        return d,e,traj_e


    def update(frame):

        x,y = positions(frame)

        x_e.append(x)
        y_e.append(y)

        traj_e.set_data(x_e[-M:], y_e[-M:])
        e.set_data(x, y)
        time_text.set_text('time = %.1f' % frame)

        return traj_d,traj_e,d,e, orb


    return FuncAnimation(fig, update, frames=np.linspace(0, T_final, T_final*fps),
                        init_func=init, blit=True, interval=1./36*1000)

请注意,可以停止动画,通过滑块更改参数并重新运行。我想在动画中避免这种 pause。如果有任何帮助,我将不胜感激。

感谢@ImportanceOfBeingErnest,我设法将动画的 update 功能与带有滑块的功能结合起来:

import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation 
from matplotlib.widgets import Slider

fig = plt.figure(figsize=(6,7))
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, position=[.15,.15,.75,.75] )
ax.grid()

w = 2
r = 1
fps = 36
M= 1024#
T_final = 256

x_e, y_e = [], []  
orb_x, orb_y = [], [] 

# trajectories
traj_e, = ax.plot(x_e,y_e,'-g',lw=1)

# center 
e, = ax.plot([], [], 'ok')

# orbit
orb, = ax.plot([], [], '.r',ms=1)

# time
time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes)

def positions(t):
    x = r*np.cos(w*t) # epicycle
    y = r*np.sin(w*t) # epicycle
    return x,y

def orbit(r):
    phi = np.linspace(0, 2*np.pi, 360)
    orb_x =  r*np.cos(phi)
    orb_y =  r*np.sin(phi)
    return orb_x,orb_y

def init():
    ax.plot([0], ms=7, c='k',marker='o')
    return e,traj_e

def update(t):
    global r, w
    w = s_w.val
    r = s_r.val
    ax.set_xlim(-(r)*1.1, (r)*1.1)
    ax.set_ylim(-(r)*1.1, (r)*1.1)  

    x,y = positions(t)

    x_e.append(x)
    y_e.append(y)
    traj_e.set_data(x_e[-M:-1], y_e[-M:-1])
    orb.set_data(orbit(r))
    e.set_data(x, y)

    time_text.set_text('time = %.1f' % t)
    return traj_e,e, orb

ax_w = plt.axes([0.1, 0.05, 0.35, 0.03])#, facecolor=axcolor)
ax_r = plt.axes([0.55, 0.05, 0.35, 0.03])#, facecolor=axcolor)

s_w = Slider(ax_w, r'$\omega$', -20, 20, valinit=w, valstep=0.2)
s_r = Slider(ax_r, r'r', 0, 5, valinit=r, valstep=0.2)
s_w.on_changed(update)
s_r.on_changed(update)

def anim():
    fig.canvas.draw_idle()
    return FuncAnimation(fig, update, frames=np.linspace(0, T_final, T_final*fps),
                        init_func=init, blit=True, interval=30)

anim()

使用这段代码,我可以更改 rw 的值,而无需暂停或从头开始重新启动动画。这段代码出现了另一个问题,即点 跳转 到圆上的某个随机位置,然后跳回预期轨迹。我会在另一个问题中解决它。