psychopy.org | Reference | Downloads | Github

Randomizing fixed image pairs with constraints

Hi All,

I’m a beginner in programming and Psychopy. I’m working on a prospective memory task in Builder and came across a randomization issue which seems quite difficult to solve. I have 60 face pairs as stimuli, each appearing once in a random loop. Shortly, the task is to indicate with a key response whether the gender of the two faces is the same (‘right’) or not (‘left’). However, there is a specific face pair which has been learned before the gender discrimination task. If this face pair is seen, irrespective of gender discrimination, a third key must be hit (‘up’). Thus, beyond the 60 face pairs, I would like to add 4 of these specific (so called prospective) face pairs to the loop. The position of these prospective cues is crucial, because a) they should be semi-equally distributed throughout presentation and b) they should not be the first and/or last item being presented.

What I’ve done so far:

A condition file belongs to the loop, in which I manually coded all the pairs and the corresponding answers in advance (not that elegant; this was necessary, because the proportion of the certain face characteristics, e.g. sex, age, as well as answer types both need to be counterbalanced).

I’ve put a code component into the trial routine (‘Begin experiment’) which intends to say that there is a “gap” between each prospective cue with a randomly varying length. The list corresponds to one of the columns in the condition file. I’d like 6-10 trials between these cues, but I don’t want the distance to be the same across and within participants.

Results: No error messages, a running experiment, but no expected randomization.
I supposed that it was enough to include only one of the image lists in the code, but that might be the problem; perhaps the code is not appropriate.

Any comments would be appreciated!

Hi Bernadette,

I think the problem here is that the list images isn’t connected to anything in PsychoPy - you’ve created a list and then edited it, but this doesn’t have any bearing on what PsychoPy will read for the trials. What you need to change the order of is trials.trialList, as this is the list it reads in from your excel file which defines the order.

First things first, rather than having the first rows of the excel spreadsheet as a model prospective trial, I would just define it in the Begin Experiment tab, so your tab should look like this:

import random

prospCue = {'image':'74.jpg', 'correct':'up', 'imagee':'66.jpg'} # Create a model row for a prospective trial

and you wouldn’t have any prospective trials in your excel sheet.

Then, you would use your for loop later to replace random rows with the model prospective cue row (prospCue). Unfortunately, trials.trialList is read in after any code you write in Begin Experiment, so anything you change about it there will be overwritten. What we need to do instead is put it in Begin Routine, but have an if statement so it only runs on the first trial. Here’s what I wrote, which works for me:

if trials.thisN == 0: # If this is the first trial...
    prospDiffs = [6, 7, 8, 9, 10] # Possible number of trials between each prospective cue
    i = random.choice(prospDiffs) # Start at an index within range of prospDiffs...
    while i < len(trials.trialList) - 2: # While that index is less than the total number of trials - 2...
        trials.trialList[i] = prospCue # Insert a prospective trial at that index
        i = i + random.choice(prospDiffs) # Add a random value from prospDiffs to the index

So, at the beginning of the first trial, you start with a random number between 6 and 10, replace the trial at that index with a prospective trial, then keep adding between 6 and 10 to that index and repeating the process until the index is greater than the number of trials (minus however much of a gap you want between the final prospective trial and the final trial, I used 2).

You’re welcome to just copy and paste the code I wrote, seeing as you’re a newcomer to PsychoPy and coding I tried to comment as much as possible so you can see what it’s doing.

@TParsons Thank you for the clear and kind reply! Along your guidelines I managed to take steps forward. One thing I haven’t emphasized is that prospective cues must be additional items (a total of 64 items in the list), so they cannot simply replace other, non-prospective items. Thus, the changes I’ve made are the following:

> if trials.thisN == 0:
>     nonProsp = trials.trialList[4:]
>     random.shuffle(nonProsp)
>     trials.trialList[4:] = nonProsp
>     
>     prospDiffs = [6, 7, 8, 9, 10]
>     poz = 0
>     for i in [0, 1, 2, 3]:
>         poz += random.choice(prospDiffs)
>         tmp = trials.trialList[poz]
>         trials.trialList[poz] = trials.trialList[i]
>         trials.trialList[i] = tmp

This results in the expected form of randomization. The new problem is that whatever I say in this code component, the very first item is always the same. Could it be that the first trial has already been loaded before the code could work?

Moreover, if I print the list for the first trial, I got a different outcome from what can be seen during running.

Again, apologies if I misinterpret something and thanks for your time!

I think that’s exactly it, yes! I see now why you’d done for i in [0, 1, 2, 3]: originally; to keep the number of rows the same. What if you put the prospective trials at the end of the table? Then you could cycle i through [-1 -2 -3 -4], so it would replace the last 4 trials rather than the first 4.

Indeed, I put them to the 2nd, 3rd, 4th and 5th place, but this solution is practically the same. Thank you so much for your help, I really appreciate it! :slight_smile: