Making prompt in between a trial sequence, loading different presentation duration in a loop,?

886 views
Skip to first unread message

sebastija...@gmail.com

unread,
Feb 16, 2017, 4:48:38 AM2/16/17
to jsPsych
Hi!

I've only recently started using JsPsych and am really liking it so far. Because I have no prior experience using Javascript, as I've mostly used Python or Matlab as a programming language, I have a few questions which are intertwined that I cannot easily solve in this language because I am slightly lacking the conceptual capacity at the moment, but all are perhaps trivial for the veteran jsPsych coder. Maybe other users will also find the answers to these questions useful which is why I’ve tried making them clear as possible :)

Down below is the code for my stimuli presentation:
I have a var trial_seq_low and trial_seq_high.

The task sequence is as follows - at the beginning of every trial a stimuli (white box) is shown for 250ms which then disappears. After this, a timing_post_trial is defined which changes from trial to trial. The participants are asked to respond as fast as possible after the box gets presented with the response being collected until the end of the timing_post_trial.

So:
|stimulus onset (250ms)| (we gather their RT from onset of presentation)
|post stimulus interval (1000 to 2500ms)| (and should gather it until the end of the post stimulus interval)

|repeat 5x|

This is repeated five times in one sequence. The problem is, if I set the timing_response (allow_resp1 to 5 in the code below) to the desired amount of time, the stimulus stays on for longer than the 250ms.

1. How can I change this such that the stimuli would indeed be presented for 250ms and I would still collect the RT from onset (begin of 250ms) to end of the post_stimulus interval which would be considered as the RT for the first trial?

var trial_seq_low = {
type: 'single-stim',
is_html: true,
choices: ['B'],
timing_stim: 250,
response_ends_trial: false,
data: {trial: 'low_points'},
stimulus: '<img src="img/block.png">',
timeline: [
{timing_post_trial: delay1, timing_response: allow_resp1, prompt: function() {points_low = 0; return "<p>Punkte:"+points_low+" </p>"}},
{timing_post_trial: delay2, timing_response: allow_resp2, prompt: function() {return "<p>Punkte:"+points_low+" </p>"}},
{timing_post_trial: delay3, timing_response: allow_resp3, prompt: function() {return "<p>Punkte:"+points_low+" </p>"}},
{timing_post_trial: delay4, timing_response: allow_resp4, prompt: function() {return "<p>Punkte:"+points_low+" </p>"}},
{timing_post_trial: delay5, timing_response: allow_resp5, prompt: function() {return "<p>Punkte:"+points_low+" </p>"}}
],
on_finish: function(data) {
if (data.rt >= 1 && data.rt <= 200){
points_low += 50;
var res = 1
}
else if (data.rt >= 200 && data.rt < 400) {
points_low += 20;
res = 1
}
else if (data.rt >= 400 && data.rt < 500){
points_low += 5;
res = 1
}
else if (data.rt >= 500 && data.rt < 600){
points_low += 2;
res = 1
}
else if (data.rt >= 600 && data.rt < 700){
points_low += 1;
res = 1
} else {res = 0}
return points_low}
};

In addition to this, for each RT, participants get points based on their RT (RTs and points are not as they will be in the end) which gets shown after they have made their response with a prompt (this works here). The prompt, however, dissappears after each trial only to reappear again.
2. How can I make the prompt stay in between the trials with only the number of points changing?

3. In addition, I would like to give them visual feedback together with the prompt (OK arrow or NO arrow). How can this most easily be done? So a constant prompt once the sequence starts with just the number of points changing together with an OK or NO arrow (depending on their RT accuracy) appearing following their response?

As mentioned above, I have a trial_seq_low and _high version.

In one round, they are exposed to the low and high condition, with an additional screen appearing at the end of each round where they would see their cumulative score.

final_points = points_low + points_high;

var total_points = {
type: 'single-stim',
stimulus: final_points,
timing_stim: 2000,
response_ends_trial: false,
timing_post_trial: 0,
timing_response: 1
};

I define the points_low and points_high as variables outside the stim objects before either are started and define the final_points after them. This doesn’t work, however, as it stays 0 all the time.

Should the stimulus in total_points be a function with points_low and points_high as inputs? I’m slightly confused by the scope of variable definitions and sequence flow in Javascript that’s why I’m having this trivial problem.
3. Or how can I present the total number of points in a new trial gathered within two previous trial sequences?

And finally - I have an array of arrays (see below) which is used to determine the onset times and post_stimulus times. I shuffle the array through indexing for each participant in the beginning.
How can I change the post_stimulus_delay and timing_response based on the row - so that what is considered delay1 through 5 and allow_resp1 through 5 would depend on the row in which the task currently is? In Matlab or Python, I would simply create a for loop of 15 trials (I have 15 arrays) and assign the allow_resp and delay variables with indexing and then run the trial_seq_low and _high sequences 15 times with different values, but I’m not sure where to put the for loop or how this would work in this case as in the timeline just the object gets added? The most brute force way I can imagine is to just initialize that amount of variables and push all of them to the timeline (which is also what I'll have to resort to if I don't find a more elegant solution).

var sequences = [[1000, 3500, 4750, 7000, 8500],
[2750, 3750, 5000, 6500, 8250],
[1000, 2250, 6000, 7000, 8500],
[1250, 2500, 5000, 6500, 7750],
[750, 2000, 4000, 5500, 6750],
[2000, 3000, 4500, 6250, 7750],
[750, 2250, 3250, 5000, 6750],
[1000, 3250, 4250, 5750, 8750],
[1250, 4500, 5750, 7500, 8750],
[1750, 2750, 5750, 6750, 8000],
[1500, 2750, 4500, 6000, 7500],
[2500, 4000, 5000, 6500, 8000],
[3250, 4250, 5750, 7750, 8750],
[750, 3000, 4000, 5750, 6750],
[1000, 2250, 5500, 7250, 8750]];

I'm sorry for the long post, I realize these questions are probably very trivial and can be resolved relatively quickly, but I cannot find suitable answers for them.

I look forward to your response and am very grateful for them!

Best

Josh de Leeuw

unread,
Feb 17, 2017, 11:08:07 PM2/17/17
to sebastija...@gmail.com, jsPsych
Answers below.... hope it helps! --Josh

On Thu, Feb 16, 2017 at 4:48 AM <sebastija...@gmail.com> wrote:
Hi!

I've only recently started using JsPsych and am really liking it so far. Because I have no prior experience using Javascript, as I've mostly used Python or Matlab as a programming language, I have a few questions which are intertwined that I cannot easily solve in this language because I am slightly lacking the conceptual capacity at the moment, but all are perhaps trivial for the veteran jsPsych coder. Maybe other users will also find the answers to these questions useful which is why I’ve tried making them clear as possible :)

Down below is the code for my stimuli presentation:
I have a var trial_seq_low and trial_seq_high.

The task sequence is as follows - at the beginning of every trial a stimuli (white box) is shown for 250ms which then disappears. After this, a timing_post_trial is defined which changes from trial to trial. The participants are asked to respond as fast as possible after the box gets presented with the response being collected until the end of the timing_post_trial.

So:
|stimulus onset (250ms)| (we gather their RT from onset of presentation)
|post stimulus interval (1000 to 2500ms)| (and should gather it until the end of the post stimulus interval)

|repeat 5x|

This is repeated five times in one sequence. The problem is, if I set the timing_response (allow_resp1 to 5 in the code below) to the desired amount of time, the stimulus stays on for longer than the 250ms.

1. How can I change this such that the stimuli would indeed be presented for 250ms and I would still collect the RT from onset (begin of 250ms) to end of the post_stimulus interval which would be considered as the RT for the first trial?

Setting timing_stim to 250, and timing_response to the maximum duration of the trial should do what you are trying to do. If this isn't working then there might be a bug that needs to be tracked down. The stimulus should disappear after timing_stim is reached, with the trial continuing until timing_response.
setting timing_post_trial to 0 will give make it seem like the prompt never leaves the screen.
 

3. In addition, I would like to give them visual feedback together with the prompt (OK arrow or NO arrow). How can this most easily be done? So a constant prompt once the sequence starts with just the number of points changing together with an OK or NO arrow (depending on their RT accuracy) appearing following their response?

Probably by putting in an additional trial using the single-stim plugin between each test trial. You would use a function as the stimulus parameter and get the data from the last trial to determine if it should be OK or NO.
 

As mentioned above, I have a trial_seq_low and _high version.

In one round, they are exposed to the low and high condition, with an additional screen appearing at the end of each round where they would see their cumulative score.

final_points = points_low + points_high;

var total_points = {
    type: 'single-stim',
    stimulus: final_points,
    timing_stim: 2000,
    response_ends_trial: false,
    timing_post_trial: 0,
    timing_response: 1
};

I define the points_low and points_high as variables outside the stim objects before either are started and define the final_points after them. This doesn’t work, however, as it stays 0 all the time.

Should the stimulus in total_points be a function with points_low and points_high as inputs? I’m slightly confused by the scope of variable definitions and sequence flow in Javascript that’s why I’m having this trivial problem.

You need the stimulus to be a function that returns final_points:

stimulus: function() { return final_points; }

This isn't really a JavaScript scope thing, it's more of a jsPsych scope thing. The key point to remember is that your whole script is going to execute before the experiment even starts, so any variables that are defined will take their value based on when the experiment is loaded. The way around this is to wrap them in a function, which jsPsych knows to wait to run until the trial runs.
 
3. Or how can I present the total number of points in a new trial gathered within two previous trial sequences?

If you are using version 5.x then you can call jsPsych.data.getData() inside the function and parse the data structure to determine the number of points and return that value. 

Version 6 will add a lot of helper functions for data aggregation, so you'll be able to do things like:

jsPsych.data.get().last(2).select('rt').mean();

If you want to try out those features you can grab the master branch of the code and look in the docs folder for the documentation in progress.
 

And finally - I have an array of arrays (see below) which is used to determine the onset times and post_stimulus times. I shuffle the array through indexing for each participant in the beginning.
How can I change the post_stimulus_delay and timing_response based on the row - so that what is considered delay1 through 5 and allow_resp1 through 5 would depend on the row in which the task currently is? In Matlab or Python, I would simply create a for loop of 15 trials (I have 15 arrays) and assign the allow_resp and delay variables with indexing and then run the trial_seq_low and _high sequences 15 times with different values, but I’m not sure where to put the for loop or how this would work in this case as in the timeline just the object gets added? The most brute force way I can imagine is to just initialize that amount of variables and push all of them to the timeline (which is also what I'll have to resort to if I don't find a more elegant solution).

var sequences = [[1000, 3500, 4750, 7000, 8500],
                 [2750, 3750, 5000, 6500, 8250],
                 [1000, 2250, 6000, 7000, 8500],
                 [1250, 2500, 5000, 6500, 7750],
                 [750, 2000, 4000, 5500, 6750],
                 [2000, 3000, 4500, 6250, 7750],
                 [750, 2250, 3250, 5000, 6750],
                 [1000, 3250, 4250, 5750, 8750],
                 [1250, 4500, 5750, 7500, 8750],
                 [1750, 2750, 5750, 6750, 8000],
                 [1500, 2750, 4500, 6000, 7500],
                 [2500, 4000, 5000, 6500, 8000],
                 [3250, 4250, 5750, 7750, 8750],
                 [750, 3000, 4000, 5750, 6750],
                 [1000, 2250, 5500, 7250, 8750]];


That's probably the best way to do it in version 5.x.

Version 6 adds a more sophisticated way of applying variables to timelines. You can see some documentation here: 

 
I'm sorry for the long post, I realize these questions are probably very trivial and can be resolved relatively quickly, but I cannot find suitable answers for them.

I look forward to your response and am very grateful for them!

Best

--
You received this message because you are subscribed to the Google Groups "jsPsych" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jspsych+u...@googlegroups.com.
To post to this group, send email to jsp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jspsych/ea611ca2-b6b7-4d55-bdfd-1efe46baa122%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

sebastija...@gmail.com

unread,
Feb 20, 2017, 9:33:46 AM2/20/17
to jsPsych, sebastija...@gmail.com
Thanks for the answer, I've made the majority of modifications in the desired direction. The change in 6.+ with the timeline variables is excellent!

There does seem to be a bug as far as timing_stim and timing_response goes.

I created a simple trial, where I defined the stim duration and how long I'd like to gather the response. The stim does indeed stay on until the end of timing_response, which is not what should happen I suppose.

new_trial = {
type: 'single-stim',
timing_stim: 500,
timing_response: 5000,
timing_post_trial: 100,
stimulus: 'img/block.png',
choice: ['B']
};


Do you have any idea on how to circumvent this? The basic structure of one trial in my case is:

t - trial duration
s - stimuli duration.
d = difference between trial duration and stimuli duration (t-s)

once s gets presented, I need to be able to gather the RT from onset of s through d until the end of t. My understanding was that seting those parameters as they are above, should work exactly as I wrote it?

Thanks for the help again!

Josh de Leeuw

unread,
Feb 21, 2017, 11:51:01 PM2/21/17
to sebastija...@gmail.com, jsPsych
Yes, that should work. I just tested it on my build and it seems to work fine. You have a typo in your choice (should be choices) parameter but otherwise everything looks good.

