All the base knowledge we assume at the start of this workshop can be learned from this 15 minute video
In this demo we will work through making a Numerical Stroop task in PsychoPy.
A builder experiment has three main sections. To start making an experiment we add routines to our flow and add components to our routines.
A Routine is the basic building block of PsychoPy experiments. They could be complex (e.g. a single trial) or simple (e.g. an Inter-Trial-Interval presenting a fixation cross).
To present several trials, add a loop around the routine to repeat. If something changes trial-by-trial, we make a spreadsheet (this can be made in Excel). Each header is a variable, each row corresponds to the value of that variable on each trial.
Then make sure to use that variable to set the parameter of a component on every repeat of your loop.
Let’s start by presenting a different pair of numbers on each trial and allowing the participant to press the left and right arrow keys to indicate a number.
Every experiment starts with a dialog box to gather some info about the participant/experiment. By default “participant” and “session” are gathered - and these are used to set the filename of that participant.
When you are finished, come back to the main session and collect one run of your task so that we can talk through the data file.
It is very easy to store accuracy from a keyboard in PsychoPy. In our experiment, the participant can press either the left or right arrow key. So, we add a column to our spreadsheet to indicate what the correct answer is.
In our keyboard component, we can then select “Store correct” and use the variable $corrAns
in the field.
A block design is where we have sets of similar trials organized into blocks rather than having trials interleaved.
Note: these are all cases where the components would be identical between blocks.
When people have several “blocks” the natural move is to add separate routines for those blocks:
However, if both blocks contain the same stimuli/elements (e.g. in a Numerical Stroop task where both valid/congruent and incongruent trials contain two numbers and a keyboard response), this is not the most efficient approach.
Instead of a Routine for each block, create a Routine for all your trials and make it behave differently across the blocks:
Then you can set the conditions files in your blocks loop to control the block-level changes. The outer “blocks” loop then takes a (meta) “conditions” file that specifies which of the conditions files will be loaded in each block.
If you do have two blocks that contain very different stimuli the approach to take is to control the number of times each block repeats using an outer-loop.
Imagine we want our task to include a block of neutral trials and a block of congruent/incongruent trials.
We need to create a total of 3 conditions files:
Using what we know about blocks, we could add a routine to tell the participants what kind of block they are about to enter. If our blocks.xlsx file has a column to label the condition, we can add a routine to introduce the block type.
You’ve sorted out block designs in a relatively neat fashion.
Just keep clear what differs from one block to the next (for a conditions file) and what stays the same (for the Routine definition).
Counterbalancing your blocks is really just an extension of the blocking scenario, except that you set the blocks to operate in a particular order rather than leaving PsychoPy to randomize them.
At the moment, PsychoPy doesn’t handle the ordering for you - you need to decide how to create the orders and how to assign participants.
So, you need a file per conditions order (e.g. A -> B and B-> A), then determine which file will be used for this group and use that file in the blocks loop
Remember to set the blocks loop to be `sequential` rather than `random` to preserve the order you set.
The easiest way is by hand at the start of the run for the participant. The steps are:
In Experiment Settings add a field for group (which will be A, B, C… for however many orders you need)
For the block loop use that value by calling expInfo[‘group’] using the code below:
$"block" + expInfo['group'] + ".xlsx"
Note
expInfo
is a python “dictionary” that stores all information from the startup GUI. Fields of a python dictionary are accessed using the format dictName['fieldName']
. It works the same locally and online and means you can set features of your experiment based on the input received at startup!
Let’s practice counterbalancing in different ways using the exercises in this folder (“builder > counterbalancingExercises”). In “exercise 1” you will find an inefficiently counterbalanced design. We want to improve this in two phases:
When you are finished, come back to the main session, if you run into any error messages please share them (on slack) and we can discuss them.
Sometimes we might have to counterbalance subtasks (i.e. routines that contain very different sets of components).
For this we would use the second blocking method we described earlier. You can wrap a loop around any set of routines and control if it is presented in your experiment, using nReps.
In the below we could control create the order C->B->A by using a conditions file where the nReps of each sub-loop are set per iteration of the outer-loop.
e.g. using a conditions file like this…
nRepsA | nRepsB | nRepsC |
---|---|---|
0 | 0 | 1 |
0 | 1 | 0 |
1 | 0 | 1 |
Where the nReps argument of each sub-loop is set using something like ‘$nRepsA’ etc.
Open exercise 2 in the counterbalanceExercises folder. This is very similar to our last task, but this time our two routines present different kinds of components, so we need to use a different method of counterbalancing.
We want a design where groupA sees cat images first and group B sees cat words first. Counterbalance this flow using the nReps arguments in the loops.
You can now create trials and blocks in any order, fixed or random and counterbalance subtasks!
You’re in complete control (but you need to understand what orders you want!)
Up next online