Search code examples
pythonopenglnumpyplotglumpy

Display NumPy array as continuously updating image with Glumpy


I've got a simulation model running in Python using NumPy and SciPy and it produces a 2D NumPy array as the output each iteration. I've been displaying this output as an image using matplotlib and the imshow function. However, I've found out about Glumpy, and on its documentation page it says:

Thanks to the IPython shell, glumpy can be ran in interactive mode where you can experience live update in displayed arrays when their contents is changed.

However, I can't seem to work out how to do this with the examples they've given. Basically my model runs as a single function which has a big for loop in it to loop for the number of iterations I'm running. At the end of each iteration of the for loop I want to display the array. At the moment I'm using matplotlib to save the image out to a png file, as displaying it on the screen through matplotlib seems to freeze the python process.

I'm sure there's a way to do this with Glumpy, I'm just not sure how, and I can't find any useful tutorials.


Solution

  • The Glumpy documentation is fairly nonexistent! Here's an example of a simple simulation, comparing array visualisation with glumpy against matplotlib:

    import numpy as np
    import glumpy
    from OpenGL import GLUT as glut
    from time import time
    from matplotlib.pyplot import subplots,close
    from matplotlib import cm
    
    def randomwalk(dims=(256,256),n=3,sigma=10,alpha=0.95,seed=1):
        """ A simple random walk with memory """
        M = np.zeros(dims,dtype=np.float32)
        r,c = dims
        gen = np.random.RandomState(seed)
        pos = gen.rand(2,n)*((r,),(c,))
        old_delta = gen.randn(2,n)*sigma
        while 1:
            delta = (1.-alpha)*gen.randn(2,n)*sigma + alpha*old_delta
            pos += delta
            for ri,ci in pos.T:
                if not (0. <= ri < r) : ri = abs(ri % r)
                if not (0. <= ci < c) : ci = abs(ci % c)
                M[ri,ci] += 1
            old_delta = delta
            yield M
    
    def mplrun(niter=1000):
        """ Visualise the simulation using matplotlib, using blit for 
        improved speed"""
        fig,ax = subplots(1,1)
        rw = randomwalk()
        im = ax.imshow(rw.next(),interpolation='nearest',cmap=cm.hot,animated=True)
        fig.canvas.draw()
        background = fig.canvas.copy_from_bbox(ax.bbox) # cache the background
    
        tic = time()
        for ii in xrange(niter):
            im.set_data(rw.next())          # update the image data
            fig.canvas.restore_region(background)   # restore background
            ax.draw_artist(im)          # redraw the image
            fig.canvas.blit(ax.bbox)        # redraw the axes rectangle
    
        close(fig)
        print "Matplotlib average FPS: %.2f" %(niter/(time()-tic))
    
    def gprun(niter=1000):
        """ Visualise the same simulation using Glumpy """
        rw = randomwalk()
        M = rw.next()
    
        # create a glumpy figure
        fig = glumpy.figure((512,512))
    
        # the Image.data attribute is a referenced copy of M - when M
        # changes, the image data also gets updated
        im = glumpy.image.Image(M,colormap=glumpy.colormap.Hot)
    
        @fig.event
        def on_draw():
            """ called in the simulation loop, and also when the
            figure is resized """
            fig.clear()
            im.update()
            im.draw( x=0, y=0, z=0, width=fig.width, height=fig.height )
    
        tic = time()
        for ii in xrange(niter):
            M = rw.next()           # update the array          
            glut.glutMainLoopEvent()    # dispatch queued window events
            on_draw()           # update the image in the back buffer
            glut.glutSwapBuffers()      # swap the buffers so image is displayed
    
        fig.window.hide()
        print "Glumpy average FPS: %.2f" %(niter/(time()-tic))
    
    if __name__ == "__main__":
        mplrun()
        gprun()
    

    Using matplotlib with GTKAgg as my backend and using blit to avoid drawing the background each time, I can hit about 95 FPS. With Glumpy I get about 250-300 FPS, even though I currently a fairly crappy graphics setup on my laptop. Having said that, Glumpy is a bit more fiddly to get working, and unless you are dealing with huge matrices, or you need a very high framerate for whatever reason, I would stick with using matplotlib with blit.