psychopy.org | Reference | Downloads | Github

End routine only after correct response

Hello!

I have what should be a simple problem in my eyes but I can’t seem to figure out a solution which works. I am doing a simple reaction time task and want a participant to choose which position of four shapes on a screen is filled-in as fast as they can. I want to record the time to the correct button press. I am running v3.1.2 on Win10.

In the builder my keyboard response (resp) is set to store all and not to force end of routine. I have added a code component to occur each frame:

if resp.corr:
    continueRoutine = False

This successfully ends each routine in which a correct choice was made, however if an incorrect choice was made, the program ceases to respond to any of my accepted inputs, either correct or incorrect, only ‘esc’ works. I am trying to figure out why this is happening, and of course want the program to continue accepting responses until the correct key is pressed, which will be logged along with reaction time.

Thank you!

I think the issue here is due to storing multiple responses: Builder’s built-in check to see if a response is correct will fail after the first keypress, because it will be comparing a single specified response (coming from a column in your conditions file) with a list of multiple collected responses, which will necessarily be unequal.

So I think you might need to alter your code snippet to explicitly check one element of the list of responses vs the variable containing the correct response, rather than checking the resp.corr value that Builder creates for you. We can do this by indexing the list of stored keypresses to get a specific value. I can’t remember which way this list grows: you’ll either need to use an index of -1 (Python shorthand for “the last element of the list”, or, less likely, item 0 (the first item in the list).

e.g. something like:

if resp.keys[-1] == your_condition_file_column_name:
    continueRoutine = False

But if this wasn’t the first response, then the value of resp.corr that will be stored in the data will be False, so you might want to override that just in case:

if resp.keys[-1] == your_condition_file_column_name:
    resp.corr = True
    continueRoutine = False

Now you might end up with a situation where a person never pushes the correct key, so for completeness, you could build in some logic to end the trial after some number of attempts, e.g:

if resp.keys[-1] == your_condition_file_column_name:
    resp.corr = True
    continueRoutine = False
elif len(resp.keys) == 5:   # give up after 5 attempts.
    continueRoutine = False # don't need to override resp.corr in this case

Untested, so let us know if that helps.

Thanks Michael.

I just tried the last block of code and got an index out of range error on both resp.keys[-1] and resp.keys[0].

Couple clarification questions that I cant find the answers to elsewhere!: What does resp.keys() return? This method isn’t listed in the PsychoPy API to my knowledge. A list of keys entered perhaps, but from what time frame or from what part of the program? How is it different from resp.getKeys()? Does your solution loop through the list of responses from resp.keys (I was thinking this could be a solution, checking each for correctness as the list grows)? Perhaps it loops because of the while loop it’s contained within?

Thanks so much!

OK, that list will be empty when the routine first starts and so any attempt to index will fail unless it contains at least one entry. So we should insert an additional check in the code (there are more concise ways to do this but I’m being explicit here to show that we are checking that there is at least one entry in the list of keys):

if len(resp.keys) > 0 and resp.keys[-1] == your_condition_file_column_name:
    resp.corr = True
    continueRoutine = False

The keyboard API is brand-new, and is replacing the old PsychoPy event module (and I’m still getting used to it myself). Its keys attribute is defined when a keyboard is created as simply an empty list:

It doesn’t really appear in the API after that: you can simply store keys there. This is something that the Builder-generated code does for you: simply search in a Builder-generated script for lines containing .keys to see how it is used.

No, we are just checking once per screen refresh to see what the latest key press is and take action accordingly. The automatically-generated Builder code is already doing the actual checking and storing of new keypresses for us: we are just monitoring the result. And we are only checking the latest response: there is no need to loop through the list, as we should always get to see each response as it arrives (unless someone does something like push two buttons near-simultaneously, which could cause issues, as we would check only one of them).

If that is a problem, you could change the code again like this:

if len(resp.keys) > 0 and your_condition_file_column_name in resp.keys:
    resp.corr = True
    continueRoutine = False

i.e. by using in, you are checking all entries of the list on every occasion, which is a little inefficient but will prevent issues with someone mashing multiple keys at once.

Yes, the code in the “each frame” tab runs once every screen refresh. We effectively get embedded within that overarching loop for free.

Thanks Michael!

I put the following in run each frame:

if len(resp.keys) > 0 and resp.keys[-1] == corrAns:
    resp.corr = True
    continueRoutine = False
    
elif len(resp.keys) == 5:   # give up after 5 attempts.
    continueRoutine = False # don't need to override resp.corr in this case

It doesn’t run the first if statement and only ends the routine when I reach 5 responses (tested by adding some calls to print). Interestingly, removing the and statement at the top of the first if statement gives me a syntax error, where it doesn’t know what to do with resp.keys, it seems. I get the same behaviour when I use this as the first line instead:

if len(resp.keys) > 0 and corrAns in resp.keys:

Try inserting some temporary debugging statements before the code, to track why that first if never evaluates to True:

print(len(resp.keys))
print(resp.keys[-1])
print(resp.keys[-1] == corrAns)
print(len(resp.keys) > 0 and resp.keys[-1] == corrAns)
print(`\n`) # insert a blank row because there will be a stream of output produced
print(len(resp.keys))
print(resp.keys[-1])
print(resp.keys[-1] == corrAns)
print(len(resp.keys) > 0 and resp.keys[-1] == corrAns)
print('\n') # insert a blank row because there will be a stream of output produced


if len(resp.keys) > 0 and resp.keys[-1] == corrAns:
    resp.corr = True
    continueRoutine = False
    
elif len(resp.keys) == 5:   # give up after 5 attempts.
    continueRoutine = False # don't need to override resp.corr in this case

As you suggested, my code in “each frame” as above. I’m assuming you meant ’ instead of `, so I replaced those surrounding the /n.

This returns a list index out of range error at print(resp.keys[1]) as soon as I start the routine. I tried commenting out the resp.keys[-1] lines to see what the first and fourth print calls would return and it made my experiment window completely unresponsive where I had to end the task.

if len(resp.keys) > 0:
    print(len(resp.keys), resp.keys[-1], resp.keys[-1] == corrAns, len(resp.keys) > 0 and resp.keys[-1] == corrAns) 

And don’t wait around to press your keys, because we really shouldn’t be attempting to print output like this at such a high rate.

I hit the ‘right’ button 20 times. The correct ans (corrAns) should have switched from left to right during that time but it didn’t seem to.

1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
5 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
5 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
5 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
1 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
2 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
3 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
4 right False False
5 right False False

I added a print (corrAns) in there as well, and got this for again pressing ‘right’ 20 times.

1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
5 right ['right'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
5 right ['left'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
1 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
2 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
3 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
4 right ['right'] False False
5 right ['right'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
1 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
2 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
3 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
4 right ['left'] False False
5 right ['left'] False False

It looks like the ‘right’ != [‘right’]. So I changed:
if len(resp.keys) > 0 and resp.keys[-1] == corrAns:
to
if len(resp.keys) > 0 and [resp.keys[-1]] == corrAns:

Now the program responds to a single correct key press by ending the routine! And will give 5 attempts at choosing the correct answer when the initial answer is wrong! Thanks.

I’ve discovered another issue though, sometimes it takes TWO responses for the program to flip the screen to the next stimulus (I don’t know if that’s the correct usage of ‘flip’!).

Thanks for everything, Michael.

Well done to sort this out. I guess the issue is that your corrAns variable is how becoming list (of size one), rather than single values. Maybe your conditions file wraps the fries in square brackets, or it gets converted to a list somehow else along the way?