--
You received this message because you are subscribed to the Google Groups "jsPsych" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jspsych+u...@googlegroups.com.
To post to this group, send email to jsp...@googlegroups.com.

sebastija...@gmail.com

unread,
Mar 6, 2017, 10:50:13 AM3/6/17
to jsPsych, sebastija...@gmail.com
Hi! The majority works now and I am almost done.

I have one final question:

How could one modify the single-stim plugin such that you're able to accept multiple key responses per one trial after which different events happen.

I've created an adapted version of the single-stim plugin now such that following a response, you are either flashed a green or red arrow immediately after your response (a picture prompt with immediate updating), depending on your speed. In addition to this, your score constantly updates at the end of the each trial as a usual prompt.

What the final functionality should include is that, after the presentation of the stimuli, if you press a button more than once within one trial, you would be presented with a red arrow each time.

The way the single-stim works is that it accepts only one response for one trial.

I've tried adapting the parts of code from the multi-stim-multi-response such that I would be able to do that but without success.

An alternative that comes to mind would be an additional parameter within the plugin, where I would have a callback function similar to the ones that you've already implemented where it would do conceptually the same thing as "on_data_update" but here it would be "after_each_keypress"

Do you have any suggestions? Much thanks

Josh de Leeuw

unread,
Mar 6, 2017, 3:03:01 PM3/6/17
to sebastija...@gmail.com, jsPsych
You'll need to look into how the getKeyboardResponse method operates.


You can set persist to true to collect multiple responses. The callback would be executed each time the key is pressed. Then you could have logic inside the callback to determine if the key has been pressed more than once.
--Josh

--
You received this message because you are subscribed to the Google Groups "jsPsych" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jspsych+u...@googlegroups.com.
To post to this group, send email to jsp...@googlegroups.com.

maja.k...@gmail.com

unread,
Mar 18, 2017, 9:48:22 PM3/18/17
to jsPsych, sebastija...@gmail.com
I've read that and it was very helpful.

I've set "persist" to true so that it's responsive to multiple key presses.

Within my plugin, I've adapted the code such that, after each key press, a 'picture prompt' gets shown.

There are two things I would like to add here and that I haven't figured out how to do. I have tried a lot of things to get this working and none of them worked so far.

var after_response = function(info) {
if (!trial.is_html) {
display_element.append($('<img>', {
src: trial.pic_prompt,
id: 'jspsych-single-stim-pic-prompt'
}));

} else {
display_element.append($('<div>', {
html: trial.pic_prompt,
id: 'jspsych-single-stim-pic-prompt'
}));

}

if (trial.timing_stim > 0) {
t8 = setTimeout(function () {
$('#jspsych-single-stim-pic-prompt').css('visibility', 'hidden');
}, trial.timing_stim);
setTimeoutHandlers.push(t8);

}
// after a valid response, the stimulus will have the CSS class 'responded'
// which can be used to provide visual feedback that a response was recorded
$("#jspsych-single-stim-stimulus").addClass('responded');

After 2 or more keypresses, the picture prompt always stays on screen. So when I press a key for the first time, the picture prompt appears and dissappears as written in the code (and working as intended), but after the next keypress it appears and stays on until the end of a trial (does this have to do with the timeout?). I'm not sure how to adapt the code such that after each keypress, the picture prompt will appear and dissappear as after the first keypress.

In addition, if there are 2 or more keypresses per trial, I would like for the picture used in the picture prompt to change together with the points that are being generally added up (a variable dynamically changing inside a function in the prompt) as a consequence of 2 or more keypresses per trial.

In pseudocode, I would essentially want to do:
if number of keypresses >= 2
picture propmt = incorrect.jpg
variable in the normal prompt denoting points = variable - 10


I don't know how I can pass the change from the .js plugin file to the .html file where the picture prompt .jpg is defined and the variable for the normal prompt is being updated.

I would really appreciate advice on this, because I have no idea how to implement that at the moment. I've tried a lot of different things but none work.

Josh de Leeuw

unread,
Mar 29, 2017, 10:43:55 PM3/29/17
to maja.k...@gmail.com, jsPsych, sebastija...@gmail.com
This isn't a specific answer to your question, but it sounds like you need some clarification on how the plugin files interact with the html file. This page might help:



--
You received this message because you are subscribed to the Google Groups "jsPsych" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jspsych+u...@googlegroups.com.
To post to this group, send email to jsp...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages