6.4 KiB
Creating an Experiment: Chunks, Blocks, & Trials
To create an experiment in jsPsych, you'll need to define the experiment structure. jsPsych experiments consist of three different structures: chunks, blocks, & trials. This page goes into detail about each kind of structure, and the features related to each.
The timeline analogy
A useful analogy for understanding chunks, blocks, & trials is a timeline. We can think of an experiment as being drawn on a timeline. The simplest version of the timeline would mark the occurrence of each trial in the experiment:
Sometimes, we might repeat the same kind of trial over and over again, just changing what stimulus is shown or with some other minor modification. jsPsych can group these trials together into a block, making it faster to define the structure of the experiment. With blocks, a timeline might look something like this:
But, what if we wanted to group trials together that weren't the same kind (i.e. didn't use the same plugin) but shared some other relationship? This is what a chunk does. Chunks are simply groups of blocks, but conceptually they are treated as if they are a whole separate timeline in jsPsych. This allows for more complex experiment designs, such as loops and conditional if statemens. With chunks, timelines can get very complicated if needed:
Defining an experiment
The jsPsych.init
method requires that an experiment definition is passed in as the value of the experiment_structure
parameter.
jsPsych.init({
experiment_structure: exp
})
The exp
variable above needs to be an array, with each element of the array being either a chunk or a block.
To create a block, define a JavaScript object with a type
property set to the particular plugin that the block uses. For example, to create a block using the jspsych-single-stim
plugin, the corresponding object would look something like:
var single_stim_block = {
type: 'single-stim',
stimulus: ['img/happy_face.png', 'img/sad_face.png']
}
jsPsych.init({
experiment_structure: [single_stim_block]
})
The above block contains two trials. The first trial will show the image file img/happy_face.png
and the second will show img/sad_face.png
. Different plugins have different methods for specifying multiple trials within a block. Check the documentation of the plugin that you are using for more details about how that plugin works.
To show instructions before the faces appear, define another block and add it to the experiment_structure
array:
var instructions_block = {
type: 'text',
text: 'Press H if the face is happy. Press S if the face is sad.'
}
var single_stim_block = {
type: 'single-stim',
stimulus: ['img/happy_face.png', 'img/sad_face.png']
}
jsPsych.init({
experiment_structure: [instructions_block, single_stim_block]
})
Let's imagine that we want subjects to keep viewing the faces until they get the correct response for each one. We can use a chunk to loop over the trials. To create a chunk, create an object with a chunk_type
property set to a valid chunk type and a timeline
property containing an array of chunks and blocks within the chunk. Some chunk types will require other properties to be set as well:
var instructions_block = {
type: 'text',
text: 'Press H if the face is happy. Press S if the face is sad.'
}
var single_stim_block = {
type: 'single-stim',
stimulus: ['img/happy_face.png', 'img/sad_face.png']
}
var looping_chunk = {
chunk_type: 'while',
timeline: [single_stim_block],
continue_function: function(data){
// code here to check if they got both answers correct.
// this is a bit too complicated for a simple tutorial
// about chunks and blocks, so imagine that the variable
// correct is true is they got both answers right, and
// false otherwise.
if(correct) { return false; }
else { return true; }
}
}
jsPsych.init({
experiment_structure: [instructions_block, looping_chunk]
})
Getting formal about definitions
What exactly are chunks, blocks, and trials?
A trial defines the parameters that will be used for a single execution of a plugin's plugin.trial
method. Since all experiments are defined in terms of plugins, this is the atomic unit of a jsPsych experiment.
A block is a collection of trials in which each trial uses the same plugin. Since it is very common in behavioral research to have multiple trials of the same type in a row with different stimuli, jsPsych experiments are defined at the block level by default. When creating the experiment_structure
array for the jsPsych.init
method, each element of the array can be either a block or a chunk.
A chunk is a collection of chunks or blocks that will be run in order. There are a few different kinds of chunks, which can be used to create experiments that loop or experiments that change which parts execute based on what the subject has done so far.
All three types are defined as JavaScript objects within the jsPsych code.
Chunk types
There are different types of chunks; each defines a different way of executing the chunk's timeline. To specify the chunk type, set the chunk_type
property of the chunk definition object.
var chunk = {
chunk_type: 'linear',
timeline: [block1, block2]
}
Linear
A linear chunk executes the timeline once and then is complete.
If the experiment_structure
property in jsPsych.init
contains blocks, they will be converted to linear chunks internally.
While
A while chunk can be used for looping. It executes the timeline and then calls the continue_function
to see if it should execute the timeline again. If the continue_function
returns true
, then the chunk executes again. If the function returns false
, the chunk is complete.
The continue_function
will be passed the data generated by the most recent execution of the chunk as the first parameter. The data will be an array; each item in the array will be the data for a single trial.
var while_chunk = {
chunk_type: 'while',
timeline: [block1, block2],
continue_function: function(data){
// check to see if the average RT was under 1s
var sum_rt = 0;
for(var i=0; i < data.length; i++){
sum_rt += data.rt;
}
var average_rt = sum_rt / data.length;
if(average_rt < 1000){
// end the loop
return false;
} else {
// keep going until they are faster!
return true;
}
}
}
If
An if chunk will only execute if some condition is met.