Allocating participant and condition numbers¶
How can participant IDs be allocated to participants in an online experiment?
Back to GET - externally allocated IDs¶
Remember that last week we talked about the HTTP GET method, which allows us to pass parameters along to web pages. The example given was:
http://example.com/page?colour=red&size=3
What if it looked like this:
http://example.com/experiment.html?participant=12
We can use this method to pass a participant number to jsPsych, and it has a very convenient way of receiving it.
Make another copy of the latest version of your experiment and call it id_in_url
.
Now right at the top of experiment.js
, add this code:
var participant_id = jsPsych.data.getURLVariable('participant');
jsPsych.data.addProperties({participant: participant_id});
In your web browser, load up the new copy of the experiment. In your browser, at the end of the URL, add a participant number as above. So it will look something like:
http://jspsychlearning.ppls.ed.ac.uk/~UUN/allocator/experiment.html?participant=123
Remember that UUN is your University username, for a student this will look something like s1234567.
Complete the experiment. When you look at the data, you should see a new column called “participant”, equal to the number that you entered.
Where should participant numbers come from?¶
There are two possibilities here. One is that the participant will be sent from some external service (e.g. Amazon MTurk or Crowdflower, or a Qualtrics survey) and there will already be an ID in the URL. In this case, you need to record the ID as above.
We can also create our own small program on the server which allocates participant IDs.
Make another copy of your experiment (without the id_in_url
changes). Rename this directory to allocator
. We’ll modify this to use the PHP ID allocator.
Open a new file called participant_id_allocator.php
and copy this code into it:
<?php
$username = explode("/", dirname(__FILE__))[2];
$server_data = '/home/'.$username.'/server_data';
$partid_file = $server_data.'/partid_example.txt';
$partid = file_get_contents($partid_file);
if ($partid == FALSE) {
$partid = 0;
} else {
$partid = (int)$partid;
}
$partid += 1;
if (substr(realpath(dirname($partid_file)), 0, strlen($server_data))!=$server_data) {
error_log("attempt to write to bad path: ".$partid_file);
} else {
file_put_contents($partid_file, (string)$partid);
}
printf('%d', $partid); // send ID!
?>
This code will:
Try to read a file in
server_data
calledparticipant_id.txt
If the file doesn’t exist, set the variable
$id
to zeroIf the file does exist, open it and interpret the contents as a whole number
Add one to
$id
Write
$id
toparticipant_id.txt
Send
$id
back – so this will be sent back to our experiment code where we can record the ID.
The file participant_id.txt
should always contain the last ID that was used. Every
time this is accessed (and the program runs), it will increase the ID by 1, and forward
to the experiment with the new ID.
You should be able to go to the URL for this code on the server, something like:
http://jspsychlearning.ppls.ed.ac.uk/~UUN/allocator/participant_id_allocator.php
This will send back a participant ID and you’ll see it on the page. Every time you load or reload the page, the ID should increase by 1.
Finally, since participant_id.txt
always contains the next participant number,
you can edit it to change the next participant ID, or delete it to start again at 1.
Adding this to an experiment¶
Add the call-function
plugin to your HTML file (see https://www.jspsych.org/v8/plugins/call-function/).
At the top of the experiment add:
var participant_id;
Then add a new node to your experiment which will call participant_id_allocator.php
and get a new participant ID.
var get_participant_id = {
type: jsPsychCallFunction,
async: true,
func: function (done) {
fetch("participant_id_allocator.php")
.then(function (response) {return response.text();})
.then(function (response_text) {return parseInt(response_text);})
.then(function (result) {
participant_id = result;
// condition number is the remainder of participant_id divided by 3
condition_number = participant_id % 3;
// if remainder is 0 change to 3 (so the conditions will be 1,2,3)
if (condition_number == 0) {
condition_number = 3;
}
// record this in our results
jsPsych.data.addProperties({condition: condition_number});
})
.then(done())
}
}
Better data filenames¶
At the moment the data are still being written to a file called “test.csv”. Let’s fix that!
In the part of the code where we save the data, we can add the participant number to the filename.
Look for code like this:
on_finish: function() {
var experiment_data = jsPsych.data.get();
save_data("test.csv", experiment_data.csv());
// show results as well - take this out when doing real testing!
jsPsych.data.displayData("csv");
}
and change it to this:
on_finish: function(){
var experiment_data = jsPsych.data.get();
save_data(participant_id+"_data.csv", experiment_data.csv());
// show results as well - take this out when doing real testing!
jsPsych.data.displayData("csv");
}
This adds the participant ID to the filename, so that they will be called 1_data.csv
, 2_data.csv
,
and so on.
We could also add the date to the filename. It’s better to do this on the server, as the
participant’s computer may have the date wrong. In save_data.php
, change the line:
$path = $server_data."/".$obj["filename"];
to this:
$path = $server_data."/".date("Y-m-d")."_".$obj["filename"];
This adds the date (according to the server clock) to the start of the filename, plus an underscore
character _
to separate this date from the rest of the name.
Run your experiment again (starting from the ID allocator) and you should see a new file in
server_data
with a filename something like this:
2018-02-11_3_data.csv
Condition number¶
When running an experiment, it’s common to want to counterbalance participants between several conditions. The usual way to do this is allocate them in order. For example, for three conditions:
Participant ID |
Condition |
---|---|
1 |
1 |
2 |
2 |
3 |
3 |
4 |
1 |
5 |
2 |
6 |
3 |
7 |
1 |
etc. |
etc. |
We can easily allocate conditions using JavaScript modulus, %
.
The code:
var x = y % z;
gives the remainder when y
is divided by z
.
In our example:
Participant ID |
Remainder (ID % 3) |
---|---|
1 |
1 |
2 |
2 |
3 |
0 |
4 |
1 |
5 |
2 |
6 |
0 |
7 |
1 |
etc. |
etc. |
Let’s add this to the experiment. At the top of experiment.js
, add this:
var condition_number;
Then in the call-function
node where we get the participant number, replace this line:
.then(function (result) {participant_id = result;})
with this:
.then(function (result) {
participant_id = result;
// condition number is the remainder of participant_id divided by 3
condition_number = participant_id % 3;
// if remainder is 0 change to 3 (so the conditions will be 1,2,3)
if (condition_number == 0) {
condition_number = 3;
}
})
Run your experiment and check that the condition number appears in the output.
Example¶
See this example of getting a participant number from the server, calculating a condition number, and changing the data filename.