I’m new to Psychopy. I know how to randomize a list of images. But at the moment I’m trying to build a task in which 4 images appear in each corner of the screen: 2 neutral, one positive and one negative.
I want the order and placement of image valence (positive, neutral & negative) to be randomized without repetition. For instance I don’t want negative images to appear in the same place every time.
I’m not sure how to do that. Any help would be appreciated.
I’m using the latest version of psychopy (v1.85.0) on windows.
Thanks in advance.
There are two options:
(1) control this behaviour using small code snippets
(2) handle it yourself in your conditions file.
e.g. The second approach is likely simplest, just have four columns for the image names:
top_left top_right bot_left bot_right neut1.jpg neut2.jpg pos1.jpg neg1.jpg pos2.jpg neut3.jpg neut4.jpg neg2.jpg etc etc
and use those variable names in the corresponding image stimuli.
i.e. in this approach, PsychoPy will handle randomising the order of trials, while you are handling the allocation of stimuli to positions. If this pseudo randomisation within trials (which would be constant across subjects) is not sufficient, then some code would be required (and a more detailed description of the variables).
Thanks for your help. I did indeed consider the four columns approach, however the participants should select one of the pictures at each trial depending on the instructions given beforehand.
Trial 1: top left: neutral, top right: positive, bottom left: negative, bottom right: neutral.
The instructions for this trial are let’s say select the negative image.
Trial 1: top left: neutral, top right: negative, bottom left: neutral, bottom right: positive.
The instructions for this trial are let’s say select the positive image.
And so on.
Hence, how do I specify the correct answer to Psychopy for each trial? In my previous projects I specified it in my conditions file. But I only had one colomn back then. In this case would it work if I specify:
And have a nice day.
Hello. It sounds like you want something like in this post:
i.e. are you wanting the participant to just click on one of the four images to indicate the answer? In this case, yes, you could use the arrangement as discussed, with four columns to specify the image names for the four quadrants, a fifth column which repeats one of the image names (the correct choice), and another column containing the question text. The you want to insert a code component in Builder and put something like this in the
Each frame tab:
# cycle through the stimulus components by name: # (i.e. replace with the actual names of your 4 image stimulus components # in the Builder timeline view): for stimulus in [ image_TL, image_TR, image_BL, image_BR]: # 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) # get the filename for this stimulus (originally came from one of # your four columns): image_chosen = stimulus.image thisExp.addData('choice', image_chosen) # check if the stimulus' image filename matches the correct answer: if image_chosen == correct_choice: # use your actual fifth column name thisExp.addData('correct', 'True') else: thisExp.addData('correct', 'False') # end the trial once done here: continueRoutine = False # stop any further checking: break
You could also do other things here, like play different tones to give correct/incorrect feedback, highlight the clicked image, etc.
Thanks for you answer. I tried the code and it’s not working. I believe I’ve made a mistake somewhere that I can’t seem to be able to pinpoint.
# initialise a counter variable:
correct_responses = 0
#cycle through the stimulus components by name:
for stimulus in [TL, TR, BL]: #that’s how the images are entitled in my builder (the images not the $Top_Left etc. refering to the document)
# 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) # get the filename for this stimulus (originally came from one of # your four columns): image_chosen = CorrectAns #the correct answer column in the Excel file thisExp.addData('choice', image_chosen) # check if the stimulus' image filename matches the correct answer: if image_chosen == CorrectAns: thisExp.addData('correct', 'True') else: thisExp.addData('correct', 'False') # end the trial once done here: continueRoutine = False # stop any further checking: break
Here is the error it shows when I try to run it from the script:
Traceback (most recent call last):
File “C:\Users…”, line 5, in
for stimulus in [TL, TR, BL]:
NameError: name ‘TL’ is not defined
When I run it from the builder the mouse has no effect. Wherever I click there’s no response whatsoever.
- Why are you running it from the scrip[t rather than from the Builder window?
- You haven’t posted the full error message which makes it harder to analyse things, but that line somehow appears to be in line 5 of your script. That early in the experiment script, it is highly unlikely that TL, TR, etc can have been defined yet. That code is supposed to be running on every frame refresh during your experiment, not at the very beginning of your experiment, before the stimuli have bene been created.
I suggest you read through the instructions above more carefully about where exactly to put this code.
Indeed I was placing the code in the wrong place in my coder (I created a new code file for it at first). However now I face a new issue with the code. I’ve tried running it form the builder then from the coder and nothing worked, I get different error messages depending on where I try to run it from.
Whenever I try to run it from the coder, the following two errors appear:
Traceback (most recent call last):
File “C:\Program Files (x86)\PsychoPy2\lib\site-packages\psychopy-1.84.2-py2.7.egg\psychopy\app\coder\coder.py”, line 2530, in runFile
fullPath = self.currentDoc.filename
AttributeError: ‘NoneType’ object has no attribute 'filename’
Note: Dynamic code seems intended but updating is “constant”:
"$CorrAns2", in Routine RateV2 (Image_To_RateV2: Image)
"$CorrAns2", in Routine SavourerV2 (a_savourer_V2: Image)
"$CorrAns", in Routine RateV (image_to_rate: Image)
"$CorrAns2", in Routine attenteV2 (ImagePosASavourer: Image)
The lines 2527 to 2545 are the following:
def runFile(self, event): """Runs files by one of various methods """ fullPath = self.currentDoc.filename filename = os.path.split(fullPath) # does the file need saving before running? if self.currentDoc.UNSAVED: sys.stdout.flush() msg = _translate('Save changes to %s before running?') % filename dlg = dialogs.MessageDialog(self, message=msg, type='Warning') resp = dlg.ShowModal() sys.stdout.flush() dlg.Destroy() if resp == wx.ID_CANCEL: return -1 # return, don't run elif resp == wx.ID_YES: self.fileSave(None) # save then run elif resp == wx.ID_NO: pass # just run
Line 2530 is the following:
fullPath = self.currentDoc.filename
Whenever I try to run it from the builder, it loads as if it’s going to run and then an output window message appears claiming that “CorrAns” is not defined & that there’s an issue in line 241 in < module>. image=CorrAns, mask=None. NameError: name ‘CorrAns’ is not defined.
Here’s the code I found (237 to 254):
if thisLine.find('Saved copy of actual frame') > -1: # show the new images, double size for easier viewing: newImg = [f for f in thisLine.split() if f.find('_local.png') > -1] newFile = newImg origFile = newFile.replace('_local.png', '.png') img = os.path.join(self.parent.paths['tests'], origFile) self.png.append(wx.Image(img, wx.BITMAP_TYPE_ANY)) self.MoveEnd() self.WriteImage(self.png[-1]) self.MoveEnd() self.WriteText('= ' + origFile + '; ') img = os.path.join(self.parent.paths['tests'], newFile) self.png.append(wx.Image(img, wx.BITMAP_TYPE_ANY)) self.MoveEnd() self.WriteImage(self.png[-1]) self.MoveEnd() self.WriteText('= ' + newFile + '; ')
The line 241 is the following:
newFile = newImg
Finally, here’s the code I used for the two parts of the task when the participant has to click on one of the pictures (each part is attributed to a different Excel file):
for stimulus in [ TL, TR, BL, BR]:
if mouse. is PressedIn(stimulus): thisExp.addData('RT', t) image_chosen = CorrAns thisExp.addData('choice', image_chosen) if image_chosen == CorrAns: thisExp.addData('correct', 'True') else: thisExp.addData('correct', 'False') continueRoutine = False break
for stimulus in [ TLV2, TRV2, BLV2, BRV2]:
if mouse.is PressedIn(stimulus): thisExp.addData('RT', t) image_chosen = CorrAns2 thisExp.addData('choice', image_chosen) if image_chosen == CorrAns2: thisExp.addData('correct', 'True') else: thisExp.addData('correct', 'False') continueRoutine = False break
On a side note & maybe it could help:
In the builder I set the images to change every frame, the mouse is relative to routine & the mouse state is to be saved every frame.
Otherwise, I’m using windows 7 pro, and I’m just a user of the laptop not its admin.
Hi, by “read through the instructions above more carefully” I’m specifically referring to " insert a code component in Builder and put something like this in the
Each frame tab".
i.e. you shouldn’t be directly editing the Python .py file. Instead, from the Builder interface, insert a Code Component. You get this from the Component panel on the right hand side: click on the
Custom arrow and then click the code icon. This component has specific tabs to type code in. The component will automatically handle putting code in the right place so that it runs at the start of the experiment, at the start of a routine, on each frame, and so on.
We can’t really sort out any errors until we know that this is how you are inserting your custom code.
Once I put it in the builder it worked! Hallelujah!
Thank you so much.
One last thing. Even when I select the wrong photo, the correct one is automatically shown in the next frame. Is there no way to “reject” incorrect answers? So unless the person chooses the right photo there is no moving forward in the task.
I’ve seen this post: https://discourse.psychopy.org/t/in-coder-properties-of-builder-can-i-designate-trigger-loop-for-only-correcrt-answers/1470/2
But I’m not sure we’re looking for the same thing.
With the appropriate code, you can probably do whatever you want. But what you are describing is entirely different to the situation above (i.e. there is no point in recording whether a response was correct or not if the final response will always be correct, and the reaction time is also meaningless if multiple responses can be made. You are only going to get useful responses here if you describe exactly what you want to do.
The participants have to choose between multiple photos on the screen.
They need to pick one and only one depending on the instructions given to them at the beginning of each bloc.
For instance: in bloc 1 there are 3 negative images & 1 positive & they have to select the positive image
In bloc 2: there are 2 positive images, 1 neutral & 1 negative and they have to pick the negative image
In every bloc, the participant should select only one type of image depending on its valence (positive, negative, neutral). Once the image is selected, the participant will look at it for 10 seconds then rate on a scale from 1 to 10 how much emotion it stirred in him.
Now, in the way I constructed the programm, each bloc is divided into 3 routines:
choice, observation, rating.
In the observation & rating routines I used the $CorrAns so that the correct photo shows in the middle of the screen.
What I’m trying to do is not allow the observation & rating routines if the person clicks on the wrong photo. For instance, if in Bloc1, if the person chooses the negative photo instead of a positive one, I want an error feedback to appear and ask the participant to select the correct image.
In my current protocol, where the participant clicks doesn’t matter because the protocol continues anyway and goes into the observation & rating routines. Given the fact that I need the participants focused, I want the protocol to continue when and only when they choose the right photo.
TR and respect of the instructions regarding image choice are important because I’m measuring negativity biases (among other things).
OK. So stick with the experimental routine as described but then create two additional routines to follow it: one for error feedback and the other for your ratings and so on. You can select which one will be executed on each trial by inserting a code component and in the
Begin Routine tab, putting some code to not continue with the routine, depending on the decision made. You then also need to wrap all three routines in another loop (i.e. nested inside your main loop). This loop isn’t linked to a conditions file. Just give it a large number of repetitions. i.e. this just makes the trial repeat until the correct selection is made. In the
begin routine tabs, put something like this:
# for the error feedback routine: if image_chosen == CorrectAns: continueRoutine = False # don't give error feedback for a correct trial
# for the rating routine: if image_chosen != CorrectAns: continueRoutine = False # don't do the rating else: # will do the rating, your_inner_loop_name.finished = True # and end the cycle of repeating this trial
I tried the command in several combinations but it didn’t work. Whatever image I click on, the correct one still shows, the program is just slower.
However I do believe have some difficulty understanding the instructions:
“add two additional routines to follow it” → follow all 3 routines or follow each routine?
“and so on” → so I need to use both codes for each routine?
“wrap all three routines in another loop” → my 3 routines? or each routine with the two new routines & their codes?
I inserted the code for each condition in my Block.
At first, I only used it for choice, then rating, then choice and rating but it didn’t work either…
I also tried wrapping my routines and putting the codes outside the inner loop.
I tried, wrapping all 3 routines with the additional routines I created for the codes.
I tried using the codes in one coder in the builder.
In the error routine I put the following code in begin routine tab:
if image_chosen == CorrAns:
continueRoutine = False
Then in the rating routine I used the following code:
if image_chosen != CorrAns:
continueRoutine = False
avancement_choix_essai.finished = True #I changed the name for each nested loop I created
Here’s an example of 1 of the flows I modified:
I think you would benefit a great deal from the workshop!
Ah I didn’t know you organized workshops. That’s a great idea and indeed I’d love to. Thank you.