【jsPsych/survey-text】参加者の入力値で刺激条件を分岐させる

235 views
Skip to first unread message

hanyu

unread,
May 12, 2021, 9:12:47 AM5/12/21
to 心理学実験について話そう
黒木先生

初めまして。大阪大学の羽生と申します。

jsPsychの「survey-text.js」ライブラリを使用し、参加者が入力した値に応じて刺激条件が分岐するような状況を設定したいと考えております。
添付のコードは、jsPsychの「jspsych-survey-text.html」を、上記のようになるよう改変したものになります。

このコードを走らせると、survey_page2にて、分岐条件に従ったメッセージが表示されるはずなのですが、実際にはメッセージ部分にundefinedと表示され、うまくいきません。

添付のコードの22、23行目の、
>var last_trial_data = jsPsych.data.get().last(1).values();
>var result_age = last_trial_data.Age;
の処理がうまくいっていないと思われるのですが、どのように変更すれば、意図した挙動になるのか、ご意見いただけませんでしょうか。
どうぞよろしくお願いいたします。


羽生
test2.html

黒木@九州大学

unread,
May 13, 2021, 6:13:01 AM5/13/21
to 心理学実験について話そう
羽生さま

黒木です。

おたずねの件は、jspsychのプログラミングにおいて、非常に分かりにくい部分なんですよね。
私も慣れるまでにすごく時間がかかりました。

まずは、
をご覧ください。

jspsychではある画面での回答に基づいて、動的に画面表示を切り替えるときには、少し変わった方法を使う必要があります。
いくつかの方法が考えられますが、私は on_startを使っています。
詳細は上記のURLにまとめていますのでご参照ください。

一応、 羽生さんのご希望通りの動作をするプログラムも添付しておきます。

ところで、javascriptのコンソール画面はお使いでしょうか。
もしお使いでなければ、まずはこれに慣れることをお勧めします。
添付プログラムにもたくさん書いていますが、
console.log
を使うと、変数の内容をコンソール画面で確認できるようになります。

これを知らないと、jspsychのプログラミングは非常に分かりづらくなります。
私はいまでも、コンソール画面に変数の中身を表示させながらプログラミングをしています。
ご参考までにお伝えしておきます。


2021年5月12日水曜日 22:12:47 UTC+9 hanyu:
test2kuroki.html

hanyu

unread,
May 14, 2021, 6:43:55 AM5/14/21
to 心理学実験について話そう
黒木先生

羽生です。お忙しい中、早速のご対応ありがとうございます。

コードとURLのご紹介をありがとうございました。どちらも拝読いたしました。コードの最も外側で、参加者の入力した値を呼び出してもうまくいかない理由がよくわかりました。
console.log()についてもありがとうございました。コーディングがかなり楽に・わかりやすくなりました。

もう一点追加でお伺いしたいのですが、
参加者の入力した値によって刺激が変わるtrial変数(添付していただいたコードでいうところのsurvey_page2など)が複数ある場合、いただいたコードの書き方に従うと、毎回on_startの部分に分岐条件を入れることになるかと思います。
そうなると、どうしてもコードが長くなり、可読性が落ちてしまうと思うのですが、これを回避する何かよい方法はありますでしょうか。
例えば、添付のコードのような状況を考えています。
添付のコードでの、参加者の入力した値で決定される3つの変数Nfol、nStart、nEndは、各変数のブロック内で宣言されます(33-77行目)。
このため、別のブロック内でこれらの変数を参照する必要がある場合、もう一度宣言することになります(143-189行目)。

一つ考えたのは、参加者の情報を入力する際、「survey-text」を使用する代わりに、javascriptのprompt()を使用する方法です。
コードの最も外側でpromptを使用し、入力された値で刺激条件を先に宣言すれば、後はtrial変数で条件を参照するだけなので、すっきりしたコードになる気がします。
ただし、promptは一度に一つの項目しか入力できないので、条件の分岐に必要な項目がたくさんあった場合、参加者さんの手間が増えてしまうのですが。。

単純に私のコードの書き方がよろしくないことももちろんあるかと思いますが、上記について、ぜひご意見等お聞かせいただけましたら幸いです。
どうぞよろしくお願いいたします。


羽生

2021年5月13日木曜日 19:13:01 UTC+9 黒木@九州大学:
test4.html

黒木@九州大学

unread,
May 14, 2021, 9:43:32 PM5/14/21
to 心理学実験について話そう
羽生さま

黒木です。ご質問の内容をまだ正確に把握できていないかもしれませんが、回答してみます。

var procedure = [];
の下あたりに、
var Nfol, nStart, nEnd
のようにして、これらをグローバル変数として宣言しておきます。
そうすることで、プログラム内のどこからでも参照できるようになります。
このとき初期値を設定してもいいですし、しなくてもいいです。

そして、先述の通り、on_start関数の中で、値を設定してやります。
このときに大事なことは、var をつけずに値を代入することです。
例えば、on_startのなかで、
Nfol = 1
とするわけです。
そうすると、別の関数内でも、Nfolは1として利用できます。

varをつけるのは、この変数を使うよ、という宣言のためです。
(余談ですが、今後、javascriptを使う機会が増えるのでしたら、varの代わりに、const, letを使うように習慣づけたほうがバグが入りにくくなります)

なので、すでに宣言した変数については、varをつける必要はありません。逆につけてしまうと、on_startの中でしか参照できない変数になったような気がします。
(ごめんなさい、未確認です。これは変数のスコープと関連があります)

もし、的外れな回答でしたら、再度ご連絡ください。どうぞよろしくお願いいたします。

