Selecting images on screen using mouse in builder view

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

OS (e.g. Win10):
PsychoPy version (e.g. 1.84.x):
Standard Standalone? (y/n) If not then what?:
What are you trying to achieve?:
Dear all
conditions.xlsx (10.8 KB)

I am starting to design one of my very simple experiments using
psychopy builder view (I have used this before, so even though I am not
good in programming I can understand simple codes and implement them by
‘add custom code’).
Here is what I need:

  1. I have six pictures
    appearing on screen until one of them is touched, that completes a
    trial. Ideally I am going to run this task using a touch screen. I
    understand if I
    design it using mouse click (right by default), I can manage to make it
    work in touch screen.
  2. I have added a ‘Conditions’ file in my
    loop. The ‘condition.xlsx’ file (also attached here) has seven columns, i.e., on every trial
    the picture from the first row is displayed until a picture is selected
    as a response. The eighth column of the ‘condition.xlsx’ is the
    corrAns stating which picture is the correct response for that
    particular trial.
  3. I have set up ‘Mouse’ as a response mode and now it correctly runs through each row and displays the trials properly.

My question…

How do I write my ‘code’ such that if the ‘corrAns’ is touched it
gives a score of ‘1’ else it gives the score of ‘0’. I want the data
sheet to record the responses as ‘1’ or ‘0’. Note, the trial ends
irrespective of accuracy of the response and no feedback is required.
And also can the program print the ‘total response correct’ after the
completion of the task. Lets say the task has 30 trials.
Thanks in advance

What specifically went wrong when you tried that?:
Include pasted full error message if possible. “That didn’t work” is not enough information.

Hi. At the moment, your “correct answer” column in the conditions file is actually a location (i.e. [-0.5, -0.5]), and seems to be constant across trials. I would have thought that you would actually want it to be one of the image file names? Actually, the conditions file doesn’t quite match your description, having seven columns for image filenames and a column labelled corrAns. Could you make the file match the description, and then we can have a go at giving you an answer (which will be some relatively simple code to insert).

Hi Michael
Thanks for your response. Now I have attached the correct ‘conditions’ file. conditions.xlsx (10.8 KB)

The builder program I created is here.
On everyRCM, mouse.psyexp (17.9 KB)

You can find the pictures to try the program here…

It would be great if you could tell me what to add in ‘code’ section so I get the score of ‘1’ (also I want its RT to be recorded, which I think it does by default) if I get the ‘CorrAns’ selected or else zero.
I would also like the program to print out and display the total number of correct responses after the test.

Thanks for your time in fixing this.

You will want something like this in the Each frame tab of a code component:

# cycle through the stimulus components by name:
for stimulus in [ Q, C1, C2, C3, C4, C5, C6]:

    # check if the mouse is pressed within the current one:
    if mouse.isPressedIn(stimulus):

        # Yes, so store the reaction time in the data:
        thisExp.addData('RT', t)

        # check if the stimulus' image filename matches the correct answer:
        if stimulus.image == eval(corrAns):
             thisExp.addData('correct', 'True')
        else:
             thisExp.addData('correct', 'False')

        # end the trial once done here:
        continueRoutine = False

        # stop any further checking:
        break

The eval(corrAns) is necessary because your corrAns variable doesn’t directly contain the name of the image file but instead the name of the variable which contains that image filename, and so that string needs to be evaluated to return the contents of the variable. If your corrAns variable contained the name of the image file directly (e.g. A2C1.jpg), then you could simply do if stimulus.image == corrAns:

1 Like

Hi Michael
Brilliant. Works like charm!!!. Thanks for this.
I still have 2 problems. one major and one minor.

Major problem: Now irrespective of where in the screen the mouse is clicked, it records the ‘x,y’ coordinates (and if it is in stimulus it scores) and moves to next trial. It would be better if it ends the trial if the mouse is clicked in the stimuli C1 to C6 only (not even on the Q) and then it can score it as ‘TRUE’, ‘FALSE’ (which I altered to ‘1’ and ‘0’ for ease of scoring).

