We have already seen that by default builder allows you to present trials in one of three orders, including:
From this we know that if we want a pre-specified order, the best way to do this is to use the ‘sequential’ option and specify that order in our conditions file. But what if we want more “custom”, “on-the-fly” randomisation.
Loops don’t just have to be used to present trials/repeat stimuli, they can also be used to load in your conditions file, and manipulate it how you want:
Once we know how to load our stimuli, we can use our python skills to manipulate the order of words from within our experiment itself.
Some cases where this can be useful:
and many more! We will practice with the first case example.
In this example, we are going to make sure every 5th word is presented in a fixed order, with the other words presented randomly. First, set up your conditions file to be something like this (but with more words).
Here our column “Word” is the word that will be presented and the column “Fixed” indicates if we want that word to be in a fixed location.
We could load these variables into our experiment in several ways. Remember that the ` Trial Handler <https://www.psychopy.org/api/data.html#psychopy.data.TrialHandler>`_ loads in a conditions file as a list of dictionaries. Infact, we can access that list directly using
trials is the name of our loop. Or we could access a single trial dictionary using
trials.trialList[n] where n is the index.
There are several inbuilt fuctions that can be handy for use with trialHandler:
trials.getCurrentTrial() - fetches the current trial info
trials.getFutureTrial(n) - fetches the info of the trial n ahead
trials.getEarlierTrial(n) - fetches the info of the trial n back
Once we have acess to the list of trials we can pick out our random trials:
oldTrials = myLoop.trialList randomTrials =  for myTrial in oldTrials: if not myTrial['Fixed']: randomTrials.append(myTrial)
Then we can piece our trialList back together by randomly sampling without replacement from the
newTrials =  for myTrial in oldTrials: if myTrial['Fixed']: # Use this trial newTrials.append(myTrial) else: # resample without replacement shuffle(randomTrials) newTrials.append(randomTrials[-1]) randomTrials.pop() print(newTrials)
Once we have our custom randomised trial list we need to use that in Builder. Usually we wrap a loop around a routine and feed in a conditions file. Then
nReps corresponds to the number of times we repeat that file. This time we need to do it a little differently…..
Add a routine called ‘showWords’ and inside it add a simple textBox component that lasts for 0.5 seconds. Wrap a loop around the routine and call it ‘trials’. This time we want nReps to correspond to the length of our custom trialList (‘newTrials’). So you can type
len(newTrials) in the nReps field.
len() might not smoothly translate in the nReps field. If that happens make a custom variable after the creation of ‘newTrials’ and use that instead in teh nReps field, e.g. :code:` myNReps = len(newTrials) will smoothly translate in a code component.
OK finally, we need to use the trial info from each run in our textBox component. In the Text field of the component type
newTrials[trials.thisN] and make sure to set every repeat.
trials.thisN might not smoothly translate (but it should do very soon). In place, you can use a code component to count the iterations, in the ‘Begin Experiment’ tab type
trialCount = 0 then in the ‘End Routine’ tab type
trialCount +=1 then use ‘trialCount’ in place of ‘trials.thisN’.
If you ran that now you might be surprised to see a full dictionary printed out on each trial. Remember each trial is a dictionary we need to access the value corresponding to the key ‘Word’. So for the final touch update
Present a list of numbers and alternate numbers between odd and even.
Hint: remember how we can seperate out specific conditions (e.g. randomTrials) and how we can sample without replacement using