为什么我的“人生游戏"模拟会在几秒钟内减速到爬行? Matplotlib怪? [英] Why does my Game of Life simulation slow down to a crawl within seconds? Matplotlib to blame?

查看:370
本文介绍了为什么我的“人生游戏"模拟会在几秒钟内减速到爬行? Matplotlib怪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用python学习OOP,所以为了好玩,我今天早上推出了GameOfLife模拟器.当它启动时,它以每秒约20个周期的速度运行(由于添加了plt.pause(0.05)),但是在几秒钟内,它的运行速度就会降低到每秒约2个周期.

I'm learning OOP in python and so for a bit of fun I bashed out a GameOfLife simulator this morning. When it starts up it runs at about 20 cycles per second (due to the plt.pause(0.05) I added), but within seconds it slows down to ~ 2 cycles per second.

我无法想象这是算法本身,也看不到任何明显的内存泄漏源.

I can't imagine it's the algorithm itself, and I can't see any obvious sources for memory leaks.

matplotlib是否无法转储旧图,是否是这个问题,导致成千上万的叠加图像堆积?我尝试添加del im,但没有帮助...

Is matplotlib failing to dump the old plots, is that the issue, causing thousands of overlayed images building up? I tried adding del im but it didn't help...

这确实不重要,但是我觉得我可以从答案中学到一些东西.

This isn't important, really, but I feel I could learn something from the answer.

如果您认为我的实施不力,请告诉我,我很想学习!

PS if you think my implementation is poor then do let me know, I'm keen to learn!

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import convolve
import time

class GoL():

    KERNEL = np.array([[1, 1, 1],
                       [1, 0, 1],
                       [1, 1, 1]])

    def __init__(self, width, height, p=0.3):
        self.width = width
        self.height = height
        self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])

    def play(self):
        self.plot()
        while True:
            self.cycle()

    def cycle(self):
        c = self.eval()
        for x in range(1,self.width-1):
            for y in range(1,self.height-1):
                c_val = c[x,y]
                if c_val == 3: self.matrix[x,y] = 1 #Alive regardless of whether cell alive or dead
                elif c_val < 2: self.matrix[x,y] = 0 #Dead regardless of whether cell alive or dead
                elif c_val > 3: self.matrix[x,y] = 0 #Dead regardless of whether cell alive or dead
                elif self.matrix[x,y] == 1 and c_val == 2: self.matrix[x,y] = 1 #If a living cell with 2 neighours, live
                else: self.matrix[x,y] = 0 #Only other option is dead with 2 neighbours; die
        self.plot()

    def eval(self):
        c = convolve(self.matrix, GoL.KERNEL, mode='constant')
        return c

    def plot(self):
        im = plt.imshow(self.matrix)
        plt.pause(0.05)
        del im #Added to see if speeds things up; it does not

并运行:

gol = GoL(width=100,height=100)
gol.play()

推荐答案

通过打印plot函数内部的图像数量

You will see that the images of previous calls are still present by printing the number of images inside the plot function,

print ( len(plt.gca().images) )

在您的情况下,即使删除图像,该数字也会稳定增加,因为它仍然是轴的一部分,因此每次迭代都会重绘.

In your case this number will increase steadily, even though you delete the image, because it is still part of the axes and hence get redrawn every iteration.

最好先绘制一次图像,然后仅更新其数据.

It would be much better to draw the image once, and then only update its data.

class GoL():
    # ...

    def __init__(self, width, height, p=0.3):
        self.width = width
        self.height = height
        self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])
        self.im = plt.imshow(self.matrix)

    #  ....

    def plot(self):
        self.im.set_data(self.matrix)
        plt.pause(0.05)
        print len(plt.gca().images)

这将以恒定速度产生动画.

This will result in an animation at constant speed.


关于在哪里改进代码的问题,有两件事:


Concerning the question on where to improve the code, there are two things:

  1. 使用matplotlib.animation.FuncAnimation,因为它更加稳定,可让您轻松地终止动画.
  2. 在numpy数组上使用条件,而不是遍历矩阵的所有像素.
  1. use matplotlib.animation.FuncAnimation, as this is much more stable and lets you savely terminate the animation.
  2. use conditions on numpy arrays instead of looping over all pixels of the matrix.

完整代码:

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import convolve
import matplotlib.animation as animation

class GoL():

    KERNEL = np.array([[1, 1, 1],
                       [1, 0, 1],
                       [1, 1, 1]])

    def __init__(self, width, height, p=0.3):
        self.width = width
        self.height = height
        self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])
        self.im = plt.imshow(self.matrix)

    def play(self):
        self.plot()
        self.ani= animation.FuncAnimation(plt.gcf(), self.cycle, repeat=True, interval=50 )
        plt.show()

    def cycle(self, n):
        c = self.eval()
        new = np.zeros_like(self.matrix)
        new[c == 3] = 1
        new[c < 2] = 0
        new[c > 3] = 0
        new[(self.matrix == 1) & (c == 2)] = 1
        self.matrix = new
        self.plot()

    def eval(self):
        return convolve(self.matrix, self.KERNEL, mode='constant')

    def plot(self):
        self.im.set_data(self.matrix)

gol = GoL(width=100,height=100)
gol.play()

这篇关于为什么我的“人生游戏"模拟会在几秒钟内减速到爬行? Matplotlib怪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