Could you suggest me how to do that in the code section?

Minor problem: It would be great it displays the number of ‘1s’ in the ‘correct/score’ column on the ‘screen’ after the task is complete. I want the color of the number printed in black (because I am going to make the screen white). I just want to see the number (note: not as a feedback to the participant). So just printing total correct response will do.
Looking forward to hearing from you.

Thanks again

This is because you have the mouse component set to “End routine on press”. You want to determine the end of the routine completely in code, so you need to uncheck that setting. That way, clicks that aren’t on one of the stimuli will have no effect, as the code will end the routine only if a stimulus is clicked.

You just need to keep track of valid responses as they occur. In the Begin Experiment tab of the code component, insert this:

# initialise a counter variable:
correct_responses = 0

Then amend the Each Frame code to look like this:

# cycle through the stimulus components by name:
for stimulus in [ C1, C2, C3, C4, C5, C6]:

# check if the mouse is pressed within the current one:
if mouse.isPressedIn(stimulus):

    # Yes, so store the reaction time in the data:
    thisExp.addData('RT', t)

    # check if the stimulus' image filename matches the correct answer:
    if stimulus.image == eval(corrAns):
        thisExp.addData('correct', 1)
        correct_responses = correct_responses + 1
    else:
         thisExp.addData('correct', 0)

    # end the trial once done here:
    continueRoutine = False

    # stop any further checking:
    break

You now have a variable that you can use in a text stimulus as needed. i.e. put this in the Text field of a text component:

$str(correct_responses)

(The str() function converts the integer value into a string of characters for display.)

1 Like

Dear Michael
Brilliant. Everything worked perfectly and task is ready to go. Thank you very much for that.

Am also trying to adapt this method to another task, which is similar to this. Here a prime of ‘play’ (a picture) appears and a click response on the picture only should start the trial. I tried to achieve this by adding this code
if mouse.isPressedIn(‘next.jpg’):
continueRoutine = TRUE
else:
continueRoutine = FALSE
break
This doesn’t seem to work. Nor does it throw any error. This needs first fixing. This is only minor though, the major issues follow.

Major prob 1:
Here, on a trial, the screen shows four pictures (ignore the two extra Simpsons at the edges). There is an audio stimulus heard at the background and the participant has to click on one of the pictures to register the response based on the audio stimulus. I got the task running (but only if I remove the code component I added to record the response). The problem started when I tried to ‘score’-I pretty much used the code you gave which worked brilliantly for previous task. Unlike ‘1’ or ‘0’, this time I wanted different way of recording: if the click was made in ‘corrAns’ score it as ‘2’ , if clicked in ‘clCorrAns’ give score of ‘1’, otherwise, give score of ‘0’.

I tried to achieve this by adding this code

for stimulus in [pos_1, pos_2, pos_3, pos_4]:

** # check if the mouse is pressed within the current one:**
** if mouse.isPressedIn(stimulus):**

** # Yes, so store the reaction time in the data:**
** thisExp.addData(‘RT’, t)**

** # check if the stimulus’ image filename matches the correct answer:**
** if stimulus.image == eval(corrAns):**
** thisExp.addData(‘score’, 2)**
** elif stimulus.image == eval(clCorrAns):**
** thisExp.addData(‘score’, 1)**
** else:**
** thisExp.addData(‘score’, 0)**

** # end the trial once done here:**
** continueRoutine = False**

** # stop any further checking:**
** break**

The problem is, it displays the first trial, but when I click the mouse on one of responses it either throws up the error shown below or the program stops working.

File “C:\Users\ksengottuvel\Desktop\GJT\GJT_lastrun.py”, line 225, in
_ if mouse.isPressedIn(stimulus):_
_ File “C:\Program Files (x86)\PsychoPy2\lib\site-packages\psychopy-1.82.01-py2.7.egg\psychopy\event.py”, line 548, in isPressedIn_
_ return any(wanted & pressed) and shape.contains(self)_
AttributeError: ‘unicode’ object has no attribute ‘contains’
Exception TypeError: “‘NoneType’ object is not callable” in <bound method Server.del of <pyolib.server.Server object at 0x049EA690>> ignored

