Timing efficiency: win.flip() outside of a while loop

I am dynamically changing the shape of two ShapeStim objects using the following code:

cwd = os.path.dirname(__file__)
width, height = [1366, 768]
win = visual.Window(size = (width, height), fullscr = True, pos = (0,0), units = "norm", color = [-1,-1,-1])
event.Mouse(visible = False) 

trialLength = 30
timer = core.Clock()
text = visual.TextStim(win = win, text = '', height = 0.1, pos = (0,0), color="White")
image = visual.ImageStim(win = win, pos = (0,0), size=(2,2), image=os.path.join(cwd + '/Pictures/pic1.jpg'))
mask1 = visual.Rect(win=win, pos=(0.0,0), lineColor='Black', fillColor='Black')
mask2 = visual.Rect(win=win, pos=(0.3,0), lineColor='Black', fillColor='Black')

timer.reset()
image.setAutoDraw(True)
mask1.setAutoDraw(True)
mask2.setAutoDraw(True)

while timer.getTime() < trialLength:
    if 'escape' in event.getKeys(keyList=['escape']):
        core.quit()
    mask1.size = ((trialLength - timer.getTime())*.02,4)
    mask2.size = ((trialLength - timer.getTime())*.02,4)
    win.flip()
    
mask1.setAutoDraw(False)
mask2.setAutoDraw(False)
image.setAutoDraw(False)

What I am doing is gradually shrinking the size of the vertical rectangles until the end of the trial length, where an under-layed the picture is completely revealed.

I wanted to know if there is a way to better do this so that the win.flip() command occurs outside the while loop, which I worry will affect the timing (i.e create more lagging)?

Thank you for the help.

If you did that, then your stimuli would only be drawn once. There must be a win.flip() each time your stimuli are updated, or else those changes are never displayed.

Also, having win.flip() within your loop creates some natural breathing space for the computer: it “brakes” the loop so that an iteration only occurs once per screen refresh. That means the CPU has a bit of down time on each cycle to attend to housekeeping outside PsychoPy. If you have an unconstrained loop, it can potentially repeat millions of times per second, starving the CPU of time for any other competing activities. At some point, that will cause a lag, as the OS will unpredictably will leap in and seize control from PsychoPy to attend to urgent business, and that will cause timing issues.

Lastly, you aren’t really getting any value from autoDraw here. The code would actually be more concise if you delete those six lines and explicitly draw the stimuli, perhaps making it more clear why the flip needs to be where it is:

while timer.getTime() < trialLength:
    # check for escape:
    if 'escape' in event.getKeys(keyList=['escape']):
        core.quit()

    # update the stimuli:
    mask1.size = ((trialLength - timer.getTime())*.02,4)
    mask2.size = ((trialLength - timer.getTime())*.02,4)

    # draw the stimuli to the back buffer:
    image.draw()
    mask1.draw()
    mask2.draw()

    # flip the back buffer to the screen:
    win.flip()

Also note that you are calling the same function three times per iteration (timer.getTime()). That isn’t likely to be causing performance issues here, but it is good practice to just call functions like that once per iteration, and store the result in a variable. More time-expensive calls could cause performance issues so it is good to be in the habit of avoiding duplication where possible.

Hi Michael.

I realize now that the time lag is so small that it’s insignificant. Thank you for your suggestion regarding the autoDraw()