I need to present a large number of 5 to 7 letter words (~1000) in my experiment. On each trial, up to 4 words can be presented simultaneously at specific locations. I plan to put words in a txt file, and load them via np.loadtxt. I then plan to create 4 visual.TextStim objects (corresponding to each of the 4 possible locations), and call the setText method at the beginning of each trial to change text. I’ve read in the PsychoPy manual that it takes a long time to change the text. Is there a better strategy?
Your probably want to look into PsychoPy’s
These will handle reading in your conditions file, cycling through trials (randomising if required), and automatically saving the data file afterwards.
“A long time” means that it might exceed one screen refresh duration. That can be problematic for some time-critical designs, and in others, of no consequence at all.
If the timing is critical, but you stimulus display durations are of a reasonable duration, you can get around this by setting the text for the next trial during the current one (and preparing the very first one in advance). The
TrialHandlerhere may not be so useful for you, as it is concerned with current trial values, although you can access values from preceding or upcoming trials with the
Thank you! I plan to change the text during the fixation period, and present the word for 1000ms. If the setText function takes more than a frame, I may just increase the duration of my fixation period by one frame right?
Ahh, OK if you have a fixation period within the trial, then you are all set to go.
You shouldn’t increase the duration of the fixation period, as you don’t really know at this stage what delays you might experience with updating the text stimuli (this really needs to be measured on your particular system, and it might very well be variable from trial to trial).
I’d suggest that you draw your fixation stimulus, zero the trial timer, update the text stimulus, then start whatever timing/drawing loop system you need to control the duration of your fixation stimulus. i.e. you don’t have to be drawing on every frame: what ever is in the buffer will continue to be drawn until you change it. So however long the text updating takes, you’ll still be able to get back on schedule to keep your fixation stimulus displayed for the intended time (as long as that time is relatively long compared (realistically, anything more than 100 ms is probably going to be more than sufficient, although you really should be measuring the delays yourself to be sure)).
With this sort of scheme, any variable slop associated with updating the text stimulus is absorbed within the intended duration of the fixation stimulus.
Perhaps make a quick Builder experiment with a stimulus set to display for either a set amount of time, or a set number of refreshes, and see how the generated code handles those variations (and you can come up with a hybrid of both).
Thanks Michael! If I understand correctly, you are suggesting to do something like:
> fixation.draw()#draw fixation > fixation_clock = core.Clock() > stimulus.setText('blabla') > win.flip() > fixation_clock.reset() > while True: > t = fixation_clock.getTime() > if t >0.25: > break > stimulus.draw() > win.flip() > #then start clock to measure RT...
Before my fixation, there’s a pretty long inter-trial interval (1 sc). So if the setText function introduces any delay, it will load into the ITI interval right? I am sorry if I missed something!
More like the code below. Draw the fixation, then update the text while it is on screen, then shift to showing the pre-prepared text stimulus.
But if you have an ITI period before hand, just do it in there instead, and you can do a frame counting loop for each of the fixation and text stimuli, which is easier and potentially more precise.
trial_clock = core.Clock() # good habit to just create objects once rt_clock = core.Clock() for trial in trials: rt_clock_started = False fixation.draw() # draw fixation win.flip() trial_clock.reset() # t = 0 here stimulus.setText('blabla') # might take some variable time # but occurs while fixation is on screen while True: t = trial_clock.getTime() if t < 0.25 - 0.0167: # one 60 Hz screen refresh period fixation.draw() # draw fixation up to 250 ms elif: t < 1.0 - 0.0167: # draw stimulus for, say 750 ms if not rt_clock_started: # start timing RT rt_clock.reset() rt_clock_started = true() if event.getKeys(): # check for response rt = t stimulus.draw() # draw the text else: break win.flip() # show whatever stimulus was drawn