PsychoPy-Matplotlib

From TSG Doc
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