Анимация Matplotlib: передача переменных через FuncAnimation

#python #matplotlib

#python #matplotlib

Вопрос:

Я пытаюсь обработать данные в matplotlib.Функция FuncAnimation. В любом случае, данные можно повторять, и я изо всех сил пытаюсь заставить функцию анимации в python выполнять итерации по внешней переменной. В данном случае переменная Ball_1.

Ошибка, которую это выдает, заключается в следующем: ‘UnboundLocalError: локальная переменная ‘ball_1′, на которую ссылаются перед назначением’

Я оглядываюсь назад, это не лучший способ сделать это. Однако я хотел бы знать, возможно ли это?

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

fig, ax = plt.subplots()
ax.set_xlim(0,100)
ax.set_ylim(0,100)

#         acc,vel,disp (x,y)
ball_1 = [[0,0,40],[0,0,100]]

ball_1_plot, = ax.plot(ball_1[0][2],ball_1[1][2], "o")

# 
def init_DEM():
    ball_1 = [[0,0,40],[0,0,100]]
    return ball_1_plot,

def DEM(step):
    
    TS = step/10
    
    # Ball_1
    # Contact
    grav = -9.81
    
    # Acceleration

    acc_x = 0   
    acc_y = grav  
    
    # Velocity
    vel_x = ball_1[0][1]   acc_x*TS  
    vel_y = ball_1[1][1]   acc_y*TS  
    
    # Position
    pos_x = vel_x * TS   0.5 * acc_x * TS * TS    ball_1[0][2]
    pos_y = vel_y * TS   0.5 * acc_y * TS * TS    ball_1[1][2]
    
    print(pos_x)
    # Update 
    
    ball_1 = [[acc_x,vel_x,pos_x],[acc_y,vel_y,pos_y]]
    
    # Update animation
    ball_1_plot.set_xdata(ball_1[0][2])
    ball_1_plot.set_xdata(ball_1[1][2])

    return ball_1_plot,
    
animation_run = FuncAnimation(fig,func=DEM, frames=[10,20], init_func=init_DEM, interval=10)
plt.show()
  

Ответ №1:

Вы можете использовать functools.partial или лямбда-функцию. Допустим, вы изменили свой код таким образом, что ball_1 и ball_1_plt больше не являются глобальными, а являются аргументами для DEM . Затем вы вызываете это следующим образом:

 from functools import partial
animation_run = FuncAnimation(
    fig,
    func=partial(DEM, ball_1=ball_1, ball_1_plot=ball_1_plot),
    frames=[10,20],
    interval=10
)
  

Ссылки будут сохраняться между вызовами, поэтому это должно работать, но вы не можете назначить их внутри DEM . Другими словами, замените это:

 ball_1 = [[acc_x,vel_x,pos_x],[acc_y,vel_y,pos_y]]
  

этим:

 ball_1[0] = [acc_x,vel_x,pos_x]
ball_1[1] = [acc_y,vel_y,pos_y]
  

Объяснение

Причина по той же причине, по которой ваш код терпит неудачу прямо сейчас. При назначении ball_1 привязывается новая переменная. Эта переменная является локальной. Ваш текущий код будет выполняться, если вы добавите оператор global ball_1 в верхней части функции. Однако лучше не использовать глобальные переменные, а передавать аргументы, как вы предлагаете в своем вопросе.

Это ваш код без каких-либо глобальных функций, перемещение вашего кода верхнего уровня в функцию и передача аргументов DEM :

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


def DEM(step, ball_1, ball_1_plot):
    TS = step/10

    # Ball_1
    # Contact
    grav = -9.81

    # Acceleration
    acc_x = 0
    acc_y = grav

    # Velocity
    vel_x = ball_1[0][1]   acc_x*TS
    vel_y = ball_1[1][1]   acc_y*TS

    # Position
    pos_x = vel_x * TS   0.5 * acc_x * TS * TS    ball_1[0][2]
    pos_y = vel_y * TS   0.5 * acc_y * TS * TS    ball_1[1][2]

    # Update
    ball_1[0] = [acc_x,vel_x,pos_x]
    ball_1[1] = [acc_y,vel_y,pos_y]

    # Update animation
    ball_1_plot.set_xdata(ball_1[0][2])
    ball_1_plot.set_xdata(ball_1[1][2])

    return ball_1_plot,

def main():
    from functools import partial

    fig, ax = plt.subplots()
    ax.set_xlim(0,100)
    ax.set_ylim(0,100)

    #         acc,vel,disp (x,y)
    ball_1 = [[0,0,40],[0,0,100]]
    ball_1_plot, = ax.plot(ball_1[0][2],ball_1[1][2], "o")

    animation_run = FuncAnimation(fig,func=partial(DEM, ball_1=ball_1, ball_1_plot=ball_1_plot), frames=[10,20], interval=10)
    plt.show()


if __name__ == '__main__':
    main()
  

Комментарии:

1. Отличный ответ, спасибо. Я не знал о частичном классе / функции. Немного странно запускать matlplotlib как псевдо игровой движок. Хотя это определенно работает. Очень признателен.