我在这个线程上给出了一个答案,谈论matplotlib上的衰落点。我对ImportantOfBeingErnest的回答感到好奇。所以我试着玩弄他的代码。
首先,这是我的代码。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation
from matplotlib.colors import LinearSegmentedColormap
def get_new_vals():
x = 0
y = 0
while True:
if x >= .9:
x = 0
y = 0
x += .1
y += .1
yield x, y
def update(t, x_vals, y_vals, intensity, scatter, gen):
# Get intermediate points
new_xvals, new_yvals = gen.next()
x_vals.extend([new_xvals])
y_vals.extend([new_yvals])
# Put new values in your plot
scatter.set_offsets(np.c_[x_vals, y_vals])
# Calculate new color values
for index in range(len(intensity)):
if intensity[index] < .1:
intensity[index] = 0
intensity[index] *= .6
intensity.extend(1 for _ in xrange(len([new_xvals])))
intens_dup = np.array(intensity)
"""
intensity = np.concatenate((np.array(intensity) * .6, np.ones(len(new_xvals))))
"""
scatter.set_array(intens_dup)
# Set title
axis.set_title('Time: %0.3f' % t)
def anim_random_points(fig, axis):
x_vals = []
y_vals = []
intensity = []
iterations = 100
colors = [ [0, 0, 1, 0], [0, 0, 1, 0.5], [0, 0.2, 0.4, 1] ]
cmap = LinearSegmentedColormap.from_list("", colors)
scatter = axis.scatter(x_vals, y_vals, c=[], cmap=cmap, vmin=0, vmax=1)
gen_values = get_new_vals()
ani = matplotlib.animation.FuncAnimation(fig, update, frames=iterations,
interval=50, fargs=(x_vals, y_vals, intensity, scatter, gen_values),
repeat=False)
# Position 1 for plt.show()
plt.show()
if __name__ == '__main__':
fig, axis = plt.subplots()
axis.set_xlabel('X Axis', size = 12)
axis.set_ylabel('Y Axis', size = 12)
axis.axis([0,1,0,1])
anim_random_points(fig, axis)
# Position 2 for plt.show()
# plt.show()
然后,我注意到一件奇怪的事情。至少对我来说是这样。请注意Position 1
和Position 2
(在代码末尾(。位置 1 放置在 animation
函数之后,另一个放置在代码之后,因为函数在位置 1 之后结束,因此转到位置 2。
由于FuncAnimation
需要figure
来运行动画,我想知道为什么plt.show()
在位置 1 上工作,而不是在位置 2 上工作。
matplotlib 文档指出了大约 FuncAnimation
保留对实例对象的引用至关重要。动画由计时器(通常来自主机 GUI 框架(前进,动画对象保存对该计时器的唯一引用。如果不保留对 Animation 对象的引用,则它(以及计时器(将被垃圾回收,这将停止动画。
如果将plt.show()
放在 anim_random_points
函数之外,则保存对动画引用的变量 ani
将被垃圾回收,并且不再显示动画。
这种情况的解决方案是从该函数返回动画
def anim_random_points(fig, axis):
# ...
ani = matplotlib.animation.FuncAnimation(...)
return ani
if __name__ == '__main__':
# ...
ani = anim_random_points(...)
plt.show()
你真的应该问两个单独的问题。
我可以回答第一个。这两个位置之间的差异是由于ani
是函数anim_random_points()
的局部变量。当执行到达函数结束时,它会自动删除。因此,位置 2 中的plt.show()
没有要显示的内容。
如果要在位置 2 中使用 plt.show()
,则需要从函数返回 ani 对象,并在代码的主要部分保留对它的引用。
def anim_random_points(fig, axis):
(...)
ani = matplotlib.animation.FuncAnimation(...)
return ani
if __name__ == '__main__':
(...)
ani = anim_random_points(fig, axis)
# Position 2 for plt.show()
plt.show()