Using Python: 3.6.13 and Psychopy 2021.2.3:
I’ve been trying to code a cancellation task in which the participants must put in a decent amount of effort even if it is ‘easy’. In order to "cancel’ the stimuli I want participants to click on the object and have it “disappear” by changing the opacity to 0. The aim of this task is to get participants to ‘work’ for a reward that they can use in the main task.
I have run into several issues regarding dropped frames due to how long it takes to draw many (300 stimuli, in my case).
My first two attempts were to utilize
visual.ShapeStim, I created a list of stimuli and then appended each stimulus component to that list to draw from later.
for stimNo in range(elemMax): elements.append(visual.TextStim(win = win, name = 'element'+str(stimNo), text = 'T', font = 'Arial', height = misc.deg2pix(params['STIM']['textHeight']['value'], monitor), pos = (0,0), wrapWidth = None, ori = 0, color = "white")) #Inbetween code before trial starts running Experiment loop starts here: trialClock.reset() while frame < 60: #This is the individual loop for each trial for stim in elements: stim.draw() for stim in elements: if stim.opacity == 1: if mouse.isPressedIn(stim, buttons=): stim.color = 'gray' stim.setOpacity(0) win.flip() frame += 1 #After a 'space' press break from the loop and reset the opacities to 1 and colours to white #This happens outside of the individual trial loop, but also even omitting this code i still get the dropped frames
ShapeStim implementation (The draw code is the same as TextStim so I have omitted it):
Tee = [(-0.1, -0.1), (0.1, -0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.3), (-0.2, 0.3), (-0.2, 0.2), (-0.1, 0.2)] for Idx in range(elemMax): elements.append(visual.ShapeStim(win = win, vertices = Tee, fillColor = 'white', size = 100, pos = (0,0)))
Both of the above implementations take 150ms - 200ms to draw the stimuli, which has the consequence of 9-12 dropped frames per flip. I also tried a version in which instead of explicitly calling .
draw() I used the
.setAutoDraw(True) method so I could change attributes without having to explicitly redraw them in a loop, which didn’t make a difference in performance unfortunately.
I had a brief attempt at doing this with the
ElementArrayStim component, where i created a T-like texture as shown below:
x = visual.ElementArrayStim(win = win, nElements = 300, fieldShape = 'sqr', elementMask = None, xys = positions, oris = 90, elementTex = array, sizes = 40) while frame < 60*5: #5seconds x.draw() win.flip() frame += 1
Which gets the job done by drawing the 300 stimuli without dropping frames. But from my understanding, these stimuli do not have a
.contains() method which makes it hard to make them interactive. At least for my purposes of changing their opacity and then changing it back due to a mouse click.
I was wondering if others had any advice on whether
ElementArrayStim is the way to go, or if there is a more efficient way to work with the previously mentioned components (or others that will achieve the same goal – I did find that
visual.GratingStim had better performance only dropping 3-4 frames per flip).
Happy to provide more context if necessary, through this troubleshooting process I was wondering if perhaps I’m hitting either a software or hardware limitation so any advice there would be great as well.
psychopy.info.RunTimeInfo() doesn’t give me any causes for concern and my PC specs are CPU: I7-6850K, GPU: NVIDIA GTX1080.