psychopy.org | Reference | Downloads | Github

Defining correct answer based on variable stimuli

I need to define correct/incorrect responses both for feedback purposes, and for storing data in the output file. My task is a visual search task where participants have to click on targets, and then press Done. There are between 0 and 3 targets in a display. I do not know how to define correct/incorrect responses, as they come from the condition file and different trials have different numbers of targets. For a response to be correct, all targets have to be clicked on (order doesn’t matter) before hitting Done.

For the practice trials, there is 1 routine between the search display and the feedback display (pictured below), so I’m not sure how to do this.
Flow

In my condition file, I have identified the Target position(s), such that the names are the same as the image names in the routine. Here is a snapshot of the Targets in the condition file:
ConditionFile
Where it says “Stim17”, this is how I named the images in Builder (below).

One problem is that there is no “Stim0”. I do not know the best way to identify target absent in the condition file. Do I just leave that field blank?

For the first row of the condition file, where there is 1 target present I need the feedback to be correct if the participant clicks on Stim17 and then clicks Done. If they click anything else (even if they clicked Stim17), it is incorrect.

For the second row, it would be they need to click Stim 30 and Stim 24, then Done to be correct.

I have looked at setting feedback like in the Demos, but I don’t know how to define correct and incorrect in this case, especially since the Feedback routine isn’t directly after the search display routine.

Currently, I have the mouse response record all clicks, so my output file shows every stimuli they clicked on (i.e. [‘Stim24’, ‘Stim30’, ‘DoneRectangle’]), where DoneRectangle is the Done button and forces the routine to end when clicked.

I have not figured this out at all, but I’m thinking that it might need to be something along these lines (this is not in proper code format at all, just my thoughts):

Begin Experiment: (this is from the feedback demo; so far I have the experiment sent up this way)
msg=’ ’

Begin routine:
If TPos1= “” and TPos2=“Stim0” and TPos3=“Stim0” and mouseclick = TPos1
msg = “Correct”
elif TPos1= “” and TPos2= “” and TPos3=“Stim0” and mouseclick = TPos1 and TPos2
msg = “Correct”
elif TPos1= “” and TPos2= “” and TPos3= “” and mouseclick = TPos1 and TPos2 and TPos3
msg = “Correct”
elif TPos1=“Stim0” and TPos2=“Stim0” and TPos3=“Stim0” and not mouseclick
msg = “Correct”
else
msg = “Incorrect”

Basically, if the mouseclick is on the same stimuli name as the Excel file (labeled TPos1, TPos2, and TPos3), then it should be marked Correct (order doesn’t matter) and any additional clicks are wrong. Everyone needs to click Done on every trial, even if there are no targets, so I’m not sure if a mouseclick on Done needs to be recorded as well for a trial to be marked Correct.

Example: TPos1 = Stim17, TPos2 = Stim23, TPos3 = Stim0 (i.e. no target present)
Mouseclicks on Stim17, Stim23, and Done is correct
Mouseclicks on Stim16, Stim23, and Done is incorrect

You’re definitely on the right lines!

I think one obstacle will be that, in the conditions file, those object names (stim0, stim1, etc.) will be interpreted as strings rather than as handles. One way around this is to create a dict at the beginning of the experiment, linking the keys (strings) to handles (the stimulus objects themselves).

stimuli = {
    'stim0': stim0,
    'stim1': stim1,
    'stim2': stim2,
    etc.
}

Meaning you can access the stimulus object by referring to stimuli[TPos1] rather than by name. This may seem trivial, but to Python it’s the difference between asking for the stimulus called stim0 and asking for the characters s, t, i, m, and 0. Think of Python as a really annoyingly pedantic friend.

Once you have this dict, what you’re looking for is mouse.isPressedIn(object): this will check whether a mouse click collected via the component mouse (you can name it whatever you like, so long as you use that name in place of mouse) is on the component object. So in your case:

if mouse.isPressedIn(stimuli[TPos1]) \
        or mouse.isPressedIn(stimuli[TPos2]) \
        or mouse.isPressedIn(stimuli[TPos3]):
    msg = "Correct"
