-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from pjkohler/main
Ebbinghaus Experiment
- Loading branch information
Showing
9 changed files
with
5,402 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Ebbinghaus experiment | ||
03-13-2021 Kohler Visual Neuroscience Laboratory, York University | ||
|
||
# Background | ||
This is an implementation of an experiment to measure the Ebbinghaus effect. The Experiment uses jspsych version 6.3 and the jspsych-psychophysics plugin which is currently available [here](https://github.com/kurokida/jspsych-psychophysics/releases). | ||
|
||
# Task Description | ||
Participants see circular discs presented on either side of the fixation point and need to use the arrow keys to identify which disc is bigger. Each disc is surrounded by a set of smaller discs. Reference disc always have the same size and are always surrounded by discs of the same size. Tests discs vary in size and are surrounded by discs that can either have the same size as the surrounding discs used for the reference discs (control condition), or be a different size, typically smaller (test condition). Every combination of test discs location (left vs right), test vs reference condition, and test disc size is presented in random order across the trials. The number of repetitions of each combination can be modified by the user - note that because test disc location is factored into the design but typically not analyzed, the effective number of trials per test disc size will be twice the number of repetitions. Trials are broken into blocks so that participants can take occasional breaks. When the experiment is complete the results are automatically saved as CSV files. Note, no participant ID is included in the name and files will be overwritten upon a subsequent run of the code. | ||
|
||
# Duration | ||
This depends on the timing parameters chosen and the response time of the participants. By default there are 10 repetitions leading to a total of 280 trials. | ||
|
||
# Results File Information | ||
The results fil contains trial level information about response time, key press, time elapsed and whether the test disc was chosen to be larger ("test_bigger"). Pre-trial prompts and other non-trial evens are included in the data. To get responses only for test trials the results need to be filtered to only include columns where "test_bigger" is not NaN. | ||
|
||
# Experimental Set-up | ||
There is a setup file which allows the researcher to modify the experiment parameters, number of repetitions and the prompt shown to the user before each trial. | ||
|
||
# Stimuli | ||
The stimuli are grayscale filled discs generated using the jspsych-psychophysics plugin. | ||
|
||
# Modifiable Parameters | ||
* Number of repetitions | ||
* Colors of the inner and outer discs | ||
* Fixation point color | ||
* Test and reference inner disc sizes | ||
* Test and reference outer disc sizes | ||
* Distance between inner and outer discs | ||
* Distance of each disc group from fixation | ||
* Welcome message shown in the beginning of the experiment. | ||
* Prompt message shown before each trial | ||
* Message telling participants to press any key to continue. | ||
* Message telling participants how many trials they have completed. | ||
* Message shown during breaks between blocks. | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
body {background-color: rgb(128, 128, 128); color: rgb(255, 255, 255)} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="jspsych-6.3/jspsych.js"></script> | ||
<script src="jspsych-6.3/jspsych-psychophysics/jspsych-psychophysics.js"></script> | ||
<script src="jspsych-6.3/plugins/jspsych-html-keyboard-response.js"></script> | ||
<script src="jspsych-6.3/plugins/jspsych-preload.js"></script> | ||
<link rel="stylesheet" href="jspsych-6.3/css/jspsych.css"></link> | ||
<link href="ebbinghaus.css" rel="stylesheet"> | ||
<script src="ebbinghaus_setup_EN.js"></script> | ||
<meta charset="utf-8"/> | ||
</head> | ||
<body></body> | ||
<script> | ||
const cross = { | ||
obj_type: 'cross', | ||
startX: 0, // location of the cross's center in the canvas | ||
startY: 0, | ||
origin_center: true, // Change the coordinate origin to the center of the window | ||
line_length: 40, | ||
line_width: 4, | ||
line_color: fix_color | ||
} | ||
|
||
const disc = { | ||
obj_type: 'circle', | ||
startX: 0, // location of the disc's center in the canvas | ||
startY: 0, | ||
radius: ref_inner, | ||
fill_color: color_inner, | ||
origin_center: true // Change the coordinate origin to the center of the window | ||
} | ||
|
||
const factors = { | ||
test_side: [-1, 1], // randomize test position (left vs right) | ||
test_outer: test_outer, // randomize test outer radius (same as ref or smaller) | ||
test_inner: test_inner // randomize test inner radius | ||
} | ||
|
||
const full_design = jsPsych.randomization.factorial(factors, repeat_trials) | ||
|
||
const block_len = Math.floor(full_design.length/block_number) | ||
|
||
var prompt = { | ||
obj_type: 'text', | ||
startX: 0, | ||
startY: 300, | ||
content: prompt_msg, | ||
font: "20px 'Arial'", | ||
text_color: 'white', | ||
origin_center: true, | ||
} | ||
|
||
const welcome = { | ||
type: "html-keyboard-response", | ||
stimulus: welcome_msg.replace("$BLOCK_LEN", block_len).replace("$BLOCK_NUM", block_number) | ||
} | ||
|
||
const first_msg = any_key_msg | ||
let first_prompt = Object.assign({}, prompt) | ||
first_prompt = Object.assign(first_prompt, {content: prompt_msg + first_msg}) | ||
const first_prompt_trial = { type: 'psychophysics', stimuli: [cross, first_prompt] } | ||
|
||
var procedure = { | ||
timeline: [ | ||
{ | ||
type: 'psychophysics', | ||
stimuli: function(){ | ||
const test_x = dist_groups * jsPsych.timelineVariable('test_side', true) | ||
const test_radius = jsPsych.timelineVariable('test_inner', true) | ||
// standard inner disc | ||
let ref_inner_disc = Object.assign({}, disc) | ||
ref_inner_disc = Object.assign(ref_inner_disc, {startX: (test_x*-1)}) | ||
// test inner disc | ||
let test_inner_disc = Object.assign({}, disc) | ||
test_inner_disc = Object.assign(test_inner_disc, {startX: test_x, radius: test_radius}) | ||
// add to array | ||
let obj_array = [cross, ref_inner_disc, test_inner_disc] | ||
for (let i = 0; i < 360; i=i+60) { | ||
let outer_x = dist_discs * Math.cos(i * Math.PI / 180); | ||
let outer_y = dist_discs * Math.sin(i * Math.PI / 180); | ||
|
||
let ref_outer_disc = Object.assign({}, disc) | ||
ref_outer_disc = Object.assign(ref_outer_disc, | ||
{ | ||
startX: outer_x + (test_x*-1), | ||
startY: outer_y, | ||
fill_color: color_outer, | ||
radius: ref_outer // always use the first element | ||
} | ||
) | ||
obj_array.push(ref_outer_disc) | ||
let test_outer_disc = Object.assign({}, disc) | ||
test_outer_disc = Object.assign(test_outer_disc, | ||
{ | ||
startX: outer_x + test_x, | ||
startY: outer_y, | ||
fill_color: color_outer, | ||
radius: jsPsych.timelineVariable('test_outer', true) | ||
} | ||
) | ||
obj_array.push(test_outer_disc) | ||
} | ||
let cur_prompt = Object.assign({}, prompt) | ||
cur_prompt = Object.assign(cur_prompt, {content: prompt_msg}) | ||
obj_array.push(cur_prompt) | ||
return(obj_array) | ||
}, | ||
choices: ["ArrowLeft", "ArrowRight"], | ||
data: function(){ | ||
let t = jsPsych.data.get().filter({ref_inner_radius: ref_inner}).count() + 1 | ||
let b = Math.floor(t/block_len)+1 | ||
const data_obj = { | ||
trial: t, | ||
block: b, | ||
test_pos: jsPsych.timelineVariable('test_side', true), | ||
test_inner_radius: jsPsych.timelineVariable('test_inner', true), | ||
test_outer_radius: jsPsych.timelineVariable('test_outer', true), | ||
ref_inner_radius: ref_inner, | ||
ref_outer_radius: ref_outer // store reference values just in case | ||
} | ||
return data_obj | ||
}, | ||
// record responses relative to test position (left vs right) | ||
on_finish: function(data){ | ||
if ( data.test_pos < 0 ) { | ||
// if test on the left | ||
if ( data.key_press == "arrowleft" ) { | ||
data.test_bigger = true | ||
} else if ( data.key_press == "arrowright" ) { | ||
data.test_bigger = false | ||
} else { | ||
data.test_bigger = null | ||
} | ||
} else { | ||
// if test on the right | ||
if ( data.key_press == "arrowleft" ) { | ||
data.test_bigger = false | ||
} else if ( data.key_press == "arrowright" ) { | ||
data.test_bigger = true | ||
} else { | ||
data.test_bigger = null | ||
} | ||
} | ||
}, | ||
}, | ||
{ | ||
type: 'psychophysics', | ||
stimuli: function(){ | ||
let t = jsPsych.data.get().last(1).values()[0]["trial"] // trials so far | ||
let cur_prompt = Object.assign({}, prompt) | ||
cur_prompt = Object.assign(cur_prompt, {content: prompt_msg + trial_msg.replace("$TRIAL", t).replace("$EXP_LEN", full_design.length)}) | ||
return [cur_prompt, cross] | ||
}, | ||
choices: jsPsych.NO_KEYS, | ||
trial_duration: 1000, | ||
response_ends_trial: false | ||
}, | ||
// break statement | ||
{ | ||
timeline: [ | ||
{ | ||
type: "html-keyboard-response", | ||
stimulus: function() { | ||
let t = jsPsych.data.get().last(2).values()[0]["trial"] // trials so far | ||
let b = jsPsych.data.get().last(2).values()[0]["block"] // block | ||
const html_out = '<div style="color: white; text-align: center; vertical-align: top; display: inline-block; width: 800px; margin: auto">'+ | ||
break_msg.replace("$PERCENT", (t/full_design.length * 100).toFixed(0)).replace("$BLOCK",b).replace("$BLOCK_NUM", block_number) | ||
return html_out | ||
}, | ||
post_trial_gap: 1000 | ||
} | ||
], | ||
conditional_function: function(){ | ||
let t = jsPsych.data.get().last(2).values()[0]["trial"] // trials so far | ||
if ( ( ( t % block_len ) == 0 ) && ( t < full_design.length ) ) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
} | ||
], | ||
timeline_variables: full_design, | ||
randomize_order: true | ||
} | ||
|
||
jsPsych.init({ | ||
timeline: [welcome, first_prompt_trial, procedure], | ||
on_finish: function() { | ||
jsPsych.data.get().localSave('csv','ebbinghaus_data.csv'); | ||
} | ||
}); | ||
</script> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
const color_inner = 'rgb(191, 191, 191)'; // color of inner discs | ||
const color_outer = 'rgb(64, 64, 64)'; // color of outer discs | ||
const fix_color = 'rgb(255, 255, 255)'; | ||
const ref_inner = 25; // inner disc radius (reference) | ||
const test_inner = [20, 23, 24, 25, 26, 27, 30] // (test) | ||
const ref_outer = 35 // outer disc radius (reference) | ||
const test_outer = [35, 15] // (test) | ||
const dist_discs = 80; // distance between inner and outer discs | ||
const dist_groups = 200; // distance from fixation for each disc group | ||
const repeat_trials = 10; // how many times to repeat each trial type | ||
// total_trials = repeat_trials * 2 * 2 * test_inner.lenght() | ||
const block_number = 10; // how many blocks to include in the experiment | ||
|
||
const prompt_msg = "Keep staring at the cross in the center of the screen.\n\n"+ | ||
"Use the left and right arrow keys to indicate "+ | ||
"which of the center circles is biggest.\n\n" | ||
// message to display before each trial. | ||
// note: '\n\n' is needed at the end of each line | ||
// because prompt is displayed using the psychophysics plugin | ||
|
||
// note that words that begin with $ will be replaced with variable values when the code is run | ||
const welcome_msg = "Welcome to the Size Judgment Experiment. <br>" + | ||
"There will be $BLOCK_NUM blocks in this experiment. <br>" + | ||
"There will be $BLOCK_LEN trials in each block. <br>"+ | ||
"You will be given a chance to take a break between blocks. <br>"+ | ||
"Press any key to start the experiment.</p>" | ||
|
||
const any_key_msg = "Press any key to continue." | ||
|
||
const trial_msg = "You have completed $TRIAL of $EXP_LEN trials. Get ready for the next!" | ||
|
||
const break_msg = "<p>You have completed $PERCENT% of the trials. You are on block $BLOCK of $BLOCK_NUM. <br>Good job! Take a break if you need to.</p>"+ | ||
"<p>Press any key to continue the experiment.</p></div>" |
Oops, something went wrong.