mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
update timeline overview for evaluateTimelineVariable, conditional function
This commit is contained in:
parent
63ce26e0f2
commit
33d8273097
@ -7,7 +7,7 @@ To create an experiment using jsPsych, you need to specify a timeline that descr
|
|||||||
To create a trial, you need to create an object that describes the trial. The most important feature of this object is the `type` parameter. This tells jsPsych which plugin to use to run the trial. For example, if you want to use the [html-keyboard-response plugin](../plugins/html-keyboard-response) to display a short message, the trial object would look like this:
|
To create a trial, you need to create an object that describes the trial. The most important feature of this object is the `type` parameter. This tells jsPsych which plugin to use to run the trial. For example, if you want to use the [html-keyboard-response plugin](../plugins/html-keyboard-response) to display a short message, the trial object would look like this:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var trial = {
|
const trial = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'Welcome to the experiment.'
|
stimulus: 'Welcome to the experiment.'
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ The parameters for this object (e.g., `stimulus`) will depend on the plugin that
|
|||||||
To create a timeline with the single trial and run the experiment, just embed the trial object in an array. A timeline can simply be an array of trials.
|
To create a timeline with the single trial and run the experiment, just embed the trial object in an array. A timeline can simply be an array of trials.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var timeline = [trial];
|
const timeline = [trial];
|
||||||
|
|
||||||
jsPsych.run(timeline);
|
jsPsych.run(timeline);
|
||||||
```
|
```
|
||||||
@ -32,21 +32,21 @@ Scaling up to multiple trials is straightforward. Create an object for each tria
|
|||||||
```javascript
|
```javascript
|
||||||
// with lots of trials, it might be easier to add the trials
|
// with lots of trials, it might be easier to add the trials
|
||||||
// to the timeline array as they are defined.
|
// to the timeline array as they are defined.
|
||||||
var timeline = [];
|
const timeline = [];
|
||||||
|
|
||||||
var trial_1 = {
|
const trial_1 = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'This is trial 1.'
|
stimulus: 'This is trial 1.'
|
||||||
}
|
}
|
||||||
timeline.push(trial_1);
|
timeline.push(trial_1);
|
||||||
|
|
||||||
var trial_2 = {
|
const trial_2 = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'This is trial 2.'
|
stimulus: 'This is trial 2.'
|
||||||
}
|
}
|
||||||
timeline.push(trial_2);
|
timeline.push(trial_2);
|
||||||
|
|
||||||
var trial_3 = {
|
const trial_3 = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'This is trial 3.'
|
stimulus: 'This is trial 3.'
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ timeline.push(trial_3);
|
|||||||
Each object on the timeline can also have it's own timeline. This is useful for many reasons. One is that it allows you to define common parameters across trials once and have them apply to all the trials on the nested timeline. The example below creates a series of trials using the [image-keyboard-response plugin](../plugins/image-keyboard-response/), where the only thing that changes from trial-to-trial is the image file being displayed on the screen.
|
Each object on the timeline can also have it's own timeline. This is useful for many reasons. One is that it allows you to define common parameters across trials once and have them apply to all the trials on the nested timeline. The example below creates a series of trials using the [image-keyboard-response plugin](../plugins/image-keyboard-response/), where the only thing that changes from trial-to-trial is the image file being displayed on the screen.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var judgment_trials = {
|
const judgment_trials = {
|
||||||
type: jsPsychImageKeyboardResponse,
|
type: jsPsychImageKeyboardResponse,
|
||||||
prompt: '<p>Press a number 1-7 to indicate how unusual the image is.</p>',
|
prompt: '<p>Press a number 1-7 to indicate how unusual the image is.</p>',
|
||||||
choices: ['1','2','3','4','5','6','7'],
|
choices: ['1','2','3','4','5','6','7'],
|
||||||
@ -75,7 +75,7 @@ In the above code, the `type`, `prompt`, and `choices` parameters are automatica
|
|||||||
You can also override the values by declaring a new value in the `timeline` array. In the example below, the second trial will display a different prompt message.
|
You can also override the values by declaring a new value in the `timeline` array. In the example below, the second trial will display a different prompt message.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var judgment_trials = {
|
const judgment_trials = {
|
||||||
type: jsPsychImageKeyboardResponse,
|
type: jsPsychImageKeyboardResponse,
|
||||||
prompt: '<p>Press a number 1-7 to indicate how unusual the image is.</p>',
|
prompt: '<p>Press a number 1-7 to indicate how unusual the image is.</p>',
|
||||||
choices: ['1','2','3','4','5','6','7'],
|
choices: ['1','2','3','4','5','6','7'],
|
||||||
@ -102,7 +102,7 @@ Suppose we want to create an experiment where people see a set of faces. Perhaps
|
|||||||
Here's a basic version of the task with timeline variables.
|
Here's a basic version of the task with timeline variables.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [
|
timeline: [
|
||||||
{
|
{
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
@ -131,7 +131,7 @@ In the above version, there are four separate trials defined in the `timeline_va
|
|||||||
What if we wanted to add an additional step to the task where the name is displayed prior to the face appearing? (Maybe this is one condition of an experiment investigating whether the order of name-face or face-name affects retention.) We can add another variable to our list that gives the name associated with each image. Then we can add another trial to our timeline to show the name.
|
What if we wanted to add an additional step to the task where the name is displayed prior to the face appearing? (Maybe this is one condition of an experiment investigating whether the order of name-face or face-name affects retention.) We can add another variable to our list that gives the name associated with each image. Then we can add another trial to our timeline to show the name.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [
|
timeline: [
|
||||||
{
|
{
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
@ -161,14 +161,15 @@ var face_name_procedure = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using in a function
|
### Using timeline variables in a function
|
||||||
|
|
||||||
Continung the example from the previous section, what if we wanted to show the name with the face, combining the two variables together?
|
Continung the example from the previous section, what if we wanted to show the name with the face, combining the two variables together?
|
||||||
To do this, we can use a [dynamic parameter](dynamic-parameters.md) (a function) to create an HTML-string that uses both variables in a single parameter.
|
To do this, we can use a [dynamic parameter](dynamic-parameters.md) (a function) to create an HTML-string that uses both variables in a single parameter.
|
||||||
|
However, because we are getting the value of a timeline variable in a function, we need to use `jsPsych.evaluateTimelineVariable()` instead of `jsPsych.timelineVariable()`. `.evaluateTimelineVariable()` immediately gets the value of the variable when it is called, while `.timelineVariable()` creates a placeholder that jsPsych evaluates at the appropriate time during the execution of the experiment.
|
||||||
The value of the `stimulus` parameter will be a function that returns an HTML string that contains both the image and the name.
|
The value of the `stimulus` parameter will be a function that returns an HTML string that contains both the image and the name.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [
|
timeline: [
|
||||||
{
|
{
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
@ -185,9 +186,9 @@ var face_name_procedure = {
|
|||||||
{
|
{
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: function(){
|
stimulus: function(){
|
||||||
var html = `
|
const html = `
|
||||||
<img src="${jsPsych.timelineVariable('face')}">
|
<img src="${jsPsych.evaluateTimelineVariable('face')}">
|
||||||
<p>${jsPsych.timelineVariable('name')}</p>`;
|
<p>${jsPsych.evaluateTimelineVariable('name')}</p>`;
|
||||||
return html;
|
return html;
|
||||||
},
|
},
|
||||||
choices: "NO_KEYS",
|
choices: "NO_KEYS",
|
||||||
@ -205,10 +206,10 @@ var face_name_procedure = {
|
|||||||
|
|
||||||
### Random orders of trials
|
### Random orders of trials
|
||||||
|
|
||||||
If we want to randomize the order of the trials, we can set `randomize_order` to `true`.
|
If we want to randomize the order of the trials defined with timeline variables, we can set `randomize_order` to `true`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -239,7 +240,7 @@ Valid values for `type` are
|
|||||||
This `sample` parameter will create 10 repetitions, sampling with replacement.
|
This `sample` parameter will create 10 repetitions, sampling with replacement.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -259,7 +260,7 @@ var face_name_procedure = {
|
|||||||
This `sample` parameter will make the "Alex" trial three times as likely to be sampled as the others.
|
This `sample` parameter will make the "Alex" trial three times as likely to be sampled as the others.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -280,7 +281,7 @@ var face_name_procedure = {
|
|||||||
This `sample` parameter will pick three of the four possible trials to run at random.
|
This `sample` parameter will pick three of the four possible trials to run at random.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -300,7 +301,7 @@ var face_name_procedure = {
|
|||||||
This `sample` parameter will create 3 repetitions of each trial, for a total of 12 trials, with a random order.
|
This `sample` parameter will create 3 repetitions of each trial, for a total of 12 trials, with a random order.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -323,7 +324,7 @@ The resulting sample of trials will follow the pattern `group 1` -> `group 2` ->
|
|||||||
If you wanted `group 2` to sometimes be first, you could set `randomize_group_order: true`.
|
If you wanted `group 2` to sometimes be first, you could set `randomize_group_order: true`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -347,7 +348,7 @@ The function has a single parameter, `t`, which is an array of integers from `0`
|
|||||||
The function must return an array that specifies the order of the trials, e.g., returning `[3,3,2,2,1,1,0,0]` would result in the order `Dave` -> `Dave` -> `Chad` -> `Chad` -> `Beth` -> `Beth` -> `Alex` -> `Alex`.
|
The function must return an array that specifies the order of the trials, e.g., returning `[3,3,2,2,1,1,0,0]` would result in the order `Dave` -> `Dave` -> `Chad` -> `Chad` -> `Beth` -> `Beth` -> `Alex` -> `Alex`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -369,12 +370,12 @@ var face_name_procedure = {
|
|||||||
To repeat a timeline multiple times, you can create an object (node) that contains a `timeline`, which is the timeline array to repeat, and `repetitions`, which is the number of times to repeat that timeline.
|
To repeat a timeline multiple times, you can create an object (node) that contains a `timeline`, which is the timeline array to repeat, and `repetitions`, which is the number of times to repeat that timeline.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var trial = {
|
const trial = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'This trial will be repeated twice.'
|
stimulus: 'This trial will be repeated twice.'
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = {
|
const node = {
|
||||||
timeline: [trial],
|
timeline: [trial],
|
||||||
repetitions: 2
|
repetitions: 2
|
||||||
}
|
}
|
||||||
@ -383,7 +384,7 @@ var node = {
|
|||||||
The `repetitions` parameter can be used alongside other node parameters, such as timeline variables, loop functions, and/or conditional functions. If you are using `timeline_variables` and `randomize_order` is `true`, then the order of the timeline variables will re-randomize before every repetition.
|
The `repetitions` parameter can be used alongside other node parameters, such as timeline variables, loop functions, and/or conditional functions. If you are using `timeline_variables` and `randomize_order` is `true`, then the order of the timeline variables will re-randomize before every repetition.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
@ -399,17 +400,18 @@ var face_name_procedure = {
|
|||||||
## Looping timelines
|
## Looping timelines
|
||||||
|
|
||||||
Any timeline can be looped using the `loop_function` option.
|
Any timeline can be looped using the `loop_function` option.
|
||||||
The loop function must be a function that evaluates to `true` if the timeline should repeat, and `false` if the timeline should end. It receives a single parameter, named `data` by convention.
|
The loop function must be a function that evaluates to `true` if the timeline should repeat, and `false` if the timeline should end.
|
||||||
|
It receives a single parameter, named `data` by convention.
|
||||||
This parameter will be the [DataCollection object](../reference/jspsych-data.md#datacollection) with all of the data from the trials executed in the last iteration of the timeline.
|
This parameter will be the [DataCollection object](../reference/jspsych-data.md#datacollection) with all of the data from the trials executed in the last iteration of the timeline.
|
||||||
The loop function will be evaluated after the timeline is completed.
|
The loop function will be evaluated after the timeline is completed.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var trial = {
|
const trial = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'This trial is in a loop. Press R to repeat this trial, or C to continue.'
|
stimulus: 'This trial is in a loop. Press R to repeat this trial, or C to continue.'
|
||||||
}
|
}
|
||||||
|
|
||||||
var loop_node = {
|
const loop_node = {
|
||||||
timeline: [trial],
|
timeline: [trial],
|
||||||
loop_function: function(data){
|
loop_function: function(data){
|
||||||
if(jsPsych.pluginAPI.compareKeys(data.values()[0].response, 'r')){
|
if(jsPsych.pluginAPI.compareKeys(data.values()[0].response, 'r')){
|
||||||
@ -428,25 +430,27 @@ If the conditional function evaluates to `true`, the timeline will execute norma
|
|||||||
If the conditional function evaluates to `false` then the timeline will be skipped.
|
If the conditional function evaluates to `false` then the timeline will be skipped.
|
||||||
The conditional function is evaluated whenever jsPsych is about to run the first trial on the timeline.
|
The conditional function is evaluated whenever jsPsych is about to run the first trial on the timeline.
|
||||||
|
|
||||||
```javascript
|
If you use a conditional function and a loop function on the same timeline, the conditional function will only evaluate once.
|
||||||
var jsPsych = initJsPsych();
|
|
||||||
|
|
||||||
var pre_if_trial = {
|
```javascript
|
||||||
|
const jsPsych = initJsPsych();
|
||||||
|
|
||||||
|
const pre_if_trial = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'The next trial is in a conditional statement. Press S to skip it, or V to view it.'
|
stimulus: 'The next trial is in a conditional statement. Press S to skip it, or V to view it.'
|
||||||
}
|
}
|
||||||
|
|
||||||
var if_trial = {
|
const if_trial = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'You chose to view the trial. Press any key to continue.'
|
stimulus: 'You chose to view the trial. Press any key to continue.'
|
||||||
}
|
}
|
||||||
|
|
||||||
var if_node = {
|
const if_node = {
|
||||||
timeline: [if_trial],
|
timeline: [if_trial],
|
||||||
conditional_function: function(){
|
conditional_function: function(){
|
||||||
// get the data from the previous trial,
|
// get the data from the previous trial,
|
||||||
// and check which key was pressed
|
// and check which key was pressed
|
||||||
var data = jsPsych.data.get().last(1).values()[0];
|
const data = jsPsych.data.get().last(1).values()[0];
|
||||||
if(jsPsych.pluginAPI.compareKeys(data.response, 's')){
|
if(jsPsych.pluginAPI.compareKeys(data.response, 's')){
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -455,7 +459,7 @@ var if_node = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var after_if_trial = {
|
const after_if_trial = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
stimulus: 'This is the trial after the conditional.'
|
stimulus: 'This is the trial after the conditional.'
|
||||||
}
|
}
|
||||||
@ -468,7 +472,7 @@ jsPsych.run([pre_if_trial, if_node, after_if_trial]);
|
|||||||
You can run a custom function at the start and end of a timeline node using the `on_timeline_start` and `on_timeline_finish` callback function parameters. These are functions that will run when the timeline starts and ends, respectively.
|
You can run a custom function at the start and end of a timeline node using the `on_timeline_start` and `on_timeline_finish` callback function parameters. These are functions that will run when the timeline starts and ends, respectively.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var procedure = {
|
const procedure = {
|
||||||
timeline: [trial_1, trial_2],
|
timeline: [trial_1, trial_2],
|
||||||
on_timeline_start: function() {
|
on_timeline_start: function() {
|
||||||
console.log('The trial procedure just started.')
|
console.log('The trial procedure just started.')
|
||||||
@ -482,7 +486,7 @@ var procedure = {
|
|||||||
This works the same way with timeline variables. The `on_timeline_start` and `on_timeline_finish` functions will run when timeline variables trials start and end, respectively.
|
This works the same way with timeline variables. The `on_timeline_start` and `on_timeline_finish` functions will run when timeline variables trials start and end, respectively.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var face_name_procedure = {
|
const face_name_procedure = {
|
||||||
timeline: [...],
|
timeline: [...],
|
||||||
timeline_variables: [
|
timeline_variables: [
|
||||||
{ face: 'person-1.jpg', name: 'Alex' },
|
{ face: 'person-1.jpg', name: 'Alex' },
|
||||||
|
Loading…
Reference in New Issue
Block a user