Python MATPLOTLIB ANIMATION不使用全局变量?



问题:在不使用全局数组或不断添加全局"数据点列表"的情况下,使用Python的MATPLOTLIB动画函数最干净、最简单的方法是什么?一个阴谋?

这是一个动画图表的例子,绘制了股票报价机的出价和要价大小。在这个例子中,变量time[], ask[]和bid[]被用作全局变量。

我们如何修改matplotlib animate()函数不使用全局变量?

所以我试图删除"all"全局变量和只运行一个函数调用…

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from random import randint
stock = {'ask': 12.82, 'askSize': 21900, 'bid': 12.81, 'bidSize': 17800}
def get_askSize():
return stock["askSize"] + randint(1,9000) # grab a random integer to be the next y-value in the animation
def get_bidSize():
return stock["bidSize"] + randint(1,9000) # grab a random integer to be the next y-value in the animation
def animate(i):
pt_ask = get_askSize()
pt_bid = get_bidSize()
time.append(i) #x
ask.append(pt_ask) #y
bid.append(pt_bid) #y
ax.clear()
ax.plot(time, ask)
ax.plot(time, bid)
ax.set_xlabel('Time')
ax.set_ylabel('Volume')
ax.set_title('ask and bid size')
ax.set_xlim([0,40])
#axis = axis_size(get_bidSize, get_askSize)
ylim_min = (get_askSize() + get_bidSize())/6
ylim_max = (get_askSize() + get_bidSize())
ax.set_ylim([ylim_min,ylim_max])
# create empty lists for the x and y data
time = []
ask = []
bid = []
# create the figure and axes objects
fig, ax = plt.subplots()
# run the animation
ani = FuncAnimation(fig, animate, frames=40, interval=500, repeat=False)
plt.show()

正如@Warren提到的,你可以使用fargs参数来传递在动画函数中使用的共享变量。

你还应该预先计算所有的点,然后使用你的帧仅仅作为这些帧的扩展窗口。这将是一个性能更高的解决方案,并防止您需要在动画的每个tick之间转换numpy数组和列表,以便更新您的行底层数据。

这也使您能够预先计算您的y限制,以防止您的最终绘图到处跳跃。

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
rng = np.random.default_rng(0)
def animate(i, ask_line, bid_line, data):
i += 1
x = data['x'][:i]
ask_line.set_data(x, data['ask'][:i])
bid_line.set_data(x, data['bid'][:i])
stock = {'ask': 12.82, 'askSize': 21900, 'bid': 12.81, 'bidSize': 17800}
frames = 40
data = {
'x': np.arange(0, frames),
'ask': stock['askSize'] + rng.integers(0, 9000, size=frames),
'bid': stock['bidSize'] + rng.integers(0, 9000, size=frames),
}
fig, ax = plt.subplots()
ask_line, = ax.plot([], [])
bid_line, = ax.plot([], [])
ax.set(xlabel='Time', ylabel='Volume', title='ask and bid size', xlim=(0, 40))
ax.set_ylim(
min(data['ask'].min(), data['bid'].min()),
max(data['ask'].max(), data['bid'].max()),
)
# run the animation
ani = FuncAnimation(
fig, animate, fargs=(ask_line, bid_line, data),
frames=40, interval=500, repeat=False
)
plt.show()

您可以使用FuncAnimationfargs参数为animate回调函数提供额外的参数。所以animate可能以

开头
def animate(i, askSize, bidSize):
...

,在FuncAnimation的调用中,您将添加参数fargs=(askSize, bidSize)。添加您需要在animate函数中可用的任何变量(以任何形式)。

我在numpngw包中使用FuncAnimationAnimatedPNGWriter的示例中使用了它;参见例8。在这个例子中,我的回调函数是

def update_line(num, x, data, line):
"""
Animation "call back" function for each frame.
"""
line.set_data(x, data[num, :])
return line,

FuncAnimation创建

ani = animation.FuncAnimation(fig, update_line, frames=len(t),
init_func=lambda : None,
fargs=(x, sol, lineplot))

你使用了错误的动画,因为你在每次迭代中添加和删除行,这使得动画慢了很多。对于线形图,最好的处理方法是:

  1. 初始化图形和轴
  2. 初始化空行
  3. animate函数内,更新每一行的数据。

像这样:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from random import randint
stock = {'ask': 12.82, 'askSize': 21900, 'bid': 12.81, 'bidSize': 17800}
def get_askSize():
return stock["askSize"] + randint(1,9000) # grab a random integer to be the next y-value in the animation
def get_bidSize():
return stock["bidSize"] + randint(1,9000) # grab a random integer to be the next y-value in the animation
def add_point_to_line(x, y, line):
# retrieve the previous data in the line
xd, yd = [list(t) for t in line.get_data()]
# append the new point
xd.append(x)
yd.append(y)
# set the new data
line.set_data(xd, yd)
def animate(i):
pt_ask = get_askSize()
pt_bid = get_bidSize()

# append a new value to the lines
add_point_to_line(i, pt_ask, ax.lines[0])
add_point_to_line(i, pt_bid, ax.lines[1])
# update axis limits if necessary
ylim_min = (get_askSize() + get_bidSize())/6
ylim_max = (get_askSize() + get_bidSize())
ax.set_ylim([ylim_min,ylim_max])

# create the figure and axes objects
fig, ax = plt.subplots()
# create empty lines that will be populated on the animate function
ax.plot([], [])
ax.plot([], [])
ax.set_xlabel('Time')
ax.set_ylabel('Volume')
ax.set_title('ask and bid size')
ax.set_xlim([0,40])
# run the animation
ani = FuncAnimation(fig, animate, frames=40, interval=500, repeat=False)
plt.show()

最新更新