I have a response stimuli which should last 10 seconds to allow for key responses. But once either a left or right key is pressed, a border (red square) should show up at left/right position based on the key press. After .5 seconds of the first key press, this routine should end to proceed to the next one in a loop.
I’ve figured out how to draw the border and let it present for .5 seconds. But the rest of the routine components just stay there until the end of 10 seconds.
I’ve added the following code under the each frame section as the last component but it doesn’t change the experiment:
if len(response.keys)>0:
timer = core.CountdownTimer(0.5)
while not timer.getTime()>0:
continueRoutine=FALSE
(I didn’t click force end of routine on the response component)
Hi, you should never use your own timing loops within Builder code. Builder is structured inherently around a drawing and event loop that runs in time with your screen refresh cycle. So no code should go in the “each frame” tab that will take longer than one screen refresh to complete.
The easiest solution to this sort of set-up is to split your trial across two routines. End the first routine either on a keypress or when 10 s has elapsed. The second routine has the same stimuli (so the subject won’t notice the transition), except for displaying the red border. Set the stimuli in this routine to all just last for 0.5 s. You will need code in the second routine’s “begin routine” tab to skip the routine if no key was pressed, or to determine where the red border should be drawn if a key was pressed.
Thank you so much, Michael.
I put the code and the border to a new routine, but it seems like there is some problem either with the code itself or where the code should be put. Specifically, the position of border is not defined at the beginning of the second routine (name “border” is not defined). The border component is placed as the last component in the routine and the position of it is defined as [0,0].
Here is my code in the begin routine tab:
if len(response.keys)>0:
for key in response.keys:
if response.keys[0] ==('f'):
border.pos = [-0.3, 0]
win.flip()
elif response.keys[0] == ('j'):
border.pos = [0.3, 0]
win.flip()
else:
border.opacity= 0
win.flip()
else:
break
Is there any problem with that?
The name “border” undefined was a silly mistake as I changed the name of the component. But after simplifying my code to make the border appear after key press, it still has the issue of not being able to break the second routine if no key was pressed.
Here is my updated code:
if len(response.keys)>0:
if response.keys[0] ==('f'):
border.pos = [-0.3, 0]
elif response.keys[0] == ('j'):
border.pos = [0.3, 0]
else:
border.opacity= 0
else:
break
Here is the error message I get:
Can anyone help me with that?
Thanks,
Mingjia
if response.keys: # if the list is not empty
border.opacity = 1 # needs to be reset on each trial
if response.keys[0] == ('f'):
border.pos = [-0.3, 0]
elif response.keys[0] == ('j'):
border.pos = [0.3, 0]
else:
border.opacity = 0
else:
continueRoutine = False
- Don’t use ‘break’. Remember this code is embedded amongst lots of other code, so you don’t necessarily know what that will do. Instead, use the recognised way to end a routine:
continueRoutine = False
.
- The NoneType error worries me a bit: hopefully the new first line in the code above might help, otherwise there is some other issue going on.
Thanks, I really appreciate your effort into solving my problem. And for future reference, can you tell me: 1. what is the difference between len(response.keys)>0 and response.keys as a boolean value? 2. Can code override the properties of text/shape/image components as defined in the dialogue box while keeping other properties unchanged, so that I can always make some properties change in a single routine by defining them at the beginning of the routine?
If response.keys
doesn’t exist for some reason (i.e. it is None
), then calling a function like len()
on it will cause an error.
if response.keys:
is a safer test, as it will return False if response.keys
doesn’t exist, rather than causing an error
On the other hand, if response.keys
does exist and is a list, if response.keys:
will return False
if the list is empty, True
if it contains any number of entries.
So this test is safer, and does more for you.
For properties you want to override in code, set them to be “constant” in their component dialog box. That way, you can change them in code whenever needed and they won’t get changed back (i.e. Builder will set that value once at the beginning of the experiment and then thinks it job is done, and so will never revisit it). Any other properties can be changed on every routine, or even every screen refresh, as desired, using the normal means (e.g. variables defined in your conditions file).