Writing contains(mouse) to output

Hi all,

So I’m using a Windows 10 laptop/tablet hybrid. I’ve created a touchscreen task to be used with children where they tab on different stim to give their answer. I ran into lots of issues because of the multi-touch aspect of my screen. I tried using the clickable stimuli within the mouse components of the Builder, but it required a double tap to register the response which isn’t ideal. The only thing I’ve managed to get to work is this code component on every frame:

if topLeftImg.contains(mouse) and eval(corrAns) == topLeftImg:
    continueRoutine = False
elif topLeftImg.contains(mouse) and eval(corrAns) == topLeftImg:
    continueRoutine = False
elif topRightImg.contains(mouse) and eval(corrAns) == topRightImg:
    continueRoutine = False
elif bottomLeftImg.contains(mouse) and eval(corrAns) == bottomLeftImg:
    continueRoutine = False
elif bottomRightImg.contains(mouse) and eval(corrAns) == bottomRightImg:
    continueRoutine = False
else:
    continueRoutine = True

Just to clarify, there’s a correct answer and I only want the trial to end if the kids click on the correct answer. This component works perfectly (I’ve tried many different things!), but I want it to be shown in the data output what the kid clicked on and I don’t know how to add a column that says which image was clicked on. How do I write this to the file?

Does anyone have any guidance on how to achieve this?

Any advice would be appreciated!

1 Like

Hi, you’ve come up with a nice way of getting around the issue of the double click.

You can simply add custom data fields to your data file using thisExp.addData(). Can’t resist also suggesting a more concise way of doing the whole thing though:

# this list should could just be created once per trial, in the 'begin routine' tab:
stimuli = [topLeftImg, topRightImg, bottomRightImg, bottomLeftImg]

# and this run on every frame:
for stimulus in stimuli:
    if stimulus.contains(mouse) and stimulus.name == corrAns:
        thisExp.addData('clicked_stimulus', stimulus.name)
        continueRoutine = False
        break # end the loop on first click

Using loops like this allows you to avoid repeating code, which easily allows errors to creep in. e.g. notice how in your code above, you actually test topLeftImg twice? A key mantra in programming is DRY: don’t repeat yourself, because such code is error-prone and hard to maintain.

Also note that you don’t need to set continueRoutine = True, as it will remain that way unless set otherwise.

4 Likes

Hi Michael,

Thanks so much for your advice. As you can probably tell I’m still pretty new to coding and PsychoPy. Thanks for your conciseness advise - that’s so helpful! :slight_smile:

Hello,
I have a similar experiment. In my experiment I am taking responses through touchscreen. The participant has to select one of the four response images presented with the target on screen.
My issue is that I want to add a column of ‘correct’ where I can have a list of 1s and 0s depending on whether the response image clicked/touched was correct. Also, I want to provide a feedback to let the participant know whether they have responded correctly or not.

The following is my code component:

image

Here is my excel file:

image

It would be great if you could help me with it.
Thank you

You should re-structure your code into a loop - it makes for much less duplication.
Also, ideally provide the actual text of your code rather than screenshots - it makes it harder for us to just copy and paste to suggest changes.

mouseloc = mouse.getPos()

for stimulus in [RespBluePIC_P, RespRedPIC_P, RespBearPIC_P, RespCarPIC_P]:
    if stimulus.contains(mouse):
        mouserec = mouseloc
        mousetime = core.getTime() # you should probably be getting a trial-relevant time
        thisExp.addData('clicked_resp', stimulus.name)
        thisExp.addData('clicked_resp_time', mousetime)
        thisExp.addData('correct', stimulus.image == CorrAnsPic)
        continueRoutine = False

1 Like

Thank you for your suggestion. It worked fine. For feedback I am trying the following code, but the feedback is always coming to be incorrect. Can you please check the code and suggest where I might be going wrong.

Begin experiment:
msg = ’ ’

Begin routine:
if “correct” = “TRUE”:
msg = “CORRECT”
msgColor = ‘green’
else:
msg = “INCORRECT”
msgColor = ‘red’

After every trial the feedback is always “INCORRECT”.

Note that touchscreens continue to send the previous touch location when the screen isn’t being touched. For that reason I also require a change in coordinates to register a response.

We need to see it properly indented, as indenting carries meaning in Python:

