PsychoPy-Matplotlib

From TSG Doc
Jump to: navigation, search

Matplotlib does not have a (documented) way of exporting an image other than writing to file or screen. PsychoPy does not have a documented way of importing images other than reading from file. The following example shows how to use the undocumented features in both libraries.

A matplotlib graph is made, written to file and shown in a PsychoPy ImageStim. Then the graph is updated and send directly to the ImageStim object (without writing to file) to replace the old image. On the labcomputer this runs smoothly at 60Hz. This is a video of the demo. Note that the video is not as smooth as the demo.

 1 #!/usr/bin/python
 2 from __future__ import print_function
 3 from psychopy import visual, event
 4 import pyglet.gl as GL
 5 import numpy as np
 6 import matplotlib.pyplot as plt  # default backend TkAgg is ok
 7 import math
 8 import sys, time
 9 #for optimalization: http://bastibe.de/2013-05-30-speeding-up-matplotlib.html
10 
11 # make initial image
12 t = np.linspace(0, 4*np.pi, 1000) # horizontal axis
13 fig, ax = plt.subplots()         # create new figure
14 fig.set_size_inches([8,6])       # yuck
15 line, = ax.plot(t, np.sin(t))    # initial plot
16 fig.savefig('img.png', dpi=80)   # must be set to 80, this is what tostring_rgb does also
17 ncols, nrows = fig.canvas.get_width_height()
18 
19 # put it in an ImageStim
20 win = visual.Window(monitor='testMonitor')
21 img = visual.ImageStim(win, 'img.png', units='pix', interpolate=False, flipVert=True)
22 
23 # change it
24 x = t0 = t1 = 0
25 while not event.getKeys():
26 	ax.draw_artist(ax.patch)        # faster than redrawing the canvas
27 	ax.draw_artist(line)            # faster than redrawing the canvas
28 	buf = fig.canvas.tostring_rgb() # make a bitmap
29 	# convert bitmap to correct format for GL texture
30 	tex = np.fromstring(buf, dtype=np.uint8).reshape(nrows, ncols, 3).astype(np.float32)/255
31 	img._createTexture(tex, img._texID, GL.GL_RGB, img, forcePOW2=False) # set texture in video mem
32 	img.draw()                      
33 	t1 = win.flip()                 # mark time on screen
34 	print("{:.3f} s/frame".format(t1-t0), end='\r') # show frame time
35 	sys.stdout.flush()              # write text immediately
36 	t0 = t1                         # prepare for next iteration
37 	x += 0.01                       # change graph
38 	line.set_ydata(np.sin(2*t+x))   # change graph, faster than ax.clear, ax.plot