Python matplotlib动画化对象的路径

时间:2016-05-22 14:53:52

标签: python animation matplotlib

我一直在摆弄this位的Python代码来模拟弹簧摆系统。我略微改变了方程式并且它很好。但是,我还希望在this gif。

之后添加一个持久跟踪

这是我的完整代码(由于你需要ODE求解以生成绘图数据,我不能再削减它),相关位接近结束:

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()范围之外的变量的情况下保留已绘制点的历史记录。谁知道怎么做?

谢谢。

修改

我解决了。我误用了+ =而不是.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

2 个答案:

答案 0 :(得分:0)

您正在修改动画函数中的全局变量,而不将其声明为global

fooline也是多余的

除此之外,你的动画效果很好;您可以运行以下代码来查看它:

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上工作

答案 1 :(得分: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