But for a start, note that your if test uses a single = rather than ==, and that “correct” shouldn’t be in quotes (in effect, you are comparing two different strings of characters, which will always be unequal, by definition.

Sorry for the inconvenience. I will keep in mind your suggestions.
Begin Experiment:

msg = ' '

Begin Routine:

if "correct" == "True":
     msg = "CORRECT"
     msgColor = 'green'
else:
      msg = "INCORRECT"
      msgColor = 'red'

This was the code I used. Here, in my previous codes I created a column “correct” to store whether the response was correct or not. The column stores responses in TRUE/FALSE form. I tried this code without putting correct in quotes, but it didn’t work. The column is storing the correct and incorrect responses properly. But I am not sure how can I use this in codes. Similar code with key responses was working well. But since now it is with touchscreen, I am not sure how to do it.

I’ve edited your post to use triple backticks (i.e. ```) so we can see the indenting of your code.

Yes, but as stated above, quoting "correct" guarantees that this code won’t work either: the literal string of characters "correct" will never equal the string of characters "True". You need to refer to the variable name correct (i.e. without quotes) so that the comparison is done with the contents of that variable name.

A useful tip for debugging things like this is to (TEMPORARILY) insert some debugging statements to check the content of your variables. e.g.:

print(correct)
print(type(correct))

to see what the variable contains and whether it is of the type you expect. It might be possible, for example, that the variable has been interpreted from the conditions file to contain boolean values (i.e. True or False) rather than the strings of characters 'True' or 'False'.

If that is the case, then your check could just be:

if correct is True: # NB no quotes on either term here

or even just:

if correct:

Lastly, note that your code above doesn’t have matching levels of indenting between the if and else clauses.

EDIT I just noticed this:

In the code given before, we are just directly storing the result in the data file. We can’t actually directly access columns from the datafile - unlike the conditions file, which gives us input, the datafile is just for output. So instead, you need to save that value in a variable name, so that it can be referred to later, as well as being stored in the data. So in that code above, amend it to something like this:

        correct = (stimulus.image == CorrAnsPic) # keep for later
        thisExp.addData('correct_response', correct) # store in the data

That way you can now refer to the variable correct later if needed.

Thank you so much for your help. The experiment is working perfectly fine now.

Hello Michael,

I have the same problem with the doublé tap. Thing is I didn’t write the code, I just built the experiment. I think the code on the response part is:

correct = new visual.ImageStim({
    win : psychoJS.window,
    name : 'correct', units : undefined, 
    image : undefined, mask : undefined,
    ori : 0, pos : [(- 0.2), (- 0.3)], size : [0.15, 0.15],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 512, interpolate : true, depth : -4.0 
  });
  wrong = new visual.ImageStim({
    win : psychoJS.window,
    name : 'wrong', units : undefined, 
    image : 'files/wrong.png', mask : undefined,
    ori : 0, pos : [0.2, (- 0.3)], size : [0.15, 0.15],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 512, interpolate : true, depth : -5.0 
  }); 
mouse = new core.Mouse({
    win: psychoJS.window,
  });
  mouse.mouseClock = new util.Clock();
  // Initialize components for Routine "feedback"
  feedbackClock = new util.Clock();
  soundfile = ["files/check.wav"];

Wrong/correct are the two answers they have available, with the mouse requires one click on any of them but on the touchscreen it requires double tap.

Thanks for the help :slight_smile:

The poster above had problems that were specific to custom code they had written. If you don’t have any such code, then your problem is different. Please make a new topic, which fully describes your particular situation.

done, thanks!

Hello Michael,

I am quite new at Psychology and programming in Psychology. So I will greatly appreciate your help.

I also want to conduct an experiment with a touchscreen and your code has solved the problem about double-click/swipe.

In my experiment, the participants have to select one of the five choices (I used polygons here) after they saw a picture(video). There are 160 pictures(videos) and I would like to let them rest after they saw 20 pictures(videos). Since there are no right answers, all I want to know is which button the participant selects and their response time on pressing the button. However, I have no idea what I should do to collect response time.

I tried the code you suggested to triptiverma but “clicked_resp_time” seems quite weird (because it is much longer than the time clicked by a mouse)…

The following is my code component:
Begin Experiment

trialscounter = 1
import psychopy.event
mouse = psychopy.event.Mouse(win=win)
from pyschopy import iohub
from psychopy import clock, core

Begin Routine

rest = False
mouseclick = False
timer = core.CountdownTimer(1000)
stimuli = [pressframeshita, turnframeshita, pullframeshita, slideframeshita, naiframeshita]
mouse = mouse
mouse.setPos(newPos=(0,0))
mouserec=mouse.getPos()

Each Frame

if trialscounter % 20 == 0:
    if mouse.isPressedIn(pressframeshita) or mouse.isPressedIn(turnframeshita) or mouse.isPressedIn(pullframeshita) or mouse.isPressedIn(slideframeshita) or mouse.isPressedIn(naiframeshita)
     rest = True
     mouseclick = True
     timer = core.CountdownTimer(1)

else:
    if mouse.isPressedIn(pressframeshita) or mouse.isPressedIn(turnframeshita) or mouse.isPressedIn(pullframeshita) or mouse.isPressedIn(slideframeshita) or mouse.isPressedIn(naiframeshita)
     continueRoutine = False

if mouseclick == True:
     if timer.getTime()<0:
     if mouse.isPressedIn(image_3): #have a rest per 20 trials
      continueRoutine = False

mouseloc = mouse.getPos()

for stimulus in stimuli:
    if stimulus.contains(mouse):
        mouserec = mouseloc
        mousetime = core.getTime()
        thisExp.addData('clicked_stimulus', stimulus.name)
        thisExp.addData('clicked_stimulus', mousetime)
        continueRoutine = False

End Routine

trialscounter = trialscounter + 1

So sorry for my frequent modification.
Thank you very much.