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” randomization.
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:
print(Word)
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).
Word | Fixed | N |
---|---|---|
Cat | 0 | 1 |
Dog | 0 | 2 |
Fish | 0 | 3 |
Owl | 0 | 4 |
Tree | 1 | 5 |
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.
Word | Fixed | N |
---|---|---|
Cat | 0 | 1 |
Dog | 0 | 2 |
Fish | 0 | 3 |
Owl | 0 | 4 |
Tree | 1 | 5 |
We could load these variables into our experiment in several ways. Remember that the Trial Handler loads in a conditions file as a list of dictionaries. In fact, we can access that list directly using trials.trialList
where trials
is the name of our loop. Or we could access a single trial dictionary using trials.trialList[n]
where n is the index.
Note
There are several inbuilt functions 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 access 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 randomTrials
list:
newTrials = []
for myTrial in oldTrials:
if myTrial['Fixed']:
# Use this trial
newTrials.append(myTrial)
else:
# re sample without replacement
shuffle(randomTrials)
newTrials.append(randomTrials[-1])
randomTrials.pop()
print(newTrials)
Once we have our custom randomized 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.
Note
Online 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.
Note
Online 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 newTrials[trials.thisN]
to newTrials[trials.thisN]['Word']
This exercise will make a list of trials entirely through code, without the need to import an external conditions file. You will need a routine with a code component to create your trialList then a routine with a loop to iterate through that trial list:
Tip: remember we can sample without replacement using :code:`shuffle()` and :code:`pop()` so that the selection of numbers is random each time - this method works locally and online