# Summary of Tutorial Content This tutorial will step through the creation of a simple response time task. The subject is asked to respond to blue circles by pressing the F key, but to not respond to orange circles. The concepts covered in the tutorial include: * Creating trials to show instructions. * Creating trials to show stimuli and measure response time. * Using the randomization methods of the jsPsych library. * Tagging trials with additional data to describe within-subject conditions. * Using functions as trial parameters to generate dynamic content. * Using callback functions to process the data for a trial immediately after the trial ends. ## Part 1: Creating a blank experiment Start by downloading jsPsych and setting up a folder to contain your experiment files. If you are unsure how to do this, follow steps 1-5 in the [Hello World tutorial](hello-world.md). At the end of step 5 in the Hello World tutorial, you should have an experiment page that looks like this: ```html
In this experiment, a circle will appear in the center " + "of the screen.
If the circle is blue, " + "press the letter F on the keyboard as fast as you can.
" + "If the circle is orange, do not press " + "any key.
" + "Press the F key
Do not press a key
Press any key to begin.
" }; ``` Don't forget to add it to the experiment definition array: ```javascript timeline.push(instructions_block); ``` ### The complete code so far ```htmlIn this experiment, a circle will appear in the center " + "of the screen.
If the circle is blue, " + "press the letter F on the keyboard as fast as you can.
" + "If the circle is orange, do not press " + "any key.
" + "Press the F key
Do not press a key
Press any key to begin.
", timing_post_trial: 2000 }; ``` Now, let's modify the test block so that the subject only has 1,500 milliseconds to respond before the trial ends. ```javascript var test_block = { type: 'single-stim', choices: ['F'], timing_response: 1500, timeline: all_trials }; ``` If you are wondering where to figure out what the various parameter options for a plugin are, each plugin has its own [documentation page](../plugins/overview.md) which gives a list of all the parameters for that plugin and what the default values are. ## Part 9: Displaying the data We have created a somewhat reasonable experiment at this point, so let's take a look at the data being generated. jsPsych has a handy [function called `jsPsych.data.displayData()`](../core_library/jspsych-data.md#jspsychdatadisplaydata) that is useful for debugging your experiment. It will remove all of the information on the screen and replace it with the raw data collected so far. This isn't terribly useful when you are actually running an experiment, but it's very handy for checking the data during development. We need the `displayData` function to execute when the experiment ends. One way to do this is to use the [`on_finish` callback function](../features/callbacks.md#on_finish-experiment). This function will automatically execute once all the trials in the experiment are finished. We can specify a function to call in the `init` method. ```javascript jsPsych.init({ timeline: timeline, on_finish: function() { jsPsych.data.displayData(); } }); ``` ## Part 10: Adding tagging data to a trial All trials in jsPsych can be tagged with additional arbitrary data. This data will get stored alongside the data that the plugin generates, which allows experimenters to record properties of a trial with the data from the trial. In this example experiment, we are going to tag each trial as being either a `go` or a `no-go` trial. In this particular example, this is somewhat redundant, since we can determine the trial type by looking at the stimulus that was displayed. However, the technique is essential in many circumstances for marking the data for subsequent analysis. Adding tagging data involves setting the `data` parameter of a trial. Like other parameters, you can set the `data` parameter of any object and it will be passed on to the objects in the timeline. In this particular experiment, we want to set the data parameter for each type of stimulus. We can do that by adding a data property to the items in the `test_stimuli` array: ```javascript var test_stimuli = [ { stimulus: "img/blue.png", data: { response: 'go' } }, { stimulus: "img/orange.png", data: { response: 'no-go' } } ]; ``` The value for the data property should be an object. Each key in the object will be a new entry in the data for that trial, with the corresponding value attached. ## Part 11: Using functions as parameters One methodological flaw in our experiment right now is that the time between trials is always the same. This will let people anticipate the response as they learn how much time is in between the trials. We can fix this by generating a random value for the `timing_post_trial` parameter in the test block. Most jsPsych plugins will allow you to set the value of a parameter as a function. The function will be called at the start of the trial, and the parameter will be replaced with the return value of the function. We will create a simple function to generate a random value for the timing_post_trial parameter: ```javascript var post_trial_gap = function() { return Math.floor( Math.random() * 1500 ) + 750; } ``` The above function will return a random value between 750 and 2250, with uniform sampling from the range. You can do whatever you like inside a function that is a parameter, as long as the return value is a valid value for the parameter. Now that we've got a function that generates a random time, we can specify the `timing_post_trial` parameter in the testing block. ```javascript var test_block = { type: "single-stim", choices: ['F'], timing_response: 1500, timing_post_trial: post_trial_gap, timeline: all_trials }; ``` If you run the experiment, you'll notice that the interval between trials changes randomly throughout the experiment. ## Part 12: Adding data to a trial that is based on the subject's performance If you examine the data generated by the experiment, one thing that is missing is any direct indication of whether the subject responded correctly or not. It's possible to derive the correctness of the response by looking at a combination of the `rt` and `stimulus` values, but for subsequent analysis, it would also be useful to tag each trial with a `correct` property that is either `true` or `false`. We can only determine whether a trial should be marked as correct or not after the trial is complete. What we really want to do is run some code after each trial to determine the correctness of the response that was made. We can use the `on_finish` event to do this. If we attach an `on_finish` event handler to a trial, we can execute a function immediately after the trial ends. The event handler (a function) is passed a single argument containing the data generated by the trial. In the example below, the event handler calculates the correctness of the response, and then uses the jsPsych.data.addDataToLastTrial method to add a correct property to the previous trial. ```javascript var test_block = { type: "single-stim", choices: ['F'], timing_response: 1500, timing_post_trial: post_trial_gap, on_finish: function(data){ var correct = false; if(data.response == 'go' && data.rt > -1){ correct = true; } else if(data.response == 'no-go' && data.rt == -1){ correct = true; } jsPsych.data.addDataToLastTrial({correct: correct}); }, timeline: all_trials }; ``` ## Part 13: Displaying data to the subject We've got a reasonable experiment at this point. One thing that subjects might appreciate is knowing how well they performed at the end of the experiment. We will create a simple debriefing screen at the end of the experiment that shows the subject their accuracy and average response time on correct responses. First, we need a function to compute the subject's accuracy and mean RT. We will use the `jsPsych.data.getTrialsOfType()` method to get the data from all the trials run by the single-stim plugin. Then we will iterate through that data to compute the desired measures. ```javascript function getSubjectData() { var trials = jsPsych.data.getTrialsOfType('single-stim'); var sum_rt = 0; var correct_trial_count = 0; var correct_rt_count = 0; for (var i = 0; i < trials.length; i++) { if (trials[i].correct == true) { correct_trial_count++; if(trials[i].rt > -1){ sum_rt += trials[i].rt; correct_rt_count++; } } } return { rt: Math.floor(sum_rt / correct_rt_count), accuracy: Math.floor(correct_trial_count / trials.length * 100) } } ``` Next, we add a trial using the text plugin to show the response time. However, there's one catch. We want to use the function we just added above to get the average response time of the subject. But we can't do this until the experiment is over. Therefore, we need to use a *function* as the value of the `text` parameter in the block. This will result in the function being called right when the trial begins. If we didn't do this, then the `getAverageResponseTime()` function would be executed at the beginning of the experiment, which would be bad since there is no data at that point! ```javascript var debrief_block = { type: "text", text: function() { var subject_data = getSubjectData(); return "You responded correctly on "+subject_data.accuracy+"% of "+ "the trials.
Your average response time was " + subject_data.rt + "ms. Press any key to complete the "+ "experiment. Thank you!
"; } }; ``` We need to add the debrief block to the experiment definition array. ```javascript timeline.push(debrief_block); ``` ## The final code ```html