else:
    msg = "Incorrect"

Then just add another if statement for the done button:

if mouse.isPressedIn(done):
    trial.isFinished =True

You can also just use the eval() function to evaluate a string variable to an object, so if the current value of Tpos1 was the string 'stim17', eval(Tpos1) would refer to the object named stim17, not the string of characters 'stim17'.

1 Like

Thanks for the replies! I have a column in my conditions file that state the number of targets present on a trial (0,1,2,3) so what I ended up going with is:

if TPresence==0 and MouseResponse.clicked_name[0]==Finished:
    msg="Correct"
elif TPresence==1 and MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==Finished:
    msg="Correct"
elif TPresence==2 and (MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==TPos2 and MouseResponse.clicked_name[2]==Finished) or (MouseResponse.clicked_name[0]==TPos2 and MouseResponse.clicked_name[1]==TPos1 and MouseResponse.clicked_name[2]==Finished):
    msg="Correct"
elif TPresence==3 and (MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==TPos2 and MouseResponse.clicked_name[2]==TPos3 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==TPos3 and MouseResponse.clicked_name[2]==TPos2 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos2 and MouseResponse.clicked_name[1]==TPos1 and MouseResponse.clicked_name[2]==TPos3 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos2 and MouseResponse.clicked_name[1]==TPos3 and MouseResponse.clicked_name[2]==TPos1 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos3 and MouseResponse.clicked_name[1]==TPos2 and MouseResponse.clicked_name[2]==TPos1 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos3 and MouseResponse.clicked_name[1]==TPos1 and MouseResponse.clicked_name[2]==TPos2 and MouseResponse.clicked_name[3]==Finished):
    msg="Correct"
else:
    msg="Incorrect"

I don’t know if it’s the most elegant solution, but since all targets have to be clicked to be correct, but order doesn’t matter, it’s working.

The only problem is that i know mouse.clicked_name and mouse.isPressedIn are not valid arguments in javascript and therefore won’t work online. Is there a simple(ish) solution for this? I’ve looked through some of the other threads on this, but I haven’t seen anything that appears to work/is easy to implement in this case.

I’m surprised as the mouse component has all the same calls in JS as in Python - it may be an issue with autoJS compiling it. Could you post the full code you’re trying to translate?

I’m trying to translate the code above (re-copied here for convenience):

if TPresence==0 and MouseResponse.clicked_name[0]==Finished:
    msg="Correct"
elif TPresence==1 and MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==Finished:
    msg="Correct"
elif TPresence==2 and (MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==TPos2 and MouseResponse.clicked_name[2]==Finished) or (MouseResponse.clicked_name[0]==TPos2 and MouseResponse.clicked_name[1]==TPos1 and MouseResponse.clicked_name[2]==Finished):
    msg="Correct"
elif TPresence==3 and (MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==TPos2 and MouseResponse.clicked_name[2]==TPos3 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos1 and MouseResponse.clicked_name[1]==TPos3 and MouseResponse.clicked_name[2]==TPos2 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos2 and MouseResponse.clicked_name[1]==TPos1 and MouseResponse.clicked_name[2]==TPos3 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos2 and MouseResponse.clicked_name[1]==TPos3 and MouseResponse.clicked_name[2]==TPos1 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos3 and MouseResponse.clicked_name[1]==TPos2 and MouseResponse.clicked_name[2]==TPos1 and MouseResponse.clicked_name[3]==Finished) or (MouseResponse.clicked_name[0]==TPos3 and MouseResponse.clicked_name[1]==TPos1 and MouseResponse.clicked_name[2]==TPos2 and MouseResponse.clicked_name[3]==Finished):
    msg="Correct"
else:
    msg="Incorrect"

This is how it is auto-translated:

if (((TPresence === 0) && (MouseResponse.clicked_name[0] === Finished))) {
    msg = "Correct";
} else {
    if ((((TPresence === 1) && (MouseResponse.clicked_name[0] === TPos1)) && (MouseResponse.clicked_name[1] === Finished))) {
        msg = "Correct";
    } else {
        if ((((TPresence === 2) && (((MouseResponse.clicked_name[0] === TPos1) && (MouseResponse.clicked_name[1] === TPos2)) && (MouseResponse.clicked_name[2] === Finished))) || (((MouseResponse.clicked_name[0] === TPos2) && (MouseResponse.clicked_name[1] === TPos1)) && (MouseResponse.clicked_name[2] === Finished)))) {
            msg = "Correct";
        } else {
            if ((((((((TPresence === 3) && ((((MouseResponse.clicked_name[0] === TPos1) && (MouseResponse.clicked_name[1] === TPos2)) && (MouseResponse.clicked_name[2] === TPos3)) && (MouseResponse.clicked_name[3] === Finished))) || ((((MouseResponse.clicked_name[0] === TPos1) && (MouseResponse.clicked_name[1] === TPos3)) && (MouseResponse.clicked_name[2] === TPos2)) && (MouseResponse.clicked_name[3] === Finished))) || ((((MouseResponse.clicked_name[0] === TPos2) && (MouseResponse.clicked_name[1] === TPos1)) && (MouseResponse.clicked_name[2] === TPos3)) && (MouseResponse.clicked_name[3] === Finished))) || ((((MouseResponse.clicked_name[0] === TPos2) && (MouseResponse.clicked_name[1] === TPos3)) && (MouseResponse.clicked_name[2] === TPos1)) && (MouseResponse.clicked_name[3] === Finished))) || ((((MouseResponse.clicked_name[0] === TPos3) && (MouseResponse.clicked_name[1] === TPos2)) && (MouseResponse.clicked_name[2] === TPos1)) && (MouseResponse.clicked_name[3] === Finished))) || ((((MouseResponse.clicked_name[0] === TPos3) && (MouseResponse.clicked_name[1] === TPos1)) && (MouseResponse.clicked_name[2] === TPos2)) && (MouseResponse.clicked_name[3] === Finished)))) {
                msg = "Correct";
            } else {
                msg = "Incorrect";
            }
        }
    }
}

This code is also having problems:

if MouseResponse.isPressedIn(DoneRectangle, buttons=[0]):
    continueRoutine=False

It is auto-translated as:

if (MouseResponse.isPressedIn(DoneRectangle, {"buttons": [0]})) {
    continueRoutine = false;
}

My knowledge of JavaScript is pretty limited but that code looks syntactically correct at least… It could be that MouseResponse hasn’t initialised properly in JavaScript - it should have the same methods as in Python so clicked_name and isPressedIn should still work. A more experienced JavaScript programmer might spot something I’ve missed though!

I have attempted to use the solution found in other posts, but I’m getting an error. The JS code I’m using is below, where DoneRectangle is the name of my shape stim, and MouseResponse is the name of my mouse object.

if (DoneRectangle.contains(MouseResponse) && MouseResponse.getPressed()[0] === 1) {
   continueRoutine = false;
}

The error I get is
TypeError: Cannot read property ‘map’ of undefined

If I attempt to use the original code of

if (object.contains(mouse) && mouse.getPressed()[0] === 1) {
   continueRoutine = false;
}

I get an error that says that “mouse” is not defined. This makes sense to me because I don’t have a mouse component named “mouse”. When all I do is change “object” and “mouse” to what my components are called, the TypeError appears. Any suggestions??

Where are you defining your ShapeStim. It should be in a component or a Begin Experiment tab

Use AutoDraw to control its visibility as per my crib sheet

I don’t have my shape stim defined in code, it’s in the builder view. I have attached a picture of the routine where my stimuli and the code component are

Everything works fine offline, but not online

Got it. I think you need to add if t > 1: so you don’t check whether the mouse is in the shape before the shape is drawn.

@wakecarter I tried your suggestion, but the error still persists.

Try moving DoneRectangle to the top of the routine.

No change :frowning:

I have created a brand new program with just this part, and it seems to work fine (with t>3, as the stimuli appear after 3 seconds). I don’t know if something was wrong in the original program, but if I can’t get it to work I’ll just have to copy everything in to a new program I guess. But for now, I think we’re okay.