Pseudorandomization for fMRI

Hey everyone!

I created a priming experiment that works very well behaviourally, but for fMRI, I need to pseudo-randomize the order of presentation of the primes.

To do so, a program found the best combination of prime presentations for optimizing event-related potentials in the machine, such as I now have an excel sheet with one column that contains the best order to present the primes (i.e., first a happy prime, then sad, sad, then mas, then sad, then happy…).

So now, I have my initial excel sheet, comprising a column for prime stimuli, a column for target stimuli, and a last column with the type of prime (happy, sad, mask), and another excel sheet with the order of presentation.

What I want to do:

I need my code to take sequentially in the new excel sheet to get the order of prime presentation (i.e., happy prime first) and that the prime that it chooses is random between all the happy primes + the corresponding target (because it is the same face for prime and target). Then when it goes to the second line (i.e., sad) it takes randomly a sad trial (sad prime + corresponding target). When it falls on another happy prime, it has to be another of the happy primes but not one of the happy ones that have already been presented!

image

Thank you so much for your help!

Best,

Alexane

I think the solution here is to only have the order of trial types (happy, sad, mask) in your excel file and do everything else with code components. Since you’re doing neuroimaging I’m presuming we don’t need to worry about JavaScript, which makes this a little easier.

I don’t know if your main trial loop is one trial with multiple components or if the prime and target are separate trials. I’m going to assume one trial, and suggest adding a code component to it. In the “before experiment” tab, create three lists of dictionaries corresponding to the three types of trials. It would look something like this:

import random
happyTrials = [{'prime':'resources/006_happy.png', 'target':'resources/006_morph.png'}, {'prime':'etc', 'target':'etc'}] 
sadTrials = [{'prime':'resources/006_sad.png', 'target':'resources/006_morph.png'}, {'prime':'etc', 'target':'etc'}]
maskTrials = [{'prime':'resources/006_mask.png', 'target':'resources/006_mask.png'}, {'prime':'etc', 'target':'etc'}]

random.shuffle(happyTrials)
random.shuffle(sadTrials)
random.shuffle(maskTrials)

happyTrialCounter = 0
sadTrialCounter = 0
maskTrialCounter = 0

Then in the “Before Routine” tab:

if thisTrial['prime_emotion'] == 'happy':
    prime.setImage(happyTrials[happyTrialCounter]['prime']
    target.setImage(happyTrials[happyTrialCounter]['target']
    happyTrialCounter += 1
elif thisTrial['prime_emotion'] == 'sad':
   #as above for sad and again for mask

The randomization is handled by the shuffle call in the before experiment code, then you’re just going through the shuffled list for each trial type sequentially as that trial type comes up.

Hey Jonathan!

It looks absolutely great! I will try and implement this and let you know if everything worked!

Best,

Alexane

Hey Jonathan,

I have two images in the same routine indeed.

As you can see on the image, there is a polygon (always there), then the prime called ‘prime_exp’, then a mask between the prime and the target that always stays there as well, and finally the target image called ‘target_exp’.

Using your code, I just changed the name before .setImage and wrote prime_exp.setImage[…]

However, I don’t understand several things in your code:

  1. what is thisTrial ? is it the name of the loop? or the routine?
  2. what is prime_emotion? Is it now the name of the column in my excel sheet named ‘order_stimuli.xlsx’?
  3. what do I set for images in prime_exp and target_exp manually? isn’t there a “$” something to write? or I leave it blank? Because when I leave it blank it’s written: "prime_exp.setImage[… could not find path.

Best,

Alexane

The current iteration of the loop. More specifically, it’s a dictionary with every column in the excel file, but only has their values for the current iteration.

Yes, it is the column name.

This is a very subtle timing issue that’s hard to get around. Basically it tries to load an image for prime_exp before the “Before routine” code is executed. I think easiest best thing to do is probably to give it a placeholder image that will then be replaced when the “Before routine” code executes.

Thank you for your quick reply!

The picture seems to be ok for now, I’ve put an image as a placeholder for now, but thisTrial is still not defined! Where do you place it?

if thisTrial[‘prime_emotion’] == ‘happy’:
NameError: name ‘thisTrial’ is not defined

I also thought about another solution:

I have my trial with cross-prime-mask-target. What I could do could be:

Having a big loop with the order of presentation of primes in an excel sheet with the first column named “prime_order” - that will sequentially get happy, sad, mask…
And then within it, having a smaller loop that will, if happy, sad, or mask is selected, go randomly into one of my three excel sheets and get the trials from there (and keep the same structure as at the beginning!, i.e., a column for prime images, another one for target images, and one that tells me which type of prime it is - but in that case, it will always be happy in the happy excel sheet, sad in the sad excel sheet and mask in the mask excel sheet).

Is it something that is possible? I am trying to implement that! On my final csv files, I liked having prime, target and prime_emotion, it is easier to code for data analysis after! In that case, I would still need a bit of code, to define which excel sheet needs to be read depending on where we are in the sequence.

Something like:
if the trial in the excel sheet order == happy:
use excel sheet happy in the small loop
and prime + target stays $prime and $target, with all images being defined in the different excel sheets

What do you think ?

Alexane

That alternative solution might work, but I’m not sure it will do a good job of keeping track of what’s already been shown in each condition.

It’s interesting that ‘thisTrial’ is undefined, that shouldn’t happen. Could you possibly share your psyexp file?

Oh, you think?

Yes, I’ll share it now! Thanks for your help!

You can only look at the first loop (I placed it there to avoid doing the whole experiment all over aha :slight_smile: )

And there is a sample order + sample stimuli.

task_fmri.psyexp (82.3 KB)
resources.zip (964.3 KB)
stimuli_order.xlsx (8.6 KB)

Ah, interesting, the naming scheme wasn’t what I expected. Replace “thisTrial” with “thisOrder_loop” in the code and it should work.

All good!!! Thank you so much!

Is it possible to keep track of which stimuli have been presented in the output csv file? I had this for the behavioral task, but now I just have prime_emotion! (Because I can’t check if two similar faces appeared one after the other!

You can add it manually in your before routine code

if thisOrder_loop['prime_emotion'] == 'happy':
    prime.setImage(happyTrials[happyTrialCounter]['prime'])
    target.setImage(happyTrials[happyTrialCounter]['target'])
    order_loop.addData("prime_image", happyTrials[happyTrialCounter]['prime'])
    order_loop.addData("target_image", happyTrials[happyTrialCounter]['target'])
    happyTrialCounter += 1
if thisOrder_loop['prime_emotion'] == 'sad':
    #etc.
1 Like

Hello Jonathan,

Thank you very much for these helpful answers! I benefitted from this as I am trying to make similar changes to my experiment. I have modified this code to my experiment, but I am having trouble as it is not loading the images that are listed in the code into my experiment. You suggested adding a placeholder image, and I selected one, however, this is the only image that appears in my experiment. There is no error, it’s just that it does not seem as though my code is working properly.

in ‘Before experiment’, I have entered:
import random
goOH = [{‘stim1’:‘resources/trials/Wine29.jpg’, ‘stim2’:‘resources/silent.wav’},
{‘stim1’:‘resources/trials/Beer_X35.jpg’, ‘stim2’:‘resources/silent.wav’}, etc.]

stopOH = [{‘stim1’:‘resources/trials/Wine29.jpg’, ‘stim2’: ‘resources/AIGU.mp3’},
{‘stim1’:‘resources/trials/Beer_X35.jpg’, ‘stim2’: ‘resources/AIGU.mp3’}, etc.]

goNOH = [{‘stim1’:‘resources/trials/Juice_X31.jpg’, ‘stim2’:‘resources/silent.wav’},
{‘stim1’:‘resources/trials/Juice10.jpg’, ‘stim2’:‘resources/silent.wav’}, etc.]

stopNOH = [{‘stim1’:‘resources/trials/Juice_X31.jpg’, ‘stim2’: ‘resources/AIGU.mp3’},
{‘stim1’:‘resources/trials/Juice10.jpg’, ‘stim2’: ‘resources/AIGU.mp3’},

random.shuffle(goOH)
random.shuffle(stopOH)
random.shuffle(goNOH)
random.shuffle(stopNOH)

goOHTrialCounter = 0
stopOHTrialCounter = 0
goNOHTrialCounter = 0
stopNOHTrialCounter = 0

In ‘Begin Routine’, I have entered:

if [‘condition’] == ‘goOH’:
imagesbev.setImage(goOH[goOHTrialCounter][‘stim1’])
order_loop.addData(“imagesbev”, goOH[goOHTrialCounter][‘stim1’])
goOHTrialCounter += 1
elif [‘condition’] == ‘stopOH’:
imagesbev.setImage(stopOH[stopOHTrialCounter][‘stim1’])
order_loop.addData(“imagesbev”, stopOH[stopOHTrialCounter][‘stim1’])
stopOHTrialCounter += 1
elif [‘condition’] == ‘goNOH’:
imagesbev.setImage(goNOH[goNOHTrialCounter][‘stim1’])
order_loop.addData(“imagesbev”, goNOH[goNOHTrialCounter][‘stim1’])
goNOHTrialCounter += 1
elif [‘condition’] == ‘stopNOH’:
imagesbev.setImage(stopNOH[stopNOHTrialCounter][‘stim1’])
order_loop.addData(“imagesbev”, stopNOH[stopNOHTrialCounter][‘stim1’])
stopNOHTrialCounter += 1
Screen Shot 2023-05-12 at 4.31.11 PM

Whenever possible please enclose your code in ` marks so it shows up with proper indentation.

The basic problem is that your conditions are never met because ['condition'] is not referring to anything, so none of those statements are ever true. You want something like this:

if thisOrder_loop['condition'] == 'goOH':
etc.

If you have a nested loop structure and ‘condition’ is a property of the outer loop it’s a little trickier to figure out what it needs to be, but bottom line is that you aren’t referring to the variable you need right now.

Hello Jonathan,

Thank you for the reply. Should I be replacing ‘loop’ with the name of my loop? The name of my loop is SST_trials, and I have done thisOrder_SST_trials, but when I do this, NameError: name ‘thisOrder_SST_trials’ is not defined.
SST-alcohol_fMRIversion.psyexp (99.4 KB)
SST_opt-001.par.csv (4.2 KB)

‘if thisOrder_SST_trials[‘condition’] == ‘goOH’:
imagesbev.setImage(goOH[goOHTrialCounter][‘stim1’])
order_SST_trials.addData(“imagesbev”, goOH[goOHTrialCounter][‘stim1’])
goOHTrialCounter += 1
elif thisOrder_SST_trials[‘condition’] == ‘stopOH’:
imagesbev.setImage(stopOH[stopOHTrialCounter][‘stim1’])
order_SST_trials.addData(“imagesbev”, stopOH[stopOHTrialCounter][‘stim1’])
stopOHTrialCounter += 1
elif thisOrder_SST_trials[‘condition’] == ‘goNOH’:
imagesbev.setImage(goNOH[goNOHTrialCounter][‘stim1’])
order_SST_trials.addData(“imagesbev”, goNOH[goNOHTrialCounter][‘stim1’])
goNOHTrialCounter += 1
elif thisOrder_SST_trials[‘condition’] == ‘stopNOH’:
imagesbev.setImage(stopNOH[stopNOHTrialCounter][‘stim1’])
order_SST_trials.addData(“imagesbev”, stopNOH[stopNOHTrialCounter][‘stim1’])
stopNOHTrialCounter += 1’

The naming scheme PsychoPy uses is a little finicky. It looks like the name you want will be thisSST_trial['condition']

EDIT: And the addData function will be SST_trials.addData()

Hello Jonathan,

Thank you, I no longer have the NameError, but now the path is not recognized to load the images. The images at in the resources folder (/Users/samanthamurphy/SST_experiment/resources), but there is this error:

Traceback (most recent call last):
90.7388 ERROR Couldn’t find image ; check path? (tried: /Users/samanthamurphy/SST_experiment)
File “/Users/samanthamurphy/SST_experiment/SST-alcohol_fMRIversion_lastrun.py”, line 1763, in
imagesbev.setImage(‘’)
File “/Applications/PsychoPy.app/Contents/Resources/lib/python3.8/psychopy/visual/image.py”, line 416, in setImage
setAttribute(self, ‘image’, value, log)
File “/Applications/PsychoPy.app/Contents/Resources/lib/python3.8/psychopy/tools/attributetools.py”, line 134, in setAttribute
setattr(self, attrib, value)
File “/Applications/PsychoPy.app/Contents/Resources/lib/python3.8/psychopy/tools/attributetools.py”, line 27, in set
newValue = self.func(obj, value)
File “/Applications/PsychoPy.app/Contents/Resources/lib/python3.8/psychopy/visual/image.py”, line 382, in image
self.isLumImage = self._createTexture(
File “/Applications/PsychoPy.app/Contents/Resources/lib/python3.8/psychopy/visual/basevisual.py”, line 1022, in _createTexture
raise IOError(msg % (tex, os.path.abspath(tex)))
OSError: Couldn’t find image ; check path? (tried: /Users/samanthamurphy/SST_experiment)
################ Experiment ended with exit code 1 [pid:77977] #################

This is probably a file system navigation issue. Exactly what folder is your .psyexp file in, and where is the resources folder relative to that?

Hello,

The .psyexp file and the resources folder are both in the SST_experiment folder. If I call in the images using 'stim1’:‘resources/trials/Beer_X35.jpg’ for instance, psychopy checks the path users/sm/SST_experiment and it says OSError: Couldn’t find image ; check path? (tried: /Users/samanthamurphy/SST_experiment)

If I add to the path 'stim1’:‘SST_experiment/resources/trials/Beer_X35.jpg’, it says OSError: Couldn’t find image SST_experiment/resources/trials/Beer_X35.jpg; check path? (tried: /Users/sm/SST_experiment/SST_experiment/resources/trials/Beer_X35.jpg).

The first error is interesting because it’s acting like it isn’t even getting the rest of the path in the first place. Maybe try 'stim1':'./resources/trials/Beer_X35.jpg'

My other idea is to rename the folder from “resources” to something else. Why that would matter I can’t say. Worst case take the images out of the sub-folder and just stick them in the same folder as the psyexp file.