Mouse click record selections and end routine on final “okay

If this template helps then use it. If not then just delete and start from scratch.

OS
Mac OS 10.14
PsychoPy version
3.04
**Standard Standalone? **
Yes
What are you trying to achieve?:
First routine briefly flashes 4 letters from the alphabet. Second routine is a response screen displaying every letter of the alphabet. Participants use the mouse to select any and all letters they can recall from the previous screen then select an “okay” box to proceed to the next trial. I need to record which letters they click during this second routine and end the routine when they select “okay”
What did you try to make it work?:
I’ve tried to set the routine to end on valid click and put the stimuli as valid clicks but that obviously ends the routine after the first click. I’ve tried to not end routine on valid click and have it save any click and this does seem to do that however it will no longer proceed to the next trial when I click okay. Additionally, I’d like the letters they select on this screen to change color to indicate that their selection has been registered.

You are correct to de-select the “force end routine” setting, as that isn’t flexible enough for what you need. You will need to handle the response in code, so insert a code component in your routine, from the “custom components” panel. In its “begin routine” tab, put something like this:

# keep track of what/how many letters have been clicked:
clicked_letters = []

Then put something like this in the “each frame” tab so that clicks are monitored continuously throughout the trial:

if mouse.isPressedIn(your_okay_box_name) and len(clicked_letters) == 4:
    continueRoutine = False
else:
    # using your actual stimulus names, check each one for a click:
    for letter_stim in [letter01, letter02, ..., letter26]:
        # only respond if a letter has not already been clicked:
        if mouse.isPressedIn(letter_stim) and letter_stim.colour == 'black':
            letter_stim.colour = 'green'
            clicked_letters.append(letter_stim.text)

            if len(clicked_letters) == 4:
                # make the okay box look enabled
                your_okay_box_name.opacity = 1

Then something like this in the “end routine” tab to save the responses into four separate columns in your data file:

for i, letter in enumerate(clicked_letters):
    thisExp.addData('response_' + str(i), letter)

Give your text stimuli an initial colour (like black) and the okay box an initial opacity value of, say 0.5, and set each to “update every routine”. This allows them to be updated in code but then get re-set at the start of each trial.

That is extraordinarily helpful @Michael thank you very much

In this set up the colors aren’t changing when they’re clicked. Everything else is now working correctly. I’ve got a black background so my TextStim are white and I want it to be yellow when clicked. I’ve used the code provided and updated it to fit my code, but the color isn’t changing. I’ve got textstim named [AC, BC, CC, DC,…etc to ZC] their text is the corresponding letter so ‘A’,’B’,’C’…etc. color in the builder is set to white and in the code ‘white’. Do I need to update this to a $variable and define those colors? In the builder should it be set to set every repeat or frame instead of constant?

It should be set to “every repeat” so that the colour re-sets at the beginning of each trial to its default value that you specify. If it is set to “every frame”, it would keep updating with the default value 'white' you provide, which would immediately counteract the change applied in the code, so no change would be apparent. “constant” would mean that it should change in response to the code, but not get re-set at the start of each trial.

If it is still not changing, it would be worth temporarily inserting some debugging code, as it is possible that our comparison of the current stimulus colour is failing, as colours can be stored in multiple ways. e.g.:

for letter_stim in [letter01, letter02, ..., letter26]:
        # only respond if a letter has not already been clicked:
        if mouse.isPressedIn(letter_stim):
            print(letter_stim.colour)
            if letter_stim.colour == 'white':
                print('Changing to green')
                letter_stim.colour = 'green'

NB this code should not be kept in your production-ready experiment. Those print statements are expensive in terms of timing and performance.

EDIT: wait a moment, I just saw a typo in the original code (since amended), where I had letter_stim.colour == 'green' rather than letter_stim.colour = 'green'. That wouldn’t have actually changed anything (i.e. = assigns one thing to another, while == just compares them). I suspect the original code would work fine if you just change the == to = in that line, and ensure that the update fields are set to “every repeat”.

Continuing the discussion from Mouse click record selections and end routine on final “okay:

Hi Michael,

I am trying to do something similar, but I am asking people to recall lists of letters that vary in length from 3-7 letters. They would then respond by clicking the letters that were shown on a grid of 12 possible letters (4x3). How would I adapt that code so that it works with the varying letter length?

Compare the number of selected letters to the length of your target list (or string), rather than a fixed value:

if mouse.isPressedIn(your_okay_box_name) and len(clicked_letters) == len(your_target_variable):

Hey Michael,

Thanks for getting back to me. I guess I’m not totally sure how to make an Okay box so I’ll have to look into that. Can you explain what the target variable is supposed to be? I’m not experienced with python at all so I just want to make sure I understand what is going on.

Only you know what that is. i.e. from your post, you must have some sort of variable that contains the “lists of letters that vary in length from 3-7 letters”. Generally, people would put those words or strings of letters in a column in a conditions file (.xlsx or .csv) and link it to the loop controlling their trials. If none of that sounds familiar, then you need to watch this video to get the basics:

Gotcha. I know which variable you’re talking about. I limited the code to just the color changing portion for now and I can’t seem to get it to change the color even though I changed the color parameter to “Set Every Repeat”. Is there something I am missing? Here is the code I was trying to use.

for letter_stim in [F, H, J, K, L, N, P, Q, R, S, T, Y]:
        # only respond if a letter has not already been clicked:
        if wm_recall_resp.isPressedIn(letter_stim) and letter_stim.color == 'black':
            letter_stim.color == 'green'
            clicked_letters.append(letter_stim.text)

You are using == in letter_stim.color == 'green', when it should be =.

i.e. in Python = assigns a value to a name (which is what you want), while == compares one value to another. In this case, that line will simply evaluate to False (as it must currently be coloured black rather than green), and not actually do anything.

e.g. read the expressions this way:

a = b  # "make a equal b" (an action)
a == b # "a equals b" (a logical statement, which is either true or false)