psychopy.org | Reference | Downloads | Github

Pseudo-randomization of stimuli trials in a loop

**OS: macOS Catalina 10.15.6
**PsychoPy version: 2020.1.2
**Standard Standalone: YES

What are you trying to achieve?:
Pseudo-randomize trials in a loop using custom code in the builder.

What did you try to make it work?:
Checking the psychoPy source code and trying to understand a bit how things work. I copied pasted some parts to the “Beginning of the Routine” tab of the 1st routine within my loop and adjusted them to set a custom order of trials regardless of the order they appear in my excel file. I used the following code:

#This is only an example, the number of trials and their order can vary as pleased
customOrder = np.array([[2], [3], [0], [1]])  
myLoop.sequenceIndices = customOrder

The code runs the first trial based on the original order and later runs the rest of the trials in the custom order. Furthermore, the experiment seems to crash when the trial shown as the first one is about to be ran in the next loop according to the custom order. For example, if the the originally random order of the trails is 0, 1, 2, 3, (i.e. the 1st row in the stimuli list is to be run first, then the 2nd row, and so on), the code above (showing a custom order of 2, 3, 0, 1) correctly runs the first two trials (with the third and the fourth row in the stimuli list) but crashes when attempting to run the third loop with the first row. I receive the following error message:

WARNING need a bigger array for: ran

I think the problem is related to an old post that I found by googling: https://groups.google.com/g/psychopy-dev/c/-LOALuQoENs?pli=1

Any ideas of how to make this approach work? Ideally I would have to assign the order of assign the otrder of the stimuli with myLoop.sequenceIndices = customOrder when the loop element is created before starting the first routine of the loop.

Best,
Miguel

Hi There,

This is actually tricky to implement in builder because of the order in which objects are created (you probably noticed this from exporting your experiment to code).

Usually if a preset order is needed we recommend setting the conditions file to be in that order and using the ‘sequential’ loop method (if you have a new order for each participant make a set of conditions files and use something like $'conditions'+expInfo['participant']+'xlsx' in the conditions field of the loop - is there a reason that this wouldn’t be suitable for this context?

Thanks,
Becca

@Becca Thank you very much for the response. I think your approach would work well, although it is a somewhat messy (and time consuming) to create a different and separate conditions file per participant. I have have worked today in the same issue and I just out a way to do it quite nicely.

I defined a function in the “beginning of the experiment” tab of a code component that would take the name of excel file containing the trials as argument to load the trials in their original order, then randomize such trials based on some particular condition(s) and finally would return a list of the final order of such trials. Setting a loop in the builder to follow a “sequential order” rather than a “random order”, I called the function that I created in the “selected rows” space and the result is that psychoPy presents stimuli in the exact sequential order that my pseudo-randomization function returns.

Note that: For this approach to work, it is important to have a column in the conditions files that indexes the original sequential order of the stimuli so that once the stimuli list is correctly randomized the final order of the trials can be retrieved.

Here is the code that I used. To illustrate, I set the randomization condition to not allow two consecutive trials of the same stimuli type:

def pseudoRand(excelFile):
    # Load trials
    trials=data.importConditions(excelFile)
    conditionMet = False
    # Pseudo-randomize trials
    while conditionMet == False:
        random.shuffle(trials)
        conditions = []
        for row in range(len(trials)):
            conditions.append(trials[row]["stimuliCondition"])  #Name of the conditions type column
        # Condition for pseudo-randomization: No consecutive same type
        for row in range(len(trials) - 1):
            if trials[row]["stimuliCondition"] == trials[row + 1]["stimuliCondition"]:
                conditionMet = False
                break
            else:
                conditionMet = True
    # Save the final order of the trials
    customOrder = []
    for row in range(len(trials)):
        customOrder.append(trials[row]["originalIndex"]) #Name of the original index column
    return customOrder

Hi Miguel,

Pleased you found a solution. With regards to it being messy to make multiple conditions files. You can use code to do this.

For example, I use code to create several .csv files for counterbalancing https://gitlab.pavlovia.org/lpxrh6/counterbalance_conditions

Becca

1 Like