Drawing a Matplotlib plot to the Psychopy window

Hello,

Is it possible to draw a Matplotlib plot to the psychopy window itself, rather than to it’s own unique window? I’m currently running code that returns 4 values, I’m then closing the psychopy window and running the matplotlib code, which then opens it’s own window. I gather that they are completely different things, but I just wondered if it would be at all possible to draw the plot to the main experiment window.

Here is my matplot lib code (that runs at the end), the code previous to this simply gives me 4 values associated with variables ‘red’,‘green’,‘blue’,‘grey’. Which is why I did not insert the code here.

colors = ('red','green','blue','grey')
y_pos = np.arange(len(colors))
performance = [red,green,blue,grey]
 
x = plt.bar(y_pos, performance, align='center')
x[0].set_color('red')
x[1].set_color('green')
x[2].set_color('blue')
x[3].set_color('grey')
plt.xticks(y_pos, colors)
plt.ylabel('count')
 
plt.show()

I was thinking this might be helpful for any experiment (or anything else) that wanted to feedback performance to the user during an experiment, for example.

Cheers,

Steve

Hi Steve,

I don’t know whether it’s really suitable to use matplotlip in this case. If you want to show a visual feedback reporting a bar for each colour, you could easily produce that directly in psychopy. You could use visual.Rect() to create the bars with different colors and visual.Line() for the axis and then add labels with visual.TextStim().

If you really want to use matplotlib, don’t use plt.show(), you could just create the plot (as you are doing) and save it with plt.savefig() then use visual.ImageStim() to show the plot.
I think the first solution is the best one. Right now I cannot provide any code example, but it should be fairly easy to do it.
I hope this helps.
Cheers
Emanuele

1 Like

This is an example of what you could do by using only psychopy. It draws colored bars and two axis.
Keep in mind the once you obtain the list with your results (performance) you should scale them in a way that they fit pixel size that you need. In the following example: results = [1,1.4,1.3,1.6] i just multiplied them by 100 pixels to fit the size of the plot.

from psychopy import visual, event
import numpy as np

mywin = visual.Window(size=[800, 600], units='pix')

def feedback(results, col = ['red','blue','green', 'grey'], w=80.0):

	''' w = width of a bar (80 pix by default)
	    col = must have the same length of results
	    results = list of your results 
	'''
	if len(col) != len(results):
		raise TypeError("results and col must have the same length")

	tot_space = w*len(results) + (w/len(results)) # total space (bars + space between bars)
	position = np.linspace(-(tot_space/2), (tot_space/2), len(results)) # position of each bar
	axis_dist = w*1.5 # just to allow a bit of distance between he y axis and the first bar

	if tot_space + (axis_dist*2) > mywin.size[0]:
		raise TypeError("Bar width is too big for the window size")
			

	mybarplot = [visual.Rect(mywin,
		units='pix',
	        width=w, 
		height=iplot,
		pos=[position[i], iplot/2],
		lineWidth=1,  
		lineColor='white',
		lineColorSpace='rgb', 
		fillColor=col[i], 
		fillColorSpace='rgb') 
		for i, iplot in enumerate(results)]
	x_axis = visual.Line(mywin, 
			start=(-((tot_space+axis_dist)/2), 0),
			end=((tot_space+axis_dist)/2, 0),
			lineWidth = 1.5,
			lineColor = 'white',
			lineColorSpace='rgb',
			units='pix')
	y_axis =  visual.Line(mywin, 
			start=(-((tot_space+axis_dist)/2), 0), 
			end=(-((tot_space+axis_dist)/2), (tot_space+axis_dist)/2),
			lineWidth = 1.5,
			lineColor = 'white',
			lineColorSpace='rgb',
			units='pix')
	return mybarplot, x_axis, y_axis

results = np.array([1, 1.3, 1.4, 1.6]) *100 # scale the results 

# call the function

mybarplot, x_axis, y_axis = feedback(results)

# draw everything 

while event.getKeys() != ['escape']: # press escape to end the loop
	for bar in mybarplot:
		bar.draw()
	x_axis.draw()
	y_axis.draw()
	mywin.flip()

I hope the example helps you.
But definetly using matplotlib is a faster solution.
Cheers

Emanuele

3 Likes

For a little more info - make sure you use savefig to save a format that PsychoPy can then read (png would be best; pdf, svg will definitely fail)

4 Likes

Went with Matplotlib in the end (saving the image and then using ImageStim). Thank you for both suggestions. Very helpful.