I tried changing the setting in mouse component, but it didnt help. The part ‘AttributeError: ‘unicode’ object has no attribute ‘contains’’ seems to really irritate me.

This time around I do not want the computer to print the responses, so I removed that part from your previous code.

Major Prob 2:

I have not tried doing this but I am sure I need help from you on this. I have added another button at the top (talk.jpg) for every trial, a click on that should repeat the same trial again -ie., I do not want it to run through the whole loop of a trail, i.e.,I dont want it to show the play button and needing a mouse click. i.e., if the mouse is clicked in ‘talk.jpg’-rerun that particular trial again.

_Is it possible to achieve this by slightly hacking the code?- I also want the response sheet to record how many times talk button was clicked (if it was clicked).

I have added everything with this for you to figure out what my prob exactly is. I am using v 1.82.01, as I though it was much better than newer ones. conditions.xlsx (8.9 KB)
GJT_lastrun.py (16.4 KB)
GJT.psyexp (21.5 KB)

Looking forward to hearing from you. I have made good progress with your help. _

It would be great if you could suggest me a way to do it. You and the community deserve an applauding in my acknowledgement section .

Hi,

It helps us no end if your code is formatted correctly with indentations. White space is very important in Python and we can’t really properly read your code above without it. Simply put four space before each line of code (and another four spaces for each indent), so your code gets automatically formatted like this:

if mouse.isPressedIn('next.jpg'):
    continueRoutine = TRUE
else:
    continueRoutine = FALSE
    break

The problem with your code snippet above (and I suspect the rest of your code) is that you are referring to image names (e.g. 'next.jpg') rather than PsychoPy image stimulus names. An image name is simply a sequence of characters (i.e. the string of letters next.jpg). It doesn’t refer to an image file, or an image stimulus in PsychoPy. You need to use the actual names of your image stimulus components.

e.g. I think you actually have them called things like this:

for stimulus in [ Q, C1, C2, C3, C4, C5, C6]:

Note that these stimulus names don’t have quotes. Therefore they are referring to objects, not just literal strings of characters.

PsychoPy image stimuli have a .contains() method, which allows us to check whether a mouse has been clicked in them. A string of letters is just that: it is just something that exists in memory and can’t physically be clicked. Hence Python gets very confused if you ask if it has been clicked. Python objects can only respond to certain things (e.g. it also doesn’t make any sense to ask if a person has clicked a sound). So go through your code and make sure you are referring to the right sorts of objects (image components, in this case).

Hi Michael
It worked. It stores the response as I intended it to. Thanks!!!

However, one small query is still left. I tried playing around, I couldn’t fix as I am a terrible coder.

This is how I set up the code so every trial follows if a mouse is clicked on the the place of interest.

Code under ‘Each Frame’

for stimulus in [image_7]:

    # check if the mouse is pressed within the current one:
    if mouse.isPressedIn(stimulus):
        continueRoutine = False
    else:

        break

This worked.

A click on this will lead to the actual trial.

This is what I used under the code component- ‘Each Frame’ of trial to make sure the scores are given accordingly.

for stimulus in [image, image_2, image_3, image_4]:

    # check if the mouse is pressed within the current one:
    if mouse.isPressedIn(stimulus):

        # Yes, so store the reaction time in the data:
        thisExp.addData('RT', t)

        # check if the stimulus' image filename matches the correct answer:
        if stimulus.image == eval(corrAns):
             thisExp.addData('score', 2)
        elif stimulus.image == eval(clCorrAns):
             thisExp.addData('score', 1)
        else:
             thisExp.addData('score', 0)

        # end the trial once done here:
        continueRoutine = False
        break