黒木


2021年5月14日金曜日 19:43:55 UTC+9 hanyu:

hanyu

unread,
May 17, 2021, 5:43:07 AM5/17/21
to 心理学実験について話そう
黒木先生、

羽生です。何度もお返事いただいて、本当にありがとうございます。

ご教授いただいた方法でコードを書き直したところ、うまくいきました。
> 別の関数内でも、Nfolは1として利用できます。
これは、他のtrial変数内の、on_startやstimulusなどで使用する関数内で、ということなのですね。
関数内なら、どこに書かれたものでもよいのだと思っておりました。。
大変勉強になりました。

初歩的な質問にもかかわらず、ご丁寧にご対応いただき、本当にありがとうございました。


羽生

2021年5月15日土曜日 10:43:32 UTC+9 黒木@九州大学:

黒木@九州大学

unread,
May 17, 2021, 9:26:31 PM5/17/21
to 心理学実験について話そう
羽生様

> これは、他のtrial変数内の、on_startやstimulusなどで使用する関数内で、ということなのですね。
> 関数内なら、どこに書かれたものでもよいのだと思っておりました。。

すみません、この文章の意味をまだ正確に理解できていないです。

例えば、以前のプログラムで、 羽生さんが
var procedure = [];
と宣言されていますが、これはグローバル変数といって、まさにどこからでも参照できます。
だったらすべての変数をグローバル変数にしておけばいいのではないかと思われるかもしれませんが、その場合、予期しないところで変数の中身が変わってバグを含むリスクが高まるので、変数の有効範囲(スコープ)は可能な限り小さく、というのがプログラミングの大前提です。

例えば、on_startの中で宣言した変数は、on_startの中でしか参照できません。
不便そうに見えますが、on_startの中でしか参照しないのであれば、 on_startの中で宣言すべきです。

なお、やや脱線しますが、当初の質問に立ち返ると、実験中に参加者が回答した内容に応じて動的に実験内容を変更するときには、on_start(またはon_finish)で値を代入すると便利です。
このとき変数をグローバルにするかどうかはプログラムによって変わります。 羽生さんの今回のプログラムではグローバルで宣言しておいたほうがコードがすっきりしそうということですね。
それで可読性が高まるのであればグローバル変数で宣言してよいと思います。

スコープに関する説明は
などが、参考になるかと思います。

黒木

2021年5月17日月曜日 18:43:07 UTC+9 hanyu:

hanyu

unread,
May 18, 2021, 8:22:09 AM5/18/21
to 心理学実験について話そう
黒木先生

羽生です。ご連絡ありがとうございます。

>>これは、他のtrial変数内の、on_startやstimulusなどで使用する関数内で、ということなのですね。
>> 関数内なら、どこに書かれたものでもよいのだと思っておりました。。
>すみません、この文章の意味をまだ正確に理解できていないです。

初歩的な勘違いでお恥ずかしいのですが、例えば、
var num;
のように、複数箇所で参照したい変数をグローバル変数として宣言した後、
var trial = { type: ...,
    stimulus: ...,
    on_start: function(){
                     var last_trial_data = jsPsych.data.get().last(1).values();
                     num = last_trial_data[0].response.hoge; }
 }
のように、on_start内で、グローバル変数のnumに値を代入すれば、
その直後に、on_start内でもtrial変数内でもない外側で、
var A = function () { return num*num; };
としても、last_trial_data[0].response.hogeが代入された変数numを正しく参照できる、と思っておりました。
実際には、numへの代入は、var trialが実行された際に行われるため、いくらvar A = function()...をtrialの後に書いていても、正しい値は参照できないのですが。。
ややこしい説明になってしまい申し訳ありません、ご不明な点がございましたら、お知らせいただけますと幸いです。

> on_start(またはon_finish)で値を代入すると便利です。
ご教授ありがとうございます。いただいたアドバイスとコードを基に、なんとかコードが書けました。
どうしてもグローバル変数を多用してしまう実験条件ですので、バグなど発生しないか、これから細かくチェックしていこうと思います。
本当にお手数をおかけしてしまい、大変申し訳ありませんでした。


羽生

2021年5月18日火曜日 10:26:31 UTC+9 黒木@九州大学:

黒木@九州大学

unread,
May 19, 2021, 3:12:44 AM5/19/21
to 心理学実験について話そう
羽生様

ご説明ありがとうございます。
おかげさまで、おっしゃっていることを理解できました。
その上で、少し補足しておきます。

> 実際には、numへの代入は、var trialが実行された際に行われるため、

この文章には微妙に誤りがあるように感じていて、var trialの実行タイミングと、trial内のon_startのタイミングは異なります。
「var trialが実行された」状態が何を意味するかという、言葉の使い方の問題とも言えますが。

var trialは実験用のコードが読み込まれたとき(参加者が実験画面にアクセスしたとき)に実行されます。
例えば、trialの中でtypeを何にするか、stimulusを何にするかを記述しますが、それらはすべて実験の開始時に決定されます。

しかし、羽生さんの今回のプログラムのように、それを後から変更したいこともあり得ます。
その時には、functionを使って指定します。
実は stimulusにもfunctionが指定できます。
もし、まだ
https://www.jspsych.org/overview/dynamic-parameters/
をご覧になったことがなければ、ご参照ください。

すでにご理解いただいている内容だったかもしれませんが、念のために補足をしておきます。

黒木

2021年5月18日火曜日 21:22:09 UTC+9 hanyu:
Reply all
Reply to author
Forward
0 new messages