jsPsych
jsPsych copied to clipboard
Allow editing trials' parameters during simulation mode
In customized experiments with lots of behaviour modified on_start
and on_load
, I find myself further extending the function to include cases of what happens during simulation mode, e.g. speed up an animation in simulation mode or reduce the trial duration.
It would be nice if a modifiable copy of the trials is available in simulation_options
that I can use to modify the trial's parameters before the trial runs, similar to the on_start
behaviour.
Hey @nikbpetrov I'm finally getting around to triaging some of these issues.
What do you imagine the syntax would look like for this?
Same as for on_start makes sense to me.
To give one (very simplified) example from a recent experiment. Instead of this (focus on the trial_duration
parameter):
let leapfrog_trial = {
type: jsPsychHtmlKeyboardResponse,
stimulus: `<div style="font-size:3em; color: choose;">CHOOSE</div>
<div style="display: flex; justify-content: space-around; font-size: 2em; margin-top: 2em;">
<div>OPTION A</div>
<div>OPTION B</div>
</div>`,
choices: ['arrowleft', 'arrowright'],
trial_duration: SIMULATE ? SIMULATE_TRIAL_DURATION*1.2 : LEAPFROG_TRIAL_TIME_LIMIT,
simulation_options: {
data: function () {
if (jsPsych.randomization.sampleBernoulli(0.95)) {
return {rt: SIMULATE_TRIAL_DURATION}
} else {
return {rt: null, response: null}
}
}
}
}
I would prefer this:
let leapfrog_trial = {
type: jsPsychHtmlKeyboardResponse,
stimulus: `<div style="font-size:3em; color: choose;">CHOOSE</div>
<div style="display: flex; justify-content: space-around; font-size: 2em; margin-top: 2em;">
<div>OPTION A</div>
<div>OPTION B</div>
</div>`,
choices: ['arrowleft', 'arrowright'],
trial_duration: LEAPFROG_TRIAL_TIME_LIMIT,
simulation_options: {
data: function () {
if (jsPsych.randomization.sampleBernoulli(0.95)) {
return {rt: SIMULATE_TRIAL_DURATION}
} else {
return {rt: null, response: null}
}
},
trial: function(trial) {
trial.trial_duration = SIMULATE_TRIAL_DURATION*1.2
}
}
}
If necessary, I can look for more examples where this sort of thing can get incredibly useful from my previous experiments, but I think you get the point. For me, the biggest thing is that it's much cleaner as it constrains all simulation-related stuff within the simulation_options.
Ideally there would be a way to execute custom functions within simulation_options
similar to on_load
behaviour. Specifically, I would want to solve cases like the one below, where I have a custom trial, say an HTML form, and I get to control how behaviour is simulated without modifying my plugin file (though not sure the latter makes perfect sense, but it definitely feels easier for quick experiments):
[note how much stuff I have to modify in on_load
]
let admc_sn2_trial = {
type: jsPsychSurveyHtmlForm,
preamble: `<p><b><u>Instructions:</u><br>The following problems ask <i>out of 100 people your age</i>, how many would say that it is sometimes OK to do different things. For Each question, please select a number between 0 (meaning <i>no one</i> thinks that it is sometimes OK) and 100 (meaning <i>everyone</i> thinks that it is sometimes OK).</b></p>
<p style="margin-top: 3em;"><b>Out of 100 people your age, how many would say it is sometimes OK ...</b></p>`,
html: function() {
html = ''
SN2_ITEMS.forEach(e => {
html +=
`<div class="cal-statement">${e.question}</div>
<div class="slider-labels-container">
<input name="${e.id}" id="${e.id}_slider" type="range" min="0" max="100" step="1" value="0" class="jspsych-slider" style="width: 100%">
<div class="labels-container2">
<div style="left: calc(0% - (10%/2) - -7.5px);"><span>0<br>No one</span></div>
<div style="left: calc(10% - (10%/2) - -6px);"><span>10</span></div>
<div style="left: calc(20% - (10%/2) - -4.5px);"><span>20</span></div>
<div style="left: calc(30% - (10%/2) - -3px);"><span>30</span></div>
<div style="left: calc(40% - (10%/2) - -1.5px);"><span>40</span></div>
<div style="left: calc(50% - (10%/2) - 0px);"><span>50</span></div>
<div style="left: calc(60% - (10%/2) - 1.5px);"><span>60</span></div>
<div style="left: calc(70% - (10%/2) - 3px);"><span>70</span></div>
<div style="left: calc(80% - (10%/2) - 4.5px);"><span>80</span></div>
<div style="left: calc(90% - (10%/2) - 6px);"><span>90</span></div>
<div style="left: calc(100% - (10%/2) - 7.5px);"><span>100<br>Everyone</span></div>
</div>
</div>`
})
html += `<p id="slider_text" style="text-align: center"><i>Move all sliders to continue.</i></p>`
return html
},
on_load: function() {
let next_button = document.querySelector("#jspsych-survey-html-form-next")
if (!(ignore_validation === true)) {
next_button.disabled = true
let sliders_moved = {}
document.querySelectorAll(`input[type="range"]`).forEach(e=>{
sliders_moved[e.id] = false
// these 3 event listeners might be replaced by a single 'input' one
// but in this case we are just preserving the jsPsych style as per plugin-html-slider-response.js
e.addEventListener("mousedown", () => handle_slider_change(e.id, sliders_moved, next_button))
e.addEventListener("touchstart", () => handle_slider_change(e.id, sliders_moved, next_button))
e.addEventListener("change", () => handle_slider_change(e.id, sliders_moved, next_button))
})
}
if (SIMULATE) {
next_button.disabled = false;
document.querySelectorAll(`input[type="range"]`).forEach(e=>e.value=jsPsych.randomization.randomInt(0, 100))
}
}
};
Thanks, this is great. It makes total sense to me and shouldn't be too hard to add.