在matplotlib中交互更改动画参数

时间:2019-06-28 09:20:18

标签: python matplotlib animation python-interactive

我需要为一些非常简单的动画设置动画,但是我还需要一个滑块来让用户以交互方式更改动画的参数。我希望它可以在网上进行;也就是说,如果用户在播放动画时更改了参数,则动画应该可以从旧动态平稳过渡到新动态。

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

这是我的代码的简化版本:点围绕中心旋转,与中心的距离为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)

请注意,可以停止动画,通过滑块更改参数并重新运行它。我想避免动画中出现此暂停。我将不胜感激。

1 个答案:

答案 0 :(得分: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的值,而无需从头暂停或重新启动动画。但是,此代码出现了另一个问题,即点到圆上的某个随机位置,然后跳回了预期的轨迹。我会在另一个问题中解决这个问题。