Changing targets for mouse clicks

Hi, I am trying to achieve a seemingly simple thing. The core idea is that participant sees an array of symbols (here: A,B,C,D,E) and has to click on the in an order (for simplicity: alphabetic order), i.e., each “trial”, he/she has to click to a correct/valid symbol in the sequence.

I was trying to approach this issue using “Target” variable in the Clickable stimuli $ field, whereas “Target” is the column name in my excel file that defines the trial (loop). This column has 5 items, A to E in the required alphabetic sequence.

  • Primarily, I was hoping I would be able to change the “Target” = clickable stimuli on each trial according to a rule/seqience defined in my csv/excel file (in a generic way, not only for alphabetic sequences).

  • Secondarily, I would like to implement that when the participant clicks on a “non-target” item, PPy records this event (perhaps as Error) but does not move to another item in the sequence/csv.

Thank you very much!
Best,
M.

This is the simple “core” structure I would like to build on:

Win 10
PPy 3.2.4
Standard Standalone

Hi,

PsychoPy will interpret any values in condition files as literal values - e.g. the literal letter 'A', rather than the stimulus object called A. So you need to tell Python to interpret the variable as containing the name of an object, rather than as literal content. Fortunately Python is a dynamic language and allows you to do this via its eval() function. So in the “clickable stimuli” field, try putting this instead:

eval(Target)

Otherwise, I think you’re on track.

EDIT: I just saw the second part of your question… This will be a bit trickier. Instead, I think you will need to just list all clickable stimuli (i.e. A, B, C, D, E) in the clickable stimuli field.

Then you will need to have some custom code to check if the correct one has been clicked, and then end the routine. i.e. insert a code component (from the “custom” component panel).

In the “each frame” tab, put something like this:

if eval(Target) in mouse2.clicked_name:
    continueRoutine = False

Change “End routine on press” to be “Never”, since you are handling that yourself now in code, and don’t want the mouse component to end the routine automatically.

The variable mouse2.clicked_name in your data file should contain a list of clicked stimuli. On a correct trial, it will only contain the name specified in the Target variable. On others, it will include one or more other names, as well as the correct one.

1 Like

Thank you very much Michael, the eval() works nicely. Unfortunately, the second part for storing invalid clicks did not, somehow. Though I completely understand (how) it should work, even if I include the custom code (each frame) and change “End routine on press” to “Never”, the run is stuck on the first screen (trial), not storing anything… as though the clicking itself had no effect (the “Clickable stimuli” is filled correctly: A,B,C,D,E). Also tried to vary “Save mouse state”, but none of those worked out.

EDIT: Could this be not wokring because mouse2.clicked is a list? Thus, I have to somehow address the last element in the list?

EDIT2: Ok, I think I mannaged to make it work :slight_smile: but it is so anti-elegant :-1:


if len(mouse2.clicked_name) > 0:
    
    print(mouse2.clicked_name) # DEBUG
    print(len(mouse2.clicked_name)) # DEBUG
    print(mouse2.clicked_name[len(mouse2.clicked_name)-1]) # DEBUG
    
    if eval(Target) == eval(mouse2.clicked_name[len(mouse2.clicked_name)-1]):
        continueRoutine = False

I put you wrong with the second approach, because Builder just records a text representation of the stimulus name in the .clicked_name list, so you don’t need to use eval() at all here. Just this should suffice:

if Target in mouse2.clicked_name:
    continueRoutine = False

Because I suggested using eval() in this case, the check would always fail, as it would be comparing an actual stimulus object against a different type (a literal name). Removing eval() means we are comparing literal values again.

This is why we use the operator in: it checks the contents of the list to see if any entry matches. This should work even when the list is empty (which it should be initialised to at the start of the trial, provided you have placed some stimulus names in the “clickable stimuli” list).

So you don’t need to check a specific entry using an index number. But for future reference, if you ever want to access the last entry in a list, it can done simply by passing a negative index, like this:

mouse2.clicked_name[-1]

Using [-2] would give you the second to last entry, and so on.

1 Like

Awesome, many thanks! :slight_smile: