Last week, we learned how to build simple web experiments using JSPsych. In those experiments, you displayed images to participants and recorded their responses.

Reaction time experiments like this have traditionally been used with adults, but for young children these tasks are typically too demanding. Experiments with young children typically have some of the following characteristics:

  1. The key dependent variable is usually accuracy rather than reaction time. For example, in the child-friendly stroop task known as the Day-Night task, children have to say “Day” when shown a picture of the moon, and say “Night” when shown a picture of the sun. The dependent variable is not their reaction time, but the number of mistakes they make (i.e., their accuracy).
  2. Experiments have to be paced according to the demands of the child. Adult experiments typically have short inter-trial intervals, and are automatically paced. But that doesn’t work for developmental experiments, where children might get distracted. Instead, the experimenter needs to be able to start and stop the experiment as they go.
  3. Kids don’t use keyboards. At least, little kids don’t. So in most experiments children either provide a verbal response, or they point to a response.

1 Set up your lab workspace and make an RHTML file.

Create a new directory for this week’s lab, and then create a Folder in it called ColourExpt. Download the JsPsych zip file from Learn like last week, unzip it, and place the jspsych-5.0.3 folder in the ColourExpt folder. Make sure that it has unzipped properly (e.g., some people had problems with double folders being created last time).

Create a new RHTML file called ColourExpt.RHTML, save it and knit it.

2 Let’s learn some more about debugging

Last week, we ran into a lot of trouble because our websites didn’t work, and we couldn’t always determine why. Debugging is the process of determining when and why a programme fails. When a website fails it will sometimes send a diagnostic message to the web-browser, and a debugger will help us to see that message. In addition, when we’ve written our own code for a website, we can ensure that that site should send diagnostic messages in situations where the website has failed.

Open your website in a web browser like Mozilla Firefox, Google Chrome, or Internet Explorer (the easiest way to do that is by opening ColourExpt.HTML [not .RHTML] from its folder). Hopefully the website should open without problems. In the menu bar on the top right of the screen, you’ll see a Developer Tools icon. If you can’t find it, ask Hugh. Click on that, and various options will open up; from these, click on Web Console. It should look like something this:

Tabs from the developer windows

Tabs from the developer windows

These tabs will do a variety of cool things. The Inspector tab allows you to look at the HTML code for a website, and how it relates to the elements displayed on your screen. The Style Editor tab allows you to examince the .css files associated with your webpage. The Debugger tab allows you to examine the .js files associated with a web page (there aren’t any right now).

The Console tab is the most important right now. The Console is a little bit like the Console in R Studio. For example if you type 2+2 into the command line at the bottom of the console, it will calculate the result. But for your purposes, the console is most crucial because it will allow you to see error messages printed by, e.g., javascript functions or plugins that you use, and also messages that you yourself print to the console, to help you with debugging.

We can play around with this by modifying the ColourExpt.HTML file so that it looks like your SimpleExpt from last time. Delete the unnecessary R code and add the following to the header:

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="jspsych-5.0.3/jspsych.js"></script>
        <script src="jspsych-5.0.3/plugins/jspsych-text.js"></script>
        <link href="jspsych-5.0.3/css/jspsych.css" rel="stylesheet" type="text/css"></link>

and the following between <script> tags:


    var hello_trial = {
        type: 'text',
        text: 'Hello world!'
    }
    
    var goodbye_trial = {
        type: 'text',
        text: 'Goodbye cruel world!'
    }
    
    jsPsych.init({
        timeline: [ hello_trial, goodbye_trial ]
    })
    

Knit the experiment, and open it in Firefox. Hopefully it all works. If it does not work, Open the Developer console, as before, look at the error messages and call Hugh over if you can’t figure out why.

2.1  Reference Errors

If everything has worked, we will now break the experiment a bit, and see what error messages get logged.

First, change your call to jsPsych.init() so that goodbye_trial is replaced with goodbye_trail (note the different spelling). Knit the file, refresh your .html file in your web browser, and look at the console. You should see a message like this:

Simple debug message

Simple debug message

There are two buttons that you can click on here. If you click Learn More then you will be taken to a webpage that offers an explanation of the programming error that you have made (i.e., there is no variable called goodbye_trail; it is not defined).

Meanwhile, on the far right of the error message should be a link to ColourExpt.html:93:94 (the numbers might be a little different depending on the structure of your HTML code). This indicates that the source of the programming error is in the file ColourExpt.html, on lines 93-94. Click on that link and it will open the html file in the debugger, on the relevant lines. You can see that goodbye_trail is on the indicated line. However, you can’t change it from within Firefox. Instead, you have to go back to RStudio and edit it. Do that now.

2.2  Syntax Errors

Having replaced goodbye_trail with goodbye_trial, let’s now create a syntax error. Edit the var goodbye_trial so that there is no longer a curly brackets after the line text: 'Goodbye cruel world'. Remember that those little curly brackets contain sets of Key:Value pairs, and that each open bracket must have a closing brackets. Knit the file and refresh in Firefox. This time you should see an error like this:

Missing comma error

Missing comma error

Click on Learn More, and you should find a nice description of why the error is being thrown. Use the links on the console to find out where in the HTML file your error is, and then go back to RStudio to fix it.

For another example, try deleting the final quote mark from text: 'Hello world!'. Reknit the experiment and look at the error message. Now trying deleting one of the commas separating the Key : Value pairs in var goodbye_world.

2.3  Missing plugin

Delete the Text plugin from the Head of your RHTML file

        <script src="jspsych-5.0.3/plugins/jspsych-text.js"></script>

And then knit your file and reload in Firefox.

You should see that JsPsych has printed a nice error message to remind you that there is no plugin loaded for trials of type Text.

2.4  Printing your own console messages

JsPsych also gives you the means to print your own console messages before and after each trial.

To print console messages when a trial starts, we use a key:value pair like the one below:

        on_start: function() {
          console.log('This trial just started.');
        },

This key:value pair is added to one of your trial vars, like hello_trial or goodbye_trial. The key on_start: takes as its value a function. In this case, our function has the following syntax:

function() {
          console.log('This trial just started.');
        }

The first part, function() simply specifies that this is a function, and that when this function is called, then the operations in the curly braces should be carried out. In this case, the operation is to use console.log to print a message to the console.

To print console messages after a trial, use the following commands:

        on_finish: function() {
          console.log('This trial just finished.');
        },

Edit your experiment so that it prints to the console at the start of hello_trial and at the end of goodbye_trial. Make sure you’ve understood and carried out all the different debugging activities here.

3 Building a touch screen experiment

By going through the preceding section, you have hopefully learned some useful skills for debugging your experiments. That’s going to be extra important now, as we start to build a more complex touch screen experiment. There’ll be lots of error messages.

3.1 A basic touch screen experiment

The standard method for letting participants interact with a JsPsych experiment is through a keyboard. However, we want to use touch screen devices that don’t have keyboards, so we can’t code our experiments the same way as last time. Instead, what we need to do is display stimuli as buttons that participants can press. We’ll gradually build an experiment in which participants can choose whether to press an orange or a blue button.

3.1.1 Add buttons to your basic colour experiment

Building on the RHTML file that you already created, add the plugin for a button response.

<script src="jspsych-5.0.3/plugins/jspsych-button-response.js"></script>

And then turn your hello_trial into a button response:

    var hello_trial = {
        type: 'button-response',
        choices: ['Hello world!']
    }

Knit the HTML, and hopefully you will see a little button that says “Hello World!”. Press the button, and the trial should advance.

3.1.2 Add images to your button

Let’s make a button with an image on it. Add the following to your hello_trial, and make sure that in your lab directory you have an img folder that contains the image files blue.png and orange.png, which you can find in the tests&examples folder in the jspsych-5.0.3 folder.

button_html: ['<img src="img/orange.png" height="250px" width="250px"/>']

This little piece of HTML should add an image to your button of height 250 pixels and width 250 pixels, with the location of the image specified by src. Knit your experiment to test.

3.1.3 Two buttons at a time

Let’s try and create an experiment in which kids will see two images at a time, and will then choose one. That’s pretty easy to programme in JsPsych!

Edit your code as below; you’ll note that I’ve spread the code over multiple lines, and also indented it, to improve readability.

    var hello_trial = {
        type: 'button-response',
        choices: [
          'orange',
          'blue'
        ],
        button_html: [
            '<img src="img/orange.png" height="250px" width="250px"/>',
            '<img src="img/blue.png" height="250px" width="250px"/>'
        ]
    }

This code does a couple of key things.

  1. The choices key takes an array with two options, orange and blue. This means that there will be two buttons, one called “orange” and one called “blue”.
  2. the button_html key takes an array that contains the HTML that will be displayed on each button, i.e., an orange image and a blue image. Yell if you don’t understand this.

Note that in the two arrays, the ‘orange’ option is placed first and the blue option is placed second. This is important, because it means that when you select the orange picture, JsPsych will record your choice as orange.

3.1.4 Randomize the button layout

Its important that you randomize which side the relevant buttons appear on. Here’s one way to do that.

Create a var called button_stimuli that equals an array containing the html code for the two buttons; i.e., ['<img src="img/orange.png" height="250px" width="250px"/>','<img src="img/blue.png" height="250px" width="250px"/>']. Make sure it is placed above hello_trial.

Now, create a var called shuffled_button_stimuli that equals the following: jsPsych.randomization.shuffle(button_stimuli). What this means is that the value of the variable shuffled_button_stimuli should be a random ordering of the two pieces of HTML in the array.

Finally, edit the hello_trial var so that the value of the key button_html is replaced with shuffled_button_stimuli. Knit your html and refresh it a few times in your browser. Hopefully the two colours should randomly switch sides (you may need to refresh quite a few times, as this will be a fully random process).

Can you think of a problem with this design? Think about the relationship between the choices key and the button_html key. By randomizing one but not the other, you have disrupted the systematic relationship between the two.

We want to ensure that participants see a set of trials in which the orange picture is on the left, and a set of trials in which the blue picture is on the left, and that this is properly counterbalanced. What we’ll do is set up a timeline, to make sure that that is the case.

3.1.5 A counterbalanced timeline

Remember timelines from last time? You can add a timeline to a trial plugin so that you make many instances of that trial, with the parameters passed through the timeline.

In this case, we want to have some trials with orange pictures on the left, and some with blue pictures on the left. We’ll create a variable as below, called button_choices. button_choices is an array ([]) that contains two sets of key:value pairs ({}). In the first set, we have orange choices on the left and blue on the right, and and we have orange pictures on the left and blue pictures on the right.

Add this to your experiment (make sure it is placed above hello_trial) and fill in the relevant arrays for the lower set of key: value pairs, such that the positions of the orange and blue trials are switched.

    var button_choices =  [
          {
          choices: ['orange','blue'],
          button_html: ['<img src="img/orange.png" height="250px" width="250px"/>','<img src="img/blue.png" height="250px" width="250px"/>']
          },
          {
          choices: [...] ,
          button_html: [...]
          }
    ]

Now, delete the choices and button_html keys from your hello_trial var, and add a timeline key: value pair whose value is button_choices. Knit your HTML and see if you now have two trials, with one on the left and one on the right. If you don’t have this, check the debugger.

3.1.5.1 Add more trials

We can now easily add more trials, too.

Below the button_choices array, create a new var called button_choices_timeline, that has the following as its value: jsPsych.randomization.repeat(button_choices, 3);. Then, edit hello_trial so that it uses button_choices_timeline for its timeline. Knit the file, and you should now have 6 trials in a random order.

3.2 Saving the data

Like last time, we will just print the data to the screen at the end of the study. Modify jsPsych.init() so that it reads as follows.

    jsPsych.init({
        timeline: [hello_trial],
          on_finish: function() {
      jsPsych.data.displayData();
    }
    });

Knit your experiment and look at your data. It will probably look something like this:

Data on screen

Data on screen

This does not look very helpful, right? In fact, it is ever so slightly more helpful than it looks, because the value button_pressed indicates whether you chose the left or the right image (0 is left, i.e., first, and 1 is right). However, that knowledge is not going to get you very far, because you don’t know which image was on the left and which was on the right.

There are some complicated ways in which you could write custon jsPsych code to get that data. But actually the easiest way to do it is to modify the jsPsych plugin yourself. So, in RStudio, navigate to your plugins folder and open jspsych-button-response.js.

There’s lots of things going on in here, but you can ignore them for now. Instead, navigate down the page until you find the section in which the plugin saves the trial data. It looks like this:

      // gather the data to store for the trial
      var trial_data = {
        "rt": response.rt,
        "stimulus": trial.stimulus,
        "button_pressed": response.button
      };

You can see that this matches with some of the Key: Value pairs that you see in the datafile at the end of your experiment. In particular, trial_data is a set of key: value pairs in which the key “rt” contains the reaction time of your response, the key “stimulus” contains a description of the stimulus displayed on that trial (in your case there isn’t a stimulus, as the buttons don’t count as a stimulus to jsPsych), and then the key “button_pressed” indicates which of the two buttons you pressed in your response (that’s the key: value pair we looked at at the start of this section).

Edit var tria_data so that it has a new Key: value pair that records what stimuli you were showing. Something like

        "choices": trial.choices,

Remember that each of these button press trials contained a Key:Value pair called choices, which was assigned the value ['orange', 'blue'] or ['blue','orange']. Save the edited plugin and look at your data. It should appear like this

Data on screen

Data on screen

This is a little more helpful, because now you know which choice was on the left and which choice was on the right.

