#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 как псевдо игровой движок. Хотя это определенно работает. Очень признателен.