Интерактивное изменение параметров анимации в matplotlib - PullRequest
0 голосов
/ 28 июня 2019

Мне нужно анимировать что-то довольно простое, но мне также нужен слайдер, чтобы пользователь мог интерактивно изменять параметры анимации. Я хотел бы, чтобы это произошло в Интернете; то есть, если пользователь изменяет параметр во время воспроизведения анимации, анимация должна плавно переходить от старой динамики к новой.

Пока что я написал функцию, которая принимает аргументы и создает анимацию. Но он не интерактивный в том смысле, в котором я упоминал ранее. В моем коде нет ползунков или чего-то действительно интерактивного. Тем не менее, анимационная часть работает по крайней мере плавно.

Вот упрощенная версия моего кода: точка вращается вокруг центра с указанным расстоянием 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 голосов
/ 12 июля 2019

Благодаря @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()

Используя этот фрагмент кода, я могу изменить значения r и w без остановки или перезапуска анимации с нуля. Однако с этим кодом возникает еще одна проблема, заключающаяся в том, что точка переходит в некоторую случайную позицию на окружности, а затем переходит обратно на ожидаемую траекторию. Я бы сказал об этом в другом вопросе.

...