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.
1#!/usr/bin/python
2from __future__ import print_function
3from psychopy import visual, event
4import pyglet.gl as GL
5import numpy as np
6import matplotlib.pyplot as plt # default backend TkAgg is ok
7import math
8import sys, time
9#for optimalization: http://bastibe.de/2013-05-30-speeding-up-matplotlib.html
10
11# make initial image
12t = np.linspace(0, 4*np.pi, 1000) # horizontal axis
13fig, ax = plt.subplots() # create new figure
14fig.set_size_inches([8,6]) # yuck
15line, = ax.plot(t, np.sin(t)) # initial plot
16fig.savefig('img.png', dpi=80) # must be set to 80, this is what tostring_rgb does also
17ncols, nrows = fig.canvas.get_width_height()
18
19# put it in an ImageStim
20win = visual.Window(monitor='testMonitor')
21img = visual.ImageStim(win, 'img.png', units='pix', interpolate=False, flipVert=True)
22
23# change it
24x = t0 = t1 = 0
25while 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