例題18-4:Builderで行こう¶
A: さってさて、いよいよPsychoPy Builderですな。うーっ、緊張するー。
B: 珍しいですね。Aさんが緊張するとか言ってるのは。
A: あー、何しろ自分でもあまりよくわかってないツールの解説だからな。うかつなことを言わないか不安になるってもんよ。
B: 前々回からAさんBuilderはあまり知らないとか経験がないとかいろいろ言いますけど、実際どのくらい使ったことがあるんですか?
A: 今日で三日目。
B: えぇ?! 経験ないとかいうレベルじゃないじゃないですか。
A: ま、それでも例題18-3で取り上げた程度のものならすぐに出来ちゃうってことよ。なかなかすごいじゃナーイ?
B: なんですかその口調は。うさんくさい。
A: ま、ともかくBuilderよ。Builder Viewを開くとこんな感じの画面が出て来る。OSによってちょっと違うが、だいたい似たようなレイアウトになるはずだ。ちなみにこれはWindows 7上で動作させている時のキャプチャだ。
B: このなんたらペインとかいうのは?
A: 名前がないと文で表現するのが面倒くさいので勝手に名前を付けた。ポイントはこのデカいRoutineペインと下のFlowペインである。B君、思い出してほしい。心理学実験プログラムの基本中の基本と言えば?
B: へ? 基本中の基本? なんだろ。バグらないこと?
A: 違う。「繰り返し」だ。例題1でさんざん叩き込んだだろ。
B: えー。そんなこと聞いたことありませんが。
A: いや、言っているはず。そら、原稿を検索する、と…。
B: と?
A: あれ…そんなに強調して言っていないな…おかしいな…
B: なんですって?
A: あ、いや、その。とにかく。 心理学実験ではちょっとだけ条件が違う作業をひたすら繰り返すことが非常に多いのだ 。ほんの少し長さが違うとか、ほんの少し色が違うとか、そういうものを判断する作業を時には数時間にわたって何度も繰り返させるのが心理学実験である。卒論の追い込みなどの忙しい時期に友人を何時間も実験に巻き込んで友人関係にひびが入ったり、卒業してからも顔を合わせるたびに「あの時のアレは…」と文句を言われ続けることこそ基本中の基本なのである。
B: こんなのどうやってツッコんだらいいんだよ…
A: というわけで、心理学実験なんてのは「まず○○を5秒表示して、次に△△を表示して、実験参加者の判断を待つ」などという型どおりの作業と、その作業をどのように繰り返すかを指定すれば出来てしまうのである。この「型どおりの作業」を示したものがRoutineで、Routineをどのように繰り返すかを示すのがFlowである。
B: (あ、ツッコまなくても勝手に軌道修正された)
A: 今回は先の例題18-3をBuilderで作ってみようということで、まず18-1.pyを再現することを目指す。18-1.pyがしていることをまとめると以下のようになる。
まず、画面中央に「5秒待ちます」と描く。
現在の経過時間を取得して画面に描く。
5秒経過していなければ2へ戻る。経過していれば終了する。
B: ふむ。1.や2.がRoutineで、2と3を繰り返すのがFlowってわけですね。なるほどなるほど。
A: いや、違う。PsychoPyではこれをすべてまとめてひとつのRoutineとなる。
B: ええっ? なんで?
A: この辺が最初につまづくところかも知れんな。そもそも前回の18-1.pyで使ったpsychopy.core.TextStim.draw()とか自体も膨大な型どおりの作業をひとまとめにして名前を付けたもので、そういう「まとまり」の中まで言い出したらキリがない。Builderでは上の1から3の作業はひとまとまりのRoutineとして扱うんだ。
B: いきなり出鼻をくじかれた気分…。
A: ま、小難しい話はこの辺にしておいて、このRoutineをBuilderで作ってみよう。あるRoutine内で文字を描画するには、右側のComponentsペインにあるTextというコンポーネントをクリックする。
B: ダイアログが開きました。
A: ここで文字をどのように描画するかを指定する。 いきなりたくさんあって圧倒されるかも知れないが、後々大事なものも多いので一応全部順番に見ておこう。
オプション |
概要 |
備考 |
Name |
Routineペインに表示する時の名前を指定する。ひとつのRoutineに文字列が複数含まれる時などには異なる名前を付けて区別できるようにする必要がある。 |
同じ名前を持つコンポーネントが追加されると自動的に _2 などと末尾につく。 |
Start |
このRoutineが始まってから何秒後、何フレーム後…から文字列を表示するか指定する。 |
time(s):秒で指定 |
Stop |
この文字列がいつ画面から消えるかを指定する。Routineが始まってから |
duration(s):表示された時刻を基準に秒で指定 |
Color |
文字色を指定する。 |
3要素のリスト(e.g. [-1,-1,1])や色名(red)などが使える。例題18-3も参照のこと。 |
Color space |
色空間を指定する。 |
|
Font |
使用するフォントを指定する。 |
欧文フォントであるArialが標準で指定されているがそのままで日本語も表示されれる。 |
Letter height |
1文字の高さを指定する。 |
|
Opacity |
文字の透明度を指定する。 |
0.0から1.0の値。0.0なら完全に透明、1.0なら完全に不透明。 |
Orientation |
回転角度を指定する。 |
単位はdegで時計回り。 |
Position [x,y] |
文字列を描画する位置を指定する。 |
文字列の上下中心、左右中心の位置。 |
Text |
表示する文字列を指定する。 |
デフォルトで入力されている文字列が示すように改行可。 |
Units |
この文字列の描画に用いる単位を指定する。 |
この実験で標準に指定されている単位(後述)を使うならfrom exp settingsにしておけばよい。heightは未サポート。 |
Wrap width |
長い文字列が与えられた時の折り返し幅を指定する。 |
B: 結構多いんで大変だと思いましたが例題18-3を見ていればそんなに難しくないですね。時間関連の項目が増えたくらいですか。
A: うむ。そうだな。さて、18-1.pyと同じ動作にするためにはどこに何を設定すればいい? とりあえず「5秒待ちます」という文字列だけ考えてくれ。
B: ええと、まずTextに「5秒待ちます」と入力。u' 'は要らないんですか?
A: 文字コードを正しく判別してくれるので不要だ。
B: ううっ、ありがたいなあ。あとは…
A: 色とかフォントの大きさとかはそのままでいいぞ。
B: じゃ、表示開始時刻と終了時刻ですか。プログラムが始まってからすぐに文字を表示するんだからStartが0。5秒表示するんだからStopはduration(s)で5。…この(s)ってのは秒(second)のことでいいんですよね?
A: その通り。他はそのままでいいだろう。ダイアログの下の[OK]を押して閉じてくれ。
B: StartやStopの下に薄く表示されているExpected durationっていうのは?
A: それは次の画面を見た方が説明しやすいからまずOKして。
B: はーい。おお、こんなの出てきました。
A: このRoutineではtextが5秒間表示されるってのがぱっとみてわかるかと思う。この表示を timeline という。 ここでさっきのB君の質問だが、もしStartやStopの単位にframeを指定すると、Builderにはそれが何秒に相当するかわからないのでtimelineが正しく表示されなくなってしまう。RoutineペインのTextのアイコンやtimelineをクリックするとさっきのダイアログがもう一度出て来るから、Stopの単位を frame N にでもしてみて。値は正の数値が入っていれば何でもいい。変更したらまたダイアログの下の[OK]をクリック。
B: あらら、timelineが消えちゃいましたね。
A: ここで自分のディスプレイのリフレッシュレートを知っていれば、さっきのExpected Durationの欄に自分で設定した値が何秒に相当するのか計算して入力しておけば、タイムラインがきちんと表示される。
B: なるほど。
A: ちょっと蛇足だったな。さて、これで完成だ。
B: へ? もう完成?
A: うむ。実行してみよう。実行してみるには画面上部のツールバーのこの緑色のアイコンをクリックする。よくプログラムを実行させることを run と言うが、まさに run って感じのアイコンだな。
B: クリックしました。なんだかファイルを保存する場所を聞いていますが?
A: Builderは作製した実験を.psyexpという拡張子を持つXMLファイルに保存する。そのファイルの保存場所を聞いているんだな。どこか適当な場所に保存して。
B: 保存しました。今度はなんだか小さなダイアログが出てきました。
A: それは実験参加者名などを保存するためのダイアログだ。今回はどのような情報を保存するか何も指定していないので、標準の項目が表示されている。今は特に保存する情報もないからそのまま[OK]して。
B: はーい。 …おおー、表示されますね。5秒経つと自動で終わる。
A: どうだ。簡単だっただろ?
B: はい。pythonの知識は特に必要ありませんでしたね。
A: で、後は保留していた経過時間の表示だが…。
B: ? なんだか気が重そうですね?
A: うむ。その前にちょっとさっきのダイアログの話をしておくか。Builderでは全般的な実験の設定が出来る。「全般的な」って言っても何のことだかさっぱりだろうから具体的に言うと、ツールバーのこのアイコンをクリックすると設定ダイアログが表示される。
B: クリックしました。
A: ここでこの実験に関するいろいろな設定が出来る。
オプション |
概要 |
備考 |
Experiment name |
この実験の名前を指定する。データファイルなどに出力される。 |
|
Show info dlg |
実験開始時にダイアログ(infoダイアログ)を表示する。このチェックを外しておけばいきなり実験が始まる。 |
|
Experiment info |
infoダイアログで入力させたい項目を定義する。 |
pythonのdict形式で書く。 |
Save excel file |
Excelの.xlsx形式でデータを保存する。 |
|
Save csv file (summaries) |
CSV形式でデータを保存する。 |
|
Save csv file (trial-by-rial) |
CSV形式でデータを保存する。 |
|
Save psydat file |
Builder読字のpsydat形式のデータファイルを保存する。 |
|
Save log file |
ログを出力する。 |
|
Logging level |
ログに出力する内容を指定する。 |
|
Monitor |
Monitor Centerに登録されているディスプレイを指定する。 |
ディスプレイ名をテキストで書く。 |
Screen |
nVidiaやAMDのグラフィックカードを使用していて複数のディスプレイが接続されている時(=マルチディスプレイ)、何番目のディスプレイを使用するか指定する。 |
|
Full-screen window |
チェックするとフルスクリーンモードで実験を行う。 |
|
Window size (pixels) |
フルスクリーンモードを使用しない場合、刺激描画に用いるウィンドウのサイズを指定する。 |
単位はpixでなければならない。フルスクリーンモードを指定すると設定できなくなる。 |
Color |
ディスプレイの色を指定する。 |
|
colorSpace |
ディスプレイの色を指定する時の色空間を指定する。 |
|
Units |
この実験で使用するデフォルトの単位を指定する。 |
視覚刺激をRoutineペインに追加する時のダイアログでunitsにfrom exp settingsを指定するとここで指定した単位が用いられる。ここでuse prefsを指定すると例題18-2で解説したPreferencesでの設定が用いられる。 |
Enable Escape |
この項目をチェックしておくと、実験の途中でEscapeキーを押して強制的に中断することが出来る。 |
実験の中でEscapeキーを反応として記録するように設定していると強制中断できない。 |
Save data folder |
Preferencesで設定されているディレクトリ以外に保存したい場合はここで指定する。 |
|
Show mouse |
この項目をチェックしておくとマウスカーソルが表示される。 |
B: むは、長いですがそんなに難しくないですね。ただ、Experiment infoのdict形式で指定するというのは…。
A: pythonの文法を知らないと設定できない項目がついに出てきちゃったな。
B: ですね。
A: B君はもう知ってるよな?
B: はい。一応。例えばparticipantという項目にp0000という文字列を事前にセットしておきたい場合はこのように書けばいいと思います。
{'participant':'p0000', 'session':'001'}
A: 正解。pythonの文法に詳しくない方のために簡単に説明しておくと、pythonのdictというのは「連想配列」と呼ばれるデータ型の一種で、あるデータとデータの対応関係を保持しておくことが出来ます。例えば'B君'というと'おやつのブラックホール'と返ってくるという感じです。
B: ちょ、その例は何なんですか。
A: この対応関係を、pythonでは{ }で囲った中に対になるデータを : を挟んで並べて記述します。こんな感じ。
{'B君':'おやつのブラックホール'}
B: …反論できないところがくやしいッ!
A: pythonでは文字列を' 'で囲まないといけないことに注意してください。" "で囲むことも出来ます。詳しくは例題1などをご覧ください。複数のデータ対を保持しておきたい場合は、, で区切って並べます。
{'A':'好青年', 'B君':'おやつのブラックホール'}
B: なんというベタなボケを…。Aさん、「そんなわけあるかい!」
A: というわけで、Experiment infoに年齢と自動車運転免許の有無を入力する欄を追加してみましょう。sessionは今回の実験では必要ないことにして削除することにします。さ、B君。模範回答をどうぞ。
B: まったくこの人は…。こんな感じでいいですか?
{'参加者':'', '年齢':'', '運転免許証':''}
A: んんー。良い。実にすばらしいね! B君! こちらの意図をよく理解している。わざとエラーになる解答をしてくれたんだろう?
B: へ? これダメなんですか?
A: マジで、間違えたの?
B: ハイ。
A: …。
B: …。
A: えー。おほん。じゃあ、改めて聞くが、これがエラーになるとしたら何が悪いか想像がつくかね?
B: 日本語を使ってることですかね。Unicodeにするために文字列の前にuをつけないといけません。
A: 何だ、わかってるんじゃないか。じゃあ最初からuを付けろよ。
B: いや。さっきTextコンポーネントをRoutineペインに配置した時に文字コードを自動判別するってAさんが言ってたから。
A: あぁ、なるほど。そういう発想か。納得した。残念ながらここでは明示的にUnicodeにしてやらないといかんのだ。というわけで正解はこう。pythonの文法に不慣れな人は文字列の前にuがついているとUnicode文字列になると覚えておいてください。
{u'参加者':'', u'年齢':'', u'運転免許証':''}
B: 日本語で表示されるってのはいいですねえ。
A: ま、問題点というか注意点も言っておこう。良い事ばかりじゃない。
保存されるデータファイルはUnicodeになるので、 Unicodeに対応していないアプリケーションでデータファイルを開くと当然文字化けする 。
Builderは'participant'という項目がExperiment infoに含まれていると、その値をデータファイル名につける機能がある。 'participant'を削除してしまうとこの機能は無効になる 。
B: わかっている人には当たり前の内容ですね。
A: ふっ、すっかりわかっている人の立場での発言だな。ついでに面白い機能を紹介しておくと、デフォルト値にTrueまたはFalseを指定しておくと、その項目はinfoダイアログでチェックボックスとして表示される。以下のようにExperiment infoに入力して実行してみて欲しい。
{'participant':'', 'age':'20', 'license':False}
B: なるほど。これは便利。
A: さて。いよいよ経過時間の表示の話に進みたいところだが…。すでにもうずいぶん長くなてしまったな。ここで区切るか。
B: あら、一気に済ませるのかと思いましたが。
A: 前回B君に「長すぎる」と言われたばかりだからな。それにしても今までの例題x-yでyの値が5を超えたことはないんだが、今回は確実に5を超えそうだな。次回で終わるとはとても思えない。
B: ほほう。新記録達成予告ですな。
A: 最後に、ある程度pythonに慣れた人向けの便利な機能を紹介しておこう。ツールバーのこのアイコンをクリックすると実験を「コンパイル」することが出来る。C++とかを知ってる人なら「コンパイル」と聞いて大いに興奮するところだろうけど、残念ながらここでいうコンパイルはBuilderで作った実験をpythonスクリプトに変換するだけ。実行する時は普通にpythonインタプリタで実行する。コンパイルと聞いて人が期待するような実行速度面でのメリットは特にない。
B: 興奮って…。理解できない世界だ。速度面でのメリットがないなら意味ないんじゃないですか?
A: 何を言うか。楽しいじゃん。Builderで作った実験がどんなコードになるのか、おお、そこをそういう風に処理するか、考えたヤツ天才だな、でもこっちはこうした方が効率いいんじゃねえの? いっちょ俺がコード書き直してやるか、とか。あれこれ考えてたらもう飯を食べるのも忘れるくらいドキドキするよね!
B: そんな 変態 はAさんだけだと思います。
A: そっかなあ? そういう人たちがいるから私たちが便利に使っている数々のフリーウェアがあるんだと思うんだがなあ。
B: まあそれはそうかも知れませんが…。
A: この機能のおかげで次回扱う「経過時間の表示」を実現する方法があっさりわかった。正直公式ドキュメントだけだったら数日はこの問題にハマったかも知れん。わかりやすいドキュメントの作成も、プログラミング言語の知識を必要としない心理実験アプリケーションの開発も、どっちも難しいやな。そんなわけで、次回へ続く。