2016-05-22 2 views
1

Я играл с кодом 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 

ответ

0

Вы изменяете глобальные переменные в вашей функции живого, не объявляя их как global

foo и line также избыточными

Кроме этого, ваша анимация работает хорошо; вы можете запустить следующий код, чтобы увидеть его:

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) 
foox = [] 
fooy = [] 
#foo.set_data(foox, fooy) 

def init(): 
    global line, time_text, foo 
    line.set_data([], []) 
# foo.set_data([], []) 
    time_text.set_text('') 
    return line, time_text#, foo 


def animate(i): 
    global foox, fooy, foo 
    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 

ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), interval=25, blit=False, init_func=init) 

plt.show() 

Я установил blit=False потому что в прошлом я проверил, blit не работает на OSX

+0

Спасибо, хотя я получил это работает за счет изменения + = в Append. В чем разница между ними и почему требуется объявлять глобальные переменные, а другое - нет? Списки – dain

+0

являются изменяемыми объектами, которые хранят указатель/ссылку на «сохраненный» объект. –

+1

blit только не работает с бэкэндом OSX, если вы используете какой-либо из других интерактивных бэкэндов (те, которые заканчиваются на * agg), он будет работать. – tacaswell

0

я решил. Я использовал + = вместо .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 
Смежные вопросы