This part works perfectly.

Now as you might see I have these two routines separately. And are looped them for every trial.

During the trial, I have a talk button on the screen, i.e., (image_8) for every
trial, a click on that should repeat the same trial again, but i do
not want it to run through the previous routine which will need the click on next button to play the trial.

I see you have suggested this code to some one earlier on a task (but there it was key board response, here it is mouse).

I tried implementing it in the ‘End routine’ of the same code component as the trial

for stimulus in (image_8): 
    if mouse.isPressedIn(stimulus): 
          trials_repeat.finished = 1
    else: 
         continueRoutine = FALSE
         break 

This doesn’t seem to work.

The error being

for stimulus in (image_8):
'StimImage' is not iterable

I did try also to add a inner empty loop around the trial routine, which did not do any good.

Could you help?

Thanks a lot in advance. GJT.psyexp (22.8 KB)

For what it’s worth, simply wrapping your code blocks in triple-backticks (`) saves you the extra work for manually indenting everything.

1 Like

I’m not sure I really understand what the question is here. But the bug in the code at least is simple. You only have one image stimulus that you are checking, so Python complains when you you try to iterate over it in a for loop (notice the other code had a list of stimuli, not just one).

So in this case, just check for the mouse press directly, without the need for a for loop:

    if mouse.isPressedIn(image_8): 
          trials_repeat.finished = True
          # you might need  'continueRoutine = False' here too
    else: 
         continueRoutine = False
         break

Also, note that unlike in some other languages, in Python, True and False only have the first letter capitalised (i.e. FALSE is not valid).

But I’m not really sure of the logic here. The code above is highly unlikely to do anything in the End routine tab, as the trial has already ended at this stage, presumably because of a mouse press elsewhere.

So you’ll really need to describe in as clear as possible a way what it is you need to do. I suspect that this mouse checking code needs to be integrated with the other mouse checking code run on every frame, but I’m not really sure what you want to achieve.

Hi Michael
Thanks for your efforts. Sorry for not being clear. I will try again here !!!

I have two routines inserted in my task using ‘Insert routine’.
The first one is inserted to just show a picture (actually a ‘play button’ ) until a mouse is clicked on it.Once the mouse is clicked on it the next routine, i.e., the ‘actual trial’ gets to run.
Once the trial is played the participant can respond by clicking the mouse in one of the ‘four images’ on screen. With your previous help, this part of my program is working perfectly and recording as required.

I do not know how to make this task replay the ‘actual trial’ alone again if the participant clicks on the ‘replay button, i…e, the image_8’.

If the participant wants to re-play the ‘actual trial’ again, then he will click on the ‘image_8’ (which is actually a replay button) and not on the four response images. In this case the ‘actual trial’ is repeated ( but please note that I do not want the ‘play button’ routine to appear again. I tried to achieve this by making an empty loop around only the ‘actual trial’ and also by inserting this code under ‘each frame’ of code component.

if mouse.isPressedIn(image_8): 
          trials_repeat.finished = True
else: 
         continueRoutine = True
for stimulus in [image, image_2, image_3, image_4]:

# check if the mouse is pressed within the current one:
  if mouse.isPressedIn(stimulus):

    # Yes, so store the reaction time in the data:
    thisExp.addData('RT', t)

    # check if the stimulus' image filename matches the correct answer:
    if stimulus.image == eval(corrAns):
         thisExp.addData('score', 2)
    elif stimulus.image == eval(clCorrAns):
         thisExp.addData('score', 1)
    else:
         thisExp.addData('score', 0)

    # end the trial once done here:
    continueRoutine = False
    break


This throws the following error

trial_repeat.finished = True 
''trial_repeat'' is not defined 

Note this error occurs and it crashes only if I click on ‘replay button’, other wise the task runs just fine.

I could not put my head around this issue. GJT.psyexp (21.9 KB)

Your help is appreciated.
Thanks a ton

Hi, there are a few issues here.

The error message actually directly tells you the source of one of the problems: you don’t actually have anything called trials_repeat in your experiment. The two loop are currently called trials and trials_2 and so you need to use one of those defined names.

Your description above doesn’t really match the experiment, in that the play button is on same routine as the other stimuli rather than in its own routine. I’m going to assume that the Builder experiment file shows the actual intended arrangement.
To get the arrangement I think you want, you need a few tweaks.

  1. The inner loop (trials) should have a very large repeat number rather than 1 (e.g. 999). At the moment, it will only run once, so might as well not be there at all.

  2. I think the logic you want is that pushing the replay button will result in the inner loop running again (to repeat the trial), whereas pushing anything else should terminate the inner loop, to move on to the next trial (as controlled by the outer loop). So in that case, pushing replay should just end the routine (so that it will run again), and pushing anything else should both end the routine and terminate the inner loop (so that this trial doesn’t repeat). Hence you could change your code to something like:

# check if we should repeat this trial:
if mouse.isPressedIn(image_8): 
         continueRoutine = False # trial will run again
else: 
    # check for answers:
    for stimulus in [image, image_2, image_3, image_4]:

        # check if the mouse is pressed within the current one:
        if mouse.isPressedIn(stimulus):

            # Yes, so store the reaction time in the data:
            thisExp.addData('RT', t)

            # check if the stimulus' image filename matches the correct answer:
             if stimulus.image == eval(corrAns):
                 thisExp.addData('score', 2)
             elif stimulus.image == eval(clCorrAns):
                 thisExp.addData('score', 1)
             else:
                 thisExp.addData('score', 0)

            # end the trial once done here:
            continueRoutine = False

            # and stop the trial from repeating:
            trials.finished = True

            # stop any further checking
            break
1 Like

Hi Michael
Thanks a lot for that. May be I am using the terms slightly differently which is causing the confusion. I think you got what I need.

I have inserted two routines, the first routine is to just show the play button and the second routine is to play the stimuli. The inner loop is around the second routine. The outer loop is surrounding both the routines.

I tried implementing this

  1. I changed the nReps of inner loop now to 999
  2. Pasted the code you suggested in the ‘code component’ of second routine/trial.

When I run it,

Play button is shown (means the first routine is running) and the ‘Trial’ doesn’t run (means the second routine is not starting).

It throws the following error…

Exception TypeError: “NoneType” object is not callable" in <bound method server.__del__of<pyolib.server.Server object at 0x04ADB0B0>>
ignored.

I think this is just a small issue but I couldn’t fix.

Could you also suggest me a way to record how many times the ‘re-play’ button was pressed? . In the response sheet as ‘NtimesPlayed’. If it is not pressed it could be ‘0’.

Thanks again and looking forward to hearing from you.GJT.psyexp (21.4 KB)

Hi Michael

This is to let you know that now I have fixed the task and it does what I want it to do. Thanks for your time in helping me. It works brilliantly.

Just one last query in the way the data is stored:
See the attached file to clarify .csv (4.7 KB)

The output file excel has many columns that I don’t want it to show. Except the ones that are coloured. Is there any way I can get rid of all of them and record only the desired columns?

Further more, if you notice that under the ‘repeat’ column when there is a ‘yes’ /‘no’ for now. I do not understand why there is an empty row followed by ‘no’? Is there a way I can get rid of that row as well?

Further, rather than just saying ‘yes’ how could I make it to count the number of repeats /trial and record in the sheet under the ‘repeat’ column? I know I could make it record ‘1’ for every repeat, that will result in five rows (in the present form) but that will be tedious while analyzing. It would be great if it can automatically add up the repeats per trial (say, 0 or 1 or 2 or 3…)and display in the column?

Now the code is something like that for that bit,

if mouse.isPressedIn(image_20):
continueRoutine = False # trial will run again
thisExp.addData(‘repeat’, ‘yes’)
else :
thisExp.addData(‘repeat’, ‘no’)

Looking forward to hearing from you again