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