I have a program with rapid animations which works perfectly under pygame, and for technical reasons, I need to do the same using only matplotlib or an other widespread module.
The program structure is roughly:
pygame.init()
SURF = pygame.display.set_mode((500, 500))
arr = pygame.surfarray.pixels2d(SURF) # a view for numpy, as a 2D array
while ok:
# modify some pixels of arr
pygame.display.flip()
pygame.quit()
I have no low level matplotlib experience, but I think it is possible to do equivalent things with matplotlib. In other words :
How to share the bitmap of a figure, modify some pixels and refresh the screen ?
Here is a minimal working exemple, which flips 250 frames per second (more than the screen ...) on my computer :
import pygame,numpy,time
pygame.init()
size=(400,400)
SURF = pygame.display.set_mode(size)
arr = pygame.surfarray.pixels2d(SURF) # buffer pour numpy
t0=time.clock()
for counter in range(1000):
arr[:]=numpy.random.randint(0,0xfffff,size)
pygame.display.flip()
pygame.quit()
print(counter/(time.clock()-t0))
EDIT
What I try with indications in answers :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 400)
y = np.linspace(0, 2 * np.pi, 400).reshape(-1, 1)
im = plt.imshow(f(x, y), animated=True)
count=0
t0=time.clock()+1
def updatefig(*args):
global x, y,count,t0
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
if time.clock()<t0:
count+=1
else:
print (count)
count=0
t0=time.clock()+1
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
But this only provides 20 fps....
It should be noted that the human brain is capable of "seeing" up to a framerate of ~25 fps. Faster updates are not actually resolved.
With matplotlib and its animation
module the example from the question runs with 84 fps on my computer.
import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 400)
y = np.linspace(0, 2 * np.pi, 400).reshape(-1, 1)
im = ax.imshow(f(x, y), animated=True)
text = ax.text(200,200, "")
class FPS():
def __init__(self, avg=10):
self.fps = np.empty(avg)
self.t0 = time.clock()
def tick(self):
t = time.clock()
self.fps[1:] = self.fps[:-1]
self.fps[0] = 1./(t-self.t0)
self.t0 = t
return self.fps.mean()
fps = FPS(100)
def updatefig(i):
global x, y
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
tx = 'Mean Frame Rate:\n {fps:.3f}FPS'.format(fps= fps.tick() )
text.set_text(tx)
return im, text,
ani = animation.FuncAnimation(fig, updatefig, interval=1, blit=True)
plt.show()
In pyqtgraph a higher framerate is obtained, it would run with 295 fps on my computer.
import sys
import time
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import pyqtgraph as pg
class FPS():
def __init__(self, avg=10):
self.fps = np.empty(avg)
self.t0 = time.clock()
def tick(self):
t = time.clock()
self.fps[1:] = self.fps[:-1]
self.fps[0] = 1./(t-self.t0)
self.t0 = t
return self.fps.mean()
fps = FPS(100)
class App(QtGui.QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent)
#### Create Gui Elements ###########
self.mainbox = QtGui.QWidget()
self.setCentralWidget(self.mainbox)
self.mainbox.setLayout(QtGui.QVBoxLayout())
self.canvas = pg.GraphicsLayoutWidget()
self.mainbox.layout().addWidget(self.canvas)
self.label = QtGui.QLabel()
self.mainbox.layout().addWidget(self.label)
self.view = self.canvas.addViewBox()
self.view.setAspectLocked(True)
self.view.setRange(QtCore.QRectF(0,0, 100, 100))
# image plot
self.img = pg.ImageItem(border='w')
self.view.addItem(self.img)
#### Set Data #####################
self.x = np.linspace(0, 2 * np.pi, 400)
self.y = np.linspace(0, 2 * np.pi, 400).reshape(-1, 1)
#### Start #####################
self._update()
def f(self, x, y):
return np.sin(x) + np.cos(y)
def _update(self):
self.x += np.pi / 15.
self.y += np.pi / 20.
self.img.setImage(self.f(self.x, self.y))
tx = 'Mean Frame Rate:\n {fps:.3f}FPS'.format(fps= fps.tick() )
self.label.setText(tx)
QtCore.QTimer.singleShot(1, self._update)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
thisapp = App()
thisapp.show()
sys.exit(app.exec_())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With