Code for keyboard response (signal detection theory)

Hi there,

I am working on a basic old new memory recognition task, and am having a hard time figuring out how to add columns to my output file to track participant responses. Rather than only tracking right and wrong responses, I want to add four columns to see if a participant got a “hit” (said the item was old when it was old), “miss” (said it was new when it was old), “correct rejection” (said it was new when it was new), and “false alarm” (said it was old when it was new). I also want to add a column called “no answer” for instances when the participant does not click anything at all.

In my Excel file that is fed into the routine, I have a column that marks whether the item is old or new, as well as one called “qp” (q for old, p for new) that is the same as the old new column, but just in the keys that I am using in my task for participants to respond. My current thought is that I could write code to compare the participants’ responses to the qp column, and mark it as a 1 in one of the four columns I described above. Here is the code I wrote to attempt to do this under “Begin Routine”:

if qp==key_resp.keys=='q':
    thisExp.addData('Hit',1)
    thisExp.addData('Miss',0)
    thisExp.addData('False_Alarm',0)
    thisExp.addData('Corr_Rej',0)
    thisExp.addData('No_Answer',0)

elif qp==key_resp.keys=='p':
    thisExp.addData('Hit',0)
    thisExp.addData('Miss',0)
    thisExp.addData('False_Alarm',0)
    thisExp.addData('Corr_Rej',1)
    thisExp.addData('No_Answer',0)

elif key_resp.keys=='q':
    thisExp.addData('Hit',0)
    thisExp.addData('Miss',0)
    thisExp.addData('False_Alarm',1)
    thisExp.addData('Corr_Rej',0)
    thisExp.addData('No_Answer',0)

elif key_resp.keys=='p':
    thisExp.addData('Hit',0)
    thisExp.addData('Miss',1)
    thisExp.addData('False_Alarm',0)
    thisExp.addData('Corr_Rej',0)
    thisExp.addData('No_Answer',0)

else:
    thisExp.addData('Hit',0)
    thisExp.addData('Miss',0)
    thisExp.addData('False_Alarm',0)
    thisExp.addData('Corr_Rej',0)
    thisExp.addData('No_Answer',1)

The problem I am having is that no matter what kind of response I give when I go through the trials, it will always be marked as “No_Answer”. I suspect there is something I need to change about my else statement but I am not sure.

If I have made any really obvious mistakes, please excuse me as I am new to PsychoPy and just coding in general! I have been exclusively working in the builder view, so only suggestions related to that would be greatly appreciated.

Thanks in advance!

Hi @Kate_Checknita, you will only get the “No_Answer” condition if all other conditions are False. There is not much context here to work with, but there may be a couple of things happening.

You are putting this code in the “Begin Routine” tab. If this is the routine that participants must respond to, then no responses will have been given, so your conditions will always be false. If this code goes in a Begin Routine tab in a routine that comes after the response routine, it should be ok.

Are you saving the first or last key in your keyboard component? If storing all responses, you will get a list when you call the .keys attribute of the keyboard, so your conditions will never be true because you are comparing a character to a list.

Have you given ‘q’ and ‘p’ as allowed keys in the keylist of the keyboard component (leaving keylist blank is also fine)?

David is right, that the location of the one might be important (i.e. if this code is on the same routine as the response is given, then it belongs in the “End routine” tab rather than the “begin routine” tab), and about whether key_resp.keys contains a list or a single value. But regardless, there are some issues with the boolean logic.

Note this sort of statement will always evaluate to False:

if qp==key_resp.keys=='q':

qp apparently contains either 'q' or 'p', while key_resp.keys=='q' must evaluate to either True or False. So you are comparing a one-letter string to a boolean True or False value. These can never be equal, so the result of the overall expression will always be False.

I suspect that what you want is actually something like:

if qp == 'q' and key_resp.keys == 'q':

Note that then you could record all of your data in just one step, by putting the logic inside the addData() function, avoiding the multiple if/then statements:

thisExp.addData('Hit', qp == 'q' and key_resp.keys == 'q')
thisExp.addData('Miss', qp == 'q' and key_resp.keys == 'p')
thisExp.addData('False_Alarm', qp == 'p' and key_resp.keys == 'q')
thisExp.addData('Corr_Rej', qp == 'p' and key_resp.keys == 'p')
thisExp.addData('No_Answer', len(key_resp.keys) == 0)

Note that each of those expressions above evaluates to either True or False. I’m not sure how PsychoPy saves that in the datafile (i.e. it might get converted to literal strings 'True' or 'False' or the equivalent boolean integer values 1 or 0). So, only if you need to, you could explicitly coerce them to the latter, e.g.

thisExp.addData('Hit', int(qp == 'q' and key_resp.keys == 'q'))

Thank you both so much for your help, I will try that and see what I get!

So I did what you suggested, and everything works perfectly except the ‘No_Answer’ line. When I run the program and don’t respond to the stimuli, PsychoPy gives an error that says “object type of ‘NoneType’ has no len”. Because I’m not completely clear with what the len function does, would you be able to explain to me what this error is telling me and how I can fix it?

The len() function gives the length of list (i.e. it counts how many elements are contained in that list). I was guessing that no response would yield an empty list (i.e. a list with a length of zero), but instead it seems that there isn’t a list there at all in that case, so it can’t have a length. Try this instead:

thisExp.addData('No_Answer', key_resp.keys is None)