Program your experiment

How to program an experiment with jsPsych

Prerequisites

This page describes how to make changes to the lab's experiment template. If you haven't already, make sure you start by reading the create experiments protocol.

The experiments repo

When you clone the experiments repo to create your branch, you'll get a folder that looks like this.

Experiments repo

Here's what's in there:

  • archive: a folder for completed experiments

  • assets: a folder for css, js, images, and consents we all need

  • template: the experiment template (you'll make a copy of this to work from!)

  • .gitignore: tells git to ignore some files we don't want to track

  • README.md: the README file for the repo

  • childlanglab.js: javascript functions to send JSON data to php

  • write_participants.php: writes to our participants table

  • write_run.php: writes to our runs table

You'll copy the template folder and make modifications there. Changes made anywhere else will cause your pull request to be rejected

Start from the template

The template experiment you copied contains two files:

template experiment in experiments repo

The run-exp.html file started out like this:

<!DOCTYPE html>
<html>
<!-- libraries and stylesheets go in the header -->
<head>
<title>ChildLangLab Experiment X</title>
</head>
<!-- the body this is where the experiment gets displayed -->
<body></body>
<!-- the javascript that runs the experiment -->
<script></script>
</html>

Required head material

In the <head>, we added the basic libraries and stylesheets you'll need to build an experiment in the lab. You should change the X in the <title> to your experiment's exp_id.

run-exp-v1.html
<!DOCTYPE html>
<html>
<head>
<title>ChildLangLab Experiment X</title>
<!-- libraries required for jsPsych plugins -->
<script src="../assets/js/jspsych-6.0.5/jspsych.js"></script>
<script src="../assets/js/jspsych-6.0.5/plugins/jspsych-fullscreen.js"></script>
<script src="../assets/js/jspsych-6.0.5/plugins/jspsych-instructions.js"></script>
<!-- library required for writing to our database -->
<script src="../childlanglab.js"></script>
<!-- libraries required for YAML parsing -->
<script src="../assets/js/yaml.js" type="text/javascript"></script>
<!-- stylesheets for making everything pretty -->
<link href="../assets/js/jspsych-6.0.5/css/jspsych.css" rel="stylesheet" type="text/css"></link>
<link href="../assets/css/childlanglab.css" rel="stylesheet" type="text/css"></link>
</head>
<!-- the body this is where the experiment gets displayed -->
<body></body>
<!-- the javascript that runs the experiment -->
<script></script>
</html>

Required javascript

addProperties

Our database requires you to include the following fields in every experiment, so we've added these properties to the template. This function adds these fields to every trial of your experiment.

jsPsych.data.addProperties(
{
random_id: '',
condition: '',
exp_phase: '',
}
);

labreq_start

The javascript that runs the experiment gets written in between <script></script> We've added the lab's required start screen for you. It makes the browser go fullscreen and runs ChildLangLabRuntime(), a function that write to our 'runs' table in our database.

<script>
// for writing runtime data and displaying in fullscreen mode
var labreq_start = {
type: 'fullscreen',
fullscreen_mode: true,
on_start: function(){
ChildLangLabRuntime();
}
};
</script>

You should //comment out the ChildLangLabRuntime(); when testing locally, as only the lab's server has permission to insert rows into these database tables.

labreq_end

We've also included the lab's required end screen, which shows our logo and says "thanks" to the participant. It also writes out the trial-by-trial to the experiment's table in our database.

// the thanks screen at the end of the experiment
var labreq_end = {
type: 'image-button-response',
stimulus: '../assets/images/childlanglab-logo.png',
choices: ['End Experiment'],
prompt: "<p>Thanks for participating!</p>",
on_start: function(){
// ChildLangLabTrialData writes your trial data to the lab's database
// comment this out when you test locally
ChildLangLabTrialData('write_trialdata.php', jsPsych.data.get().json());
}
};

You should //comment out the ChildLangLabTrialData(); when testing locally, as only the lab's server has permission to insert rows into these database tables.

jsPsych.init

jsPsych.init launches the experiment. Anything you want in the experiment has to be added to this timeline. You can see that we've included labreq_start and labreq_end. You'd include any additional blocks in between those.

/* *************ADD YOUR EXTRA CODE HERE ********************* */
/* *****************ADD YOUR BLOCKS TO THE EXPERIMENT ************* */
// make sure you add your blocks and trials to the experiments timeline below
// start the experiment
jsPsych.init({
timeline: [labreq_start, /* add here */ labreq_end],
on_finish: function(){
// jsPsych.data.displayData() shows your data on the final screen
// comment this out when you deploy
jsPsych.data.displayData();
}
})

jsPsych.data.displayData() is a helper function that shows all of the data you collected in your experiment on the final screen. You need this to check that you are saving the data you think you are.

Required php

The experiment template folder also contains write_trialdata.php, which writes your data to our database once your experiment is deployed on the server. Be super careful with this file or you data will fail later tests.

<?php
// this path points to our configuration file.
include('../database_config.php');
// the name of your experiment table in the data schema
// this should be the only value changed in this file
$table = 'experiment_data.exp1';
// get JSON and decode to PHP array
$data_array = json_decode(file_get_contents('php://input'), true);
// connect to database
$dbconn = pg_connect( "host=$host port=$port dbname=$dbname user=$user password=$password sslmode=require" )
or die ("Could not connect to database\n");
// for each row in the data array, insert to table
// note that all values in array must have columns in table
// if a column exists in table and there is no value in array, NULL is inserted
foreach ($data_array as $row) {
$res = pg_insert($dbconn, $table, $row) or die ("Could not write row to table $table");
};
?>

Only edit one line of this file: change$table = 'experiment_data.exp1' to your experiment table in the database.

Add your experiment code

If you are running an experiment on prolific, you'll need to display our consent form and request consent via a checkbox. Add the following code to show the lab's consent form:

Conditions

Different study conditions are given as .yaml files.

{include call to load yaml and how it gets set}/

Instructions

Usually you want to add instructions; we use the jsPsych instructions plugin.

// instructions
var instructions = {
type: 'instructions',
pages: [
"First page of instructions",
"Second page of instructions",
"Third page of instructions"
],
show_clickable_nav: true
}

If you need to change instructions based on conditions, you could set the instructions in the conditions .yaml file:

instructions:
pages:
- "This is the first page"
- "This is the second page"
- "This is the third page"

and do this in run-exp.html instead:

// instructions
var instructions = {
type: 'instructions',
pages: PARAMS.instructions.pages,
show_clickable_nav: true
}

Exposure

Exposure phase.

Rating test

Rating test option.

2AFC test

2AFC test.

Questionnaire

Questionnaire demo

Design your data table

Storing your data in the lab's database is mandatory.

The template experiment is setup to automatically write to the lab's participants and runs tables, since the fields in these tables are identical across experiments. Because different experiments will want to capture different data, each experimenter sets up their experiment with its own unique data table to store trial-by-trial data.

Think about what data you'll need to collect in your study. For each variable, you'll need to define:

  • The column name (should match it's name in jsPsych data output)

  • The data type of the column (usually text, varchar, bool, int, or decimal)

  • Whether it can be NULL (usually yes, except for things in .addProperties)

  • And the primary key for your table (a unique, non-null id column)

Use QuickDBD

A great way to quickly design your data table is to use QuickDBD: https://app.quickdatabasediagrams.com. Here's an example of the data table I created for experiment 1 in QuickDBD.

I've declared the column name (e.g. condition), the type (e.g. int), whether it can be NULL and a primary key (PK, trial_id-random-id).

QuickDBD can help you visualize your table and we can import the code portion into our database to create it. To export the .sql file, select Export and choose PostgreSQL.

It is good practice to upload this .sql file with your pull request. There are other good practice things you may want to consider when creating tables for PostgreSQL (our database).

Test locally

Active lab experiments are stored in a shared folder ChildLangLab-Data in the lab’s Google Drive File Stream. This is available on all Lab computers. If you cannot access this on a computer, ask Katie for help.

To run an experiment:

  • Open terminal and navigate to the ChildLangLab-Data folder using the cd command and dragging the folder

  • Start a php server with the command: php -S localhost:8000

  • Navigate to the study URL, linked on conditions to run sheet

On the server

Experiments are hosted on our experiment server: http://experiments.childlanglab.com/

If you'll be offsite, make sure you bring the lab's wifi hotspot.