Skip to content

Commit

Permalink
Merge pull request #14 from pjkohler/main
Browse files Browse the repository at this point in the history
Ebbinghaus Experiment
  • Loading branch information
pjkohler authored Sep 16, 2021
2 parents 9a9315a + 5d214d5 commit f051388
Show file tree
Hide file tree
Showing 9 changed files with 5,402 additions and 0 deletions.
38 changes: 38 additions & 0 deletions ebbinghaus/README.md
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.




1 change: 1 addition & 0 deletions ebbinghaus/ebbinghaus.css
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)}
196 changes: 196 additions & 0 deletions ebbinghaus/ebbinghaus.html
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>
33 changes: 33 additions & 0 deletions ebbinghaus/ebbinghaus_setup_EN.js
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>"
Loading

0 comments on commit f051388

Please sign in to comment.