0

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

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

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

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)

请注意,可以停止动画,通过滑块更改参数并重新运行。我想避免动画中的这种暂停。我会很感激任何帮助。

4

1 回答 1

0

感谢@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无需从头开始暂停或重新启动动画。这段代码出现了另一个问题,即该点跳到圆上的某个随机位置,然后跳回预期的轨迹。我会在另一个问题中解决它。

于 2019-07-12T13:47:36.143 回答