matplotlib imshow、ArtistAnimation和类属性
我正在用Python编写康威的生命游戏,并想展示它的演变过程。但是我在显示输出时遇到了问题。下面是我全部的代码。
我用这个例子作为基础:来自matplotlib的文档。我的动画是静态的,但如果我使用
ims.append([plt.imshow(world.state+0, cmap=plt.cm.binary, interpolation='nearest')])
它就能正确动画化。我尝试写一个函数wolrd.get_state(),以为这是某种评估问题,但没有成功。
这让我很烦恼,我到底漏掉了什么呢?
谢谢
import numpy as np
from scipy.signal import convolve2d
import matplotlib.pyplot as plt
import matplotlib.animation as animation
class World():
"""world information"""
def __init__(self, grid):
# noinspection PyNoneFunctionAssignment
self.state = np.empty(grid.shape)
self.__x_size = len(grid[0, :])
self.__y_size = len(grid[:, 0])
self.__x = range(self.__x_size)
self.__y = range(self.__y_size)
for i in self.__x:
for j in self.__y:
self.state[i, j] = grid[i, j]
def evolve(self):
alive_neighbours = convolve2d(self.state, np.ones((3, 3)), mode='same', boundary='wrap') - self.state
for i in self.__y:
for j in self.__x:
if alive_neighbours[i, j] < 2:
self.state[i, j] = 0
elif alive_neighbours[i, j] == 3:
self.state[i, j] = 1
elif alive_neighbours[i, j] > 3:
self.state[i, j] = 0
# self.state = np.random.randint(2, size=(self.__x_size, self.__y_size ))
if __name__ == "__main__":
nbx = 5
nby = 5
nb_gen = 5
initial_seed = np.random.randint(2, size=(nbx, nby))
world = World(initial_seed)
ims = []
fig = plt.figure()
for i in range(nb_gen):
ims.append([plt.imshow(world.state, cmap=plt.cm.binary, interpolation='nearest')])
world.evolve()
ani = animation.ArtistAnimation(fig, ims, interval=500, blit=True, repeat_delay=1000)
plt.show()
注意:我已经成功使用了:
def animate(i):
world.evolve()
return (plt.imshow(world.state, cmap=plt.cm.binary, interpolation='nearest'),)
ani = animation.FuncAnimation(fig, animate, frames=nb_gen, interval=500, blit=True, repeat_delay=1000)
但这不是我想要的。
1 个回答
4
动画的每一帧都显示的是相同的世界状态。
因为世界类只是在修改状态,所以每一帧都传入了同一个对象的引用给imshow()。也就是说,动画的每一帧都在引用同一个数组。
Matplotlib在调用plt.show()之前不会把动画画到屏幕上,所以你只能看到传给imshow()的数组的最终版本,也就是World.state的最终状态。
这就是为什么
a = [1, 2, 3]
b = a
a.append(4)
print(b)
输出的是[1, 2, 3, 4]。b指向a,所以当a改变时,b也会跟着改变。
把要显示的图像复制一份可以解决这个问题。
ims.append([plt.imshow(world.state.copy(), cmap=plt.cm.binary, interpolation='nearest')])
这也是为什么world.state + 0和np.random.randint(2, size=(self.__x_size, self.__y_size ))能正常工作的原因:它们都创建了新的数组,而不是修改已经传给imshow()的数组。