Я играл с кодом this бит кода Python, чтобы сравнить систему весенне-маятника. Я слегка изменил уравнение, и он прекрасно выглядит. Тем не менее, я также хочу добавить постоянную трассировку после нее, как в this gif.Python matplotlib анимация пути объекта
Вот мой полный код (я не могу обрезать ее вниз больше, так как вам нужно решить ОДУ для генерации данных на графике), то соответствующий бит в конце:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from numpy import sin, cos, pi, array
spring_constant = 22.93
length = 0.16
mass = 0.1
# initial conditions
init = array([-0.35, 0, 0.08, 1]) # initial values
#array([theta, theta_dot, x, x_dot])
#Return derivatives of the array z (= [theta, theta_dot, x, x_dot])
def deriv(z, t, spring_k, spring_l, bob_mass):
k = spring_k
l = spring_l
m = bob_mass
g = 9.8
theta = z[0]
thetadot = z[1]
x = z[2]
xdot= z[3]
return array([
thetadot,
(-1.0/(l+x)) * (2*xdot*thetadot + g*sin(theta)),
xdot,
g*cos(theta) + (l+x)*thetadot**2 - (k/m)*x
])
#Create time steps
time = np.linspace(0.0,10.0,1000)
#Numerically solve ODE
y = odeint(deriv,init,time, args = (spring_constant, length, mass))
l = length
r = l+y[:,2]
theta = y[:,0]
dt = np.mean(np.diff(time))
x = r*sin(theta)
y = -r*cos(theta)
##MATPLOTLIB BEGINS HERE##
fig = plt.figure()
ax = fig.add_subplot(111, autoscale_on=False,
xlim=(-1.2*r.max(), 1.2*r.max()),
ylim=(-1.2*r.max(), 0.2*r.max()), aspect = 1.0)
ax.grid()
##ANIMATION STUFF BEGINS HERE##
line, = ax.plot([], [], 'o-', lw=2)
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
def init():
line.set_data([], [])
time_text.set_text('')
return line, time_text
def animate(i):
thisx = [0, x[i]]
thisy = [0, y[i]]
line.set_data(thisx, thisy)
time_text.set_text(time_template%(i*dt))
return line, time_text
ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)),
interval=25, blit=True, init_func=init)
plt.show()
Я попытался сделать список точек, добавляемый к каждому времени цикл анимации вызывает, а затем рисовать все те точки до сих пор каждый кадр:
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
foox = []
fooy = []
def init():
line.set_data([], [])
foo.set_data([], [])
time_text.set_text('')
return line, time_text, foo
def animate(i):
thisx = [0, x[i]]
thisy = [0, y[i]]
foox += [x[i]]
fooy += [y[i]]
line.set_data(thisx, thisy)
foo.set_data(foox, fooy)
time_text.set_text(time_template%(i*dt))
return line, time_text, foo
Но я получаю
UnboundLocalError: local variable 'foox' referenced before assignment
Что я думаю, это не нравится, когда вы используете глобальную переменную? Я не уверен, как сохранить историю того, какие точки были нарисованы без использования переменной вне области animate(). Кто-нибудь знает как?
спасибо.
EDIT:
я решил. Я использовал + = вместо .append() по ошибке. Теперь я чувствую себя идиотом.
Для потомков он должен быть:
def animate(i):
thisx = [0, x[i]]
thisy = [0, y[i]]
foox.append(x[i])
fooy.append(y[i])
line.set_data(thisx, thisy)
foo.set_data(foox, fooy)
time_text.set_text(time_template%(i*dt))
return line, time_text, foo
Спасибо, хотя я получил это работает за счет изменения + = в Append. В чем разница между ними и почему требуется объявлять глобальные переменные, а другое - нет? Списки – dain
являются изменяемыми объектами, которые хранят указатель/ссылку на «сохраненный» объект. –
blit только не работает с бэкэндом OSX, если вы используете какой-либо из других интерактивных бэкэндов (те, которые заканчиваются на * agg), он будет работать. – tacaswell