I am trying to visualise the output of a numerical fluid dynamics model using pygame. The model state is a (nx, ny) numpy array, which I am using surfarray.blit_array
on a (nx, ny) surface that is then blitted to the screen. I have put a working example below (press ESC to stop it).
When screen_size is (nx, ny), on my computer the code runs at 60FPS. When I set the screen_size to (nx*5, ny), it drops to 14FPS.
I think I am doing the right thing to update the display, only updating the rects and not the whole screen, so why is it slowing down so precipitously when additional blank space is added to the screen? Using display.update
seems to be no faster than using display.flip
.
import pygame
import numpy as np
from matplotlib.cm import viridis
from matplotlib.colors import Normalize
pygame.init()
pygame.font.init()
font = pygame.font.SysFont("Arial", 18)
nx = 256
ny = 257
# CHANGE THIS TO SEE THE SLOWDOWN
screen_size = (nx, ny)
flags = pygame.DOUBLEBUF #|pygame.HWACCEL|pygame.FULLSCREEN
screen = pygame.display.set_mode(screen_size, flags)
screen.set_alpha(None)
clock = pygame.time.Clock()
def show_array(arr, surf=screen, cmap=viridis):
normed = Normalize()(arr)
cmapped = cmap(normed, bytes=True)[:,:, :3]
pygame.surfarray.blit_array(surf, cmapped)
surf = pygame.Surface((nx, ny))
ocean = np.zeros((nx, ny))
x, y = np.indices(ocean.shape)
ocean[:] = np.cos(x/nx*2*np.pi) # initial condition
for i in range(10000):
active_rects = []
clock.tick(100)
# move the wave left (this is a stand-in for the real physics)
ocean = np.roll(ocean, 1, axis=0)
show_array(ocean, surf)
active_rects.append(screen.blit(surf, (0, 0)))
fps = font.render('FPS: %1.f'%clock.get_fps(), True, (255, 255, 255))
active_rects.append(screen.blit(fps, (5, 5)))
for e in pygame.event.get():
if e.type == pygame.QUIT:
exit()
if e.type == pygame.KEYDOWN:
if e.key == 27: exit()
pygame.display.update(active_rects)
#pygame.display.flip()