But it would be even better if we just recorded which choice the participant had made! And that’s easy enough to do. Remember that in the plugin, the variable response.button indicated whether button 0 or button 1 was pressed. So we can use that knowledge to select the correct choice. Edit trials.choices to use response.button to index which picture was chosen, as below, and then look at a new datafile once you’ve saved the plugin. If you don’t understand why this worked, let Hugh know.

"choices": trial.choices[response.button],

It should look as so:

Data on screen

Data on screen

3.3 Responding to a stimulus

Now we will augment our experiment with a stimulus that participants can respond to. On each trial they can press a button, hear a word, and tap a picture in response to that word.

3.3.1 Response to a single word

First, we augment our experiment so that each trial has a button, and it always plays the same word.

To our hello_trial var, we’ll add a button that participants can press. We do this by adding a stimulus key: value pair. The stimulus will be a piece of html that displays a button.

        stimulus: '<audio src="img/orange.wav" id="play_stim"></audio>'+
                     ' <center><button id="audio_button" onclick="PlaySound()" class="jspsych-btn" style="height:150px;width:150px">Play!</button></center>',

We also have to add another key: value pair to indicate that the stimulus key has html code as its value (otherwise jsPsych thinks the value should be a picture).

        is_html: true

In the stimulus code, the first line of html loads the wav file orange.wav. If you don’t have orange.wav in your img folder, you can download it from Learn. The second line of HTML creates a centered button that shows the word “Play!”. When you Click the button (onclick) it calls the function PlaySound().

Importantly, the function PlaySound isn’t in your website yet, so you need to add it above your other vars

  function PlaySound() {
    document.getElementById(play_stim);
    play_stim.play();
  }

Knit your website and see if this works (you may not be able to play audio in the RStudio preview window, but you should be able to in Internet Explorer).

3.3.2 Different words on each trial

Of course, in most experiments we want more than one condition, and we want more than one stimulus. So now, let’s change our timeline so that participants hear one of two instructions on each trial, either they hear blue or they hear orange. We want to counterbalance everything so that on half of the “blue” trials the blue picture is on the left and on half the blue trials the blue picture is on the right, and the same for the orange trials.

To do that, we’ll need to delete the stimulus: key value pair from hello_trial (keep is_html, however), and add a stimulus: key value pair to our variable button_choices. On half the trials, the key should point to blue.wav, and on half the trials it should point to orange.wav (which you can download from Learn).

Remember that right now, we have only two different trials in the button_choices variable: One trial in which Orange is on the left, and one trial in which Orange is on the right. So you’ll need to expand that var now, such that there are four trials in total, i.e., where Orange is on the left and the word heard is orange, where Orange is on the left and the word heard is blue, etc etc. I’ll let you do this on your own; shout if you have problems, but as a hint, I’ll show you what the first trial should look like.

          {
          choices: [
              'orange',
              'blue'
              ],
          button_html: [
              '<img src="img/orange.png" height="250px" width="250px"/>',
              '<img src="img/blue.png" height="250px" width="250px"/>'
              ],
          stimulus: 
              '<audio src="img/blue.wav" id="play_stim"></audio>'+
              ' <center><button id="audio_button" onclick="PlaySound()" class="jspsych-btn" style="height:150px;width:150px">Play!</button></center>',
          }

Once you’ve done this your data file should look a little bit like this:

Data on screen

Data on screen

For this data file, you can determine what the stimulus was by looking at the stimulus key: value pair. But it would be easier if you stimulus wasn’t surrounded by confusing HTML. Let’s do something about that.

3.3.3 Saving the name of your stimulus

In jsPsych, you can save arbitrary additional information about your stimuli to your datafile. You do this by adding a key called data: to your timeline.

For each trial on the timeline, add data to say what the spoken word was. Each trial should look a bit like the below, where your condition specifies which sound was spoken.

          {
          choices: [
              'orange',
              'blue'
              ],
          button_html: [
              '<img src="img/orange.png" height="250px" width="250px"/>',
              '<img src="img/blue.png" height="250px" width="250px"/>'
              ],
          stimulus: 
              '<audio src="img/blue.wav" id="play_stim"></audio>'+
              ' <center><button id="audio_button" onclick="PlaySound()" class="jspsych-btn" style="height:150px;width:150px">Play!</button></center>',
          data: { 
              condition: 'blue'
                },
          }

Knit your file and see if it works? Go thru your experiment and answer every trial either incorrectly or correctly. You should see a perfect correspendence between the Choices key and the stimulus key.

4 Congrats & Advanced stuff

Congrats! By now, you should have created a working iPad experiment. Next week, we’ll show you how to save your data, and how to load it onto the internet!