mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-11 16:18:11 +00:00
153 lines
6.4 KiB
Markdown
153 lines
6.4 KiB
Markdown
# 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.
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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.
|
|
|
|
```javascript
|
|
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.
|
|
|
|
```javascript
|
|
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.
|
|
|
|
|