8.Go-NoGoTask
Go/NoGoTaskを作成してみましょう。
このページは,jsPsychの公式サイト tutorialと
九州大学黒木 大一朗先生のサイト
を参考に作成しました。
ここで紹介するGo/NoGo taskは,青の円がでたらできるだけ早くFキーを押す,オレンジの円が出たらどのキーも押さないというものです。Go/NoGo taskのsequenceは,図1の通りです。青とオレンジがそれぞれ5回提示されます。青とオレンジは,疑似ランダムに提示される様に設定していきます。
https://gyazo.com/fb33a5f5e0271aa71e76c5beb6756003
図1.Go/NoGo taskのシークエンス。
それでは,実際のコードを見ていきます。
まず,ヘッダーからです。
今回は,日本語でwelcomeメッセージやinstruction(計測の説明)を日本語で記述するため,以下のコードをヘッダーに追加します。この一文がなければ日本語で書いた文章は文字化けします。
code:1.html
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
今まで通り,まず,jsPsychのライブラリーを読み込みます。preloadを読み込みます。文章を記述するため,html-keyboard-response.jsを読み込みます。
code:2.html
<script src="jspsych-6.3.1/jspsych.js"></script>
<script src="jspsych-6.3.1/plugins/jspsych-preload.js"></script>
<script src="jspsych-6.3.1/plugins/jspsych-html-keyboard-response.js"></script>
次に,図形(青丸とオレンジの丸)を表示してキーボードで反応を取得するので,jspsych-image-keyboard-response.jsを読み込みます。
code:3.html
<script src="jspsych-6.3.1/plugins/jspsych-image-keyboard-response.js"></script>
最後に,<link>を使ってスタイルシートを読み込みます。
<script>~</script>です。ここでは,具体的に参加者に提示する,welcomeメッセージやinstruction,fixation1など,図1の四角で囲まれたブロックをそれぞれの変数として作成していきます。
その後,作成した変数を時系列にtimelineに加えていきます。
まず,timelineの定義です。作成した変数をこの入れ物に入れていきます。
code:create timeline.html
var timeline = [];
次に,preloadです。事前に自動で画像を読み込む様にしておきます。
code: preload.html
var preload = {
type: 'preload',
auto_preload: true
}
次は,welcomeメッセージです。
画面中央に「研究にご参加いただきありがとうございます。<br>計測を開始するにはいずれかのキーを押して下さい。」を提示したいと思います。<br>は,改行です。
varを使ってwelcomeを以下の様に定義します。
typeは,"html-keyboard-response",stimulusは, "研究にご参加いただきありがとうございます。<br>計測を開始するにはいずれかのキーを押して下さい。"とします。
welcomeを定義したら,timeline.pushでtimelineに加えます。
code:define welcome message.html
var welcome = {
type: "html-keyboard-response",
stimulus: "研究に参加いただきありがとうございます。<br>計測を開始するにはいずれかのキーを押して下さい。"
};
timeline.push(welcome);
次に,instructionです。
https://gyazo.com/67b0dfedf6fc132c8dd32b379a3922d1
図2.instruction,説明文と円の関係。
図2の様に,説明文を最初に書き,その後にに青とオレンジの円を横に並べます。それぞれの円の下には,参加者がどの様に反応するか,簡単な説明をつけます。最後に,キーを押して実験を開始する様に促します。
ここで使用する画像(blue.pngとorange.png)は,jspsych-6.3.1\examples\imgに入っています。
以下の例では,researchesフォルダの中に新たにimgフォルダを作成し,2つの画像ファイルを移動させました。
また,重複を避けるため,以下の画像のパスを変更しても構いません。
img/blue.png → jspsych-6.3.1/examples/img/blue.png
img/orange.png → jspsych-6.3.1/examples/img/orange.png
適宜変更してください。
まず,varを使用してinstructionsを定義します。文章を提示するので,typeは,"html-keyboard-response"とします。stimulusは,<p>を使用します。途中,<strong>青</strong>を用いることで文字を太字で強調します。
次に,青とオレンジの2つの円を横に並べるため,<div style='width: 700px;'> を使用して,この部分だけ横幅を700ピクセルに変更します。
<div style='float: left;'>を使用して,左側に青い円を配置します。
<div class='float: right;'>を使用して,右側にオレンジの円を配置します。
それぞれの円の下に説明文をつけるので,<p class='small'>を使用して文章を記述します。
</div>を最後に入れることで,元のスタイルの設定に戻ります。
instruction後すぐに計測が開始しない様にpost_trial_gapを使用して,2秒後に開始する様に設定しました。
最後に,instructionsをtimelineに加えます。
code:define instructions trial.html
var instructions = {
type: "html-keyboard-response",
stimulus: "<p>この計測では、画面の中央に色のついた円が呈示されます。<br>" +
"もし円の色が<strong>青</strong>だったら、できるだけ速く「Fキー」を押して下さい。<br>" +
"もし円の色が<strong>オレンジ</strong>だったら、どのキーも押さないで下さい。</p>" +
"<div style='width: 700px;'>"+
"<div style='float: left;'><img src='img/blue.png'></img>" +
"<p class='small'><strong>Fキーを押して下さい。</strong></p></div>" +
"<div class='float: right;'><img src='img/orange.png'></img>" +
"<p class='small'><strong>どのキーも押さないで下さい。</strong></p>"+
"</div>" +
"</div>"+
"<p>計測を開始するにはいずれかのキーを押して下さい。</p>",
post_trial_gap: 2000
};
timeline.push(instructions);
次に,課題開始のfixation1の定義です。
これは,いきなり円が出ない様に,fixation(固視点)を2秒間提示します。
varを使用して fixation1を定義します。
fixationは,文字「+」を使用しますので,typeは,"html-keyboard-response"を使用します。stimulusは,「+」,フォントサイズは60pxとしています。この時,参加者のボタン押しは必要ないので,choicesは,jsPsych.NO_KEYSとします。2秒間提示したままにするので,trial_durationは,2000とします。計測後,結果のデータcsvファイルで収集します。パフォーマンスを評価するため,刺激の種類を,dataで{test_part: 'fixation'}と設定します。
最後に,timelineにfixation1を追加してください。
code:fixation1
var fixation1 = {
type: 'html-keyboard-response',
stimulus: '<div style="font-size:60px;"> + </div>',
choices: jsPsych.NO_KEYS,
trial_duration: 2000,
data: {test_part: 'fixation'}
}
timeline.push(fixation1);
次に,図1の2段目からの内容です。課題中の刺激(fixation,Go,NoGo)を作成していきます。疑似ランダムの配列については,fixationと刺激の定義後に設定していきます。
まずは,課題間のfixationです。
このfixationは,durationを1-2.25秒とすることで参加者に課題のタイミングを予測させないようにします。そのために,fixationを定義する前に,durationをランダムに設定できるfix_durationを定義します。
Math.random()関数は,0–1(0以上1未満)の範囲で擬似乱数を返します。
Math.floorは,引数として与えた数以下の最大の整数(少数点以下切り捨て)を返します。
次に,fixationです。基本的にはfixation1と同様です。違うところは,trial_durationが,fix_durationとなっているところです。
code:fixation.html
var fix_duration = function() {
return Math.floor( Math.random() * 1500 ) + 1000;
}
var fixation = {
type: 'html-keyboard-response',
stimulus: '<div style="font-size:60px;"> + </div>',
choices: jsPsych.NO_KEYS,
trial_duration: fix_duration,
data: {test_part: 'fixation'}
}
次に,画像を読み込むための変数と画像を提示する変数をそれぞれ定義します。
まず,画像を読み込むための変数,test_stimuliをvarを使用して定義します。
この中に青とオレンジの円を読み込みます。さらに,参加者のパフォーマンスを評価するため,dataを定義し,その中に課題の種類(test_part)と正解のキー(correct_response)を,タグ付けします。青い円が提示されたときは,Fキーを押すのでcorrect_response: 'f' ,オレンジの円が提示されたときは,どのキーも押さないので correct_response: '' ←空とします。
画像を提示するための変数,test_stimuliをvarを使用して定義します。
varを使用して,testを定義します。ここでは,画像を提示するための変数を定義します。
画像を提示するので,typeは, "image-keyboard-response"とします。
stimulusは,timelineにある変数を取得してくるので, jsPsych.timelineVariableを使用し,test_stimuli で定義した'stimulus'を読み込んできます。
choicesは,すべてのキーをとって来るようにしたいので,jsPsych.ALL_KEYSとします。
刺激の提示時間 trial_durationは,1500m秒とします。オレンジの円は,ボタン押しをしないので1500m秒経ったら消えるようにします。
提示後の処理 on_finishは,ここで参加者の反応を評価します。
参加者の押したキーボードの文字がdata.responseに入ってくるので,
jsPsych.pluginAPI.compareKeysを使って,data.responseとその問題の正解であるcorrect_responseを比較します。
前バージョンではcorrect_responseの空欄とdata.responseの'null'を比較をしてくれていたのですが
このバージョンから上手くいかないので,correct_responseに適当な文字'q'を代わりに入れます。
testの終了作業(on_finish)のときにdata.responseを'q'に置き換えて,correct_responseと比較させます。
code:test_stimuli.html
var test_stimuli = [
{stimulus: "img/blue.png", data: { test_part: 'test', correct_response: 'f' } },
{stimulus: "img/orange.png",data: { test_part: 'test', correct_response: 'q' }}
];
var test = {
type: "image-keyboard-response",
stimulus: jsPsych.timelineVariable('stimulus'),
choices: jsPsych.ALL_KEYS,
data: jsPsych.timelineVariable('data'),
trial_duration: 1500,
on_finish: function (data) {
if (data.response != null) {
} else {
data.response = 'q';
}
data.correct = jsPsych.pluginAPI.compareKeys(data.response, data.correct_response);
},
}
それでは,faxationと刺激(test)ができたので,timelineに入れていきます。
faxiationとtestを計測のたびに並べ替える必要はありません。
test_procedureを以下のように定義することで,青円→fixation→オレンジ円→fixationまたはオレンジ円→fixation→青円→fixationを疑似ランダムに5回繰り返してくれます。
そして,最後にtimeline.pushで,timelineにtest_procedureを忘れないように挿入します。
code:randam.html
// timelineを作成する
var test_procedure = {
timeline_variables: test_stimuli,
repetitions: 5,
randomize_order: true
}
timeline.push(test_procedure);
次は,参加者に結果を返します。
varを使用してdebrief_blockを定義します。文章で結果を返すので typeは,"html-keyboard-response"です。
stimulusは,正答率,青い円が出た時の正答反応時間の平均をfunctionを使って算出します。その後に,文章に値を入れて表示するようにしています。
code:debrief.html
/* define debrief block */
var debrief_block = {
type: "html-keyboard-response",
stimulus: function() {
var trials = jsPsych.data.get().filter({test_part: 'test'});
var correct_trials = trials.filter({correct: true});
var accuracy = Math.round(correct_trials.count() / trials.count() * 100);
var rt = Math.round(correct_trials.select('rt').mean());
return "<p>あなたの正答率は "+accuracy+"% でした。</p>"+
"<p>あなたの反応時間の平均値は <strong>" + rt + "ms</strong> でした。</p>" +
"<p>実験を終了するにはいずれかのキーを押して下さい。</p>" +
"<p>ご協力いただきましてありがとうございました。</p>";
}
};
timeline.push(debrief_block);
これが本当の最後です。timelineまでは今までと同じですが,計測後の処理が少し異なります。
計測終了後,結果をモニタ上に形式を指定せず表示していましたが,jsPsych.data.displayData('csv');とすることでCSV形式で表示するように設定しています。さらに,その結果をjsPsych.data.get().localSave('csv', 'data.csv');とすることでdataという名前でダウンロードする設定にしました。保存先は,特に変更をしていなければ,defaultのdowloadフォルダに保存されることになります。
code:save.html
/* start the experiment */
jsPsych.init({
timeline: timeline,
on_finish: function() {
jsPsych.data.displayData('csv'); //終了後CSV形式でデータを画面上に表示
jsPsych.data.get().localSave('csv', 'data.csv');
}
})
それでは,GoNoGoTask.htmlをresearchに保存後,ダブルクリックして実際に動かしてみましょう。
code: GoNoGoTask.html
<!DOCTYPE html>
<html>
<head>
<title>GoNoGoTask</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="jspsych-6.3.1/jspsych.js"></script>
<script src="jspsych-6.3.1/plugins/jspsych-preload.js"></script>
<script src="jspsych-6.3.1/plugins/jspsych-html-keyboard-response.js"></script>
<script src="jspsych-6.3.1/plugins/jspsych-image-keyboard-response.js"></script>
<link href="jspsych-6.3.1/css/jspsych.css" rel="stylesheet" type="text/css"></link>
</head>
<body></body>
<script>
/* create timeline */
var timeline = [];
var preload = {
type: 'preload',
auto_preload: true
}
/* define welcome message */
var welcome = {
type: "html-keyboard-response",
stimulus: "研究に参加いただきありがとうございます。<br>計測を開始するにはいずれかのキーを押して下さい。"
};
timeline.push(welcome);
/* define instructions trial */
var instructions = {
type: "html-keyboard-response",
stimulus: "<p>この実験では、画面の中央に色のついた円が呈示されます。<br>" +
"もし円の色が<strong>青</strong>だったら、できるだけ速く「Fキー」を押して下さい。<br>" +
"もし円の色が<strong>オレンジ</strong>だったら、どのキーも押さないで下さい。</p>" +
"<div style='width: 700px;'>"+
"<div style='float: left;'><img src='img/blue.png'></img>" +
"<p class='small'><strong>Fキーを押して下さい。</strong></p></div>" +
"<div class='float: right;'><img src='img/orange.png'></img>" +
"<p class='small'><strong>どのキーも押さないで下さい。</strong></p></div>" +
"</div>"+
"<p>実験を開始するにはいずれかのキーを押して下さい。</p>",
post_trial_gap: 2000
};
timeline.push(instructions);
/* define test trial */
// 計測開始前2秒間にfixationを出す。
var fixation1 = {
type: 'html-keyboard-response',
stimulus: '<div style="font-size:60px;"> + </div>',
choices: jsPsych.NO_KEYS,
trial_duration: 2000,
data: {test_part: 'fixation'}
}
// choicesは,参加者が使用できるキー
// jsPsych.NO_KEYSはどのキーも反応しない
timeline.push(fixation1);
var fix_duration = function() {
return Math.floor( Math.random() * 1500 ) + 1000;
}
// 1000から2250の値をランダムに返す
// Math.floor 引数として与えた数以下の最大の整数を返す
// Math.random()関数は、0–1(0以上、1未満)の範囲で擬似乱数を返す
var fixation = {
type: 'html-keyboard-response',
stimulus: '<div style="font-size:60px;"> + </div>',
choices: jsPsych.NO_KEYS,
trial_duration: fix_duration,
data: {test_part: 'fixation'}
}
// 全キーの場合は,choices: jsPsych.ALL_KEYS
// 刺激の定義
var test_stimuli = [
{stimulus: "img/blue.png", data: { test_part: 'test', correct_response: 'f' } },
{stimulus: "img/orange.png",data: { test_part: 'test', correct_response: 'q' }}
];
var test = {
type: "image-keyboard-response",
stimulus: jsPsych.timelineVariable('stimulus'),
choices: jsPsych.ALL_KEYS,
data: jsPsych.timelineVariable('data'),
trial_duration: 1500,
on_finish: function (data) {
if (data.response != null) {
} else {
data.response = 'q';
}
data.correct = jsPsych.pluginAPI.compareKeys(data.response, data.correct_response);
},
}
// jsPsych.timelineVariable timelineにある変数を取得してくる
// data.response -> 参加者が押したボタン(数字)
// これがdata.correct_responseと一致している場合,data.correctは,trueを返し,そうでない時はfalseを返す。
// timelineを作成する
var test_procedure = {
timeline_variables: test_stimuli,
repetitions: 5,
randomize_order: true
}
timeline.push(test_procedure);
/* define debrief block */
var debrief_block = {
type: "html-keyboard-response",
stimulus: function() {
var trials = jsPsych.data.get().filter({test_part: 'test'});
var correct_trials = trials.filter({correct: true});
var accuracy = Math.round(correct_trials.count() / trials.count() * 100);
var rt = Math.round(correct_trials.select('rt').mean());
return "<p>あなたの正答率は "+accuracy+"% でした。</p>"+
"<p>あなたの反応時間の平均値は <strong>" + rt + "ms</strong> でした。</p>" +
"<p>実験を終了するにはいずれかのキーを押して下さい。</p>" +
"<p>ご協力いただきましてありがとうございました。</p>";
}
};
timeline.push(debrief_block);
/* start the experiment */
jsPsych.init({
timeline: timeline,
on_finish: function() {
jsPsych.data.displayData('csv'); //終了後CSV形式でデータを画面上に表示
jsPsych.data.get().localSave('csv', 'data.csv');
}
})
</script>
</html>
次は,全画面表示のときの変更について言及します。
https://gyazo.com/ad42b4e5fba2e91518e9cc11e5c8afe2
【目次】