例題18-6:続^2・Builderで行こう

A: 長くなってきたのでそろそろ皆さんお忘れかも知れませんが、例題18-3で直接エディタでPsychoPyのごく簡単なスクリプト18-1.py、18-2a.pyを書いて、例題18-4からこれらのスクリプトをPsychoPyのBuilderを使って再現してみるということに挑戦しております。

B: おります。

A: で、例題18-4、18-5を使ってやっと18-1.pyの再現に成功しました。続いてこの例題18-6では18-2a.pyの再現を目指します。

B: 目指します。

A: なんだ、なんなんだB君のそのノリは。

B: いやー、ついに初の例題n-6ですね。今回は気合の入りが違いますね。

A: いや、本来はこれは例題18-3になるべき内容だったんだが。

B: へ? もう例題18-6ですよ?

A: 本来は例題18-1と18-2の内容を1回で済ませて、例題18-3の内容を1回、そして例題18-4から今回までの内容で1回にまとめるつもりだった。

B: ええー、そんなの滅茶苦茶でしょ。

A: うむ。行き当たりばったりがモットーのこの講座だが今回は見通しが甘すぎた。反省している。

B: ま、でも今回で終わるんでしょう?

A: そう願っておいてくれ。というわけで今回のお題、18-2a.pyの再現。

  1. 画面に「お腹すいたなあ」と表示する
  2. 参加者がスペースキーを押すのを待つ
  3. 画面に「あ、財布忘れた」と表示する
  4. 参加者がスペースキーを押すのを待つ
  5. 画面に「しょんぼり」と表示する
  6. 参加者がスペースキーを押すのを待つ
  7. 画面に「再生してください」と表示する
  8. 5秒間経過するのを待って終了する

B: こうやって改めて書くとシュールですね。いきなり「再生してください」ってなんなんだ。

A: もうすでにお分かりのことと思うが、1から6は1と2、3と4、5と6という似たような作業を3回繰り返している。そこで共通部分をくくって以下のように書くことが出来るだろう。

  1. 以下の作業を○○に「お腹すいたなあ」、「あ、財布忘れた」、「しょんぼり」をこの順番に代入しながら繰り返す

    1. 画面に○○と表示する
    2. 参加者がスペースキーを押すのを待つ
  2. 画面に「再生してください」と表示する

  3. 5秒間経過するのを待って終了する

B: ふむふむ。

A: このうち2と3はひとつのRoutineとして実現することが出来る、というのが例題18-4、18-5でやってきたことだ。そしてPsychoPyではiとiiもまたひとつのRoutineとして実現することが出来る。まずiとiiを実現するRoutineを作成して、それからそのRoutineを繰り返すようにする方法をこの例題18-6で学ぶ。

B: う。二つの項目が出てきた時点で次回持ち越しになる予感…。

A: んでは、さっそく始めてみようか。気分を改めて新たに実験を作ることにする。新たな実験を作成するにはメニューバーの一番左端のボタンを押すか、PsychoPyを立ち上げなおすかすればいい。

B: もうさっき一度終了させちゃったので立ち上げなおしました。

A: さて、「1の1」と「1の2」を実現するRoutineを作成するが…。ここでPsychoPyをいったん離れてExcelなりLibreOffice Calcを起動する。

B: LibreOffice?

A: 知らないかな。 http://ja.libreoffice.org/ で配布されているWindows、MacOS X、LinuxなどいろんなOSで動くフリーのOffice suiteで、CalcはMicrosoft OfficeのExcelにあたる。Ubuntuなんかだと標準でインストールされている。私ゃ最近はデスクワーク用PC以外はWinでもLinuxでも全部LibreOfficeだ。

B: へえ。昔のOpenOfficeみたいなもんですか。ちょっと試してみたけどぼくのPCでは重すぎてダメでした。

A: OpenOffice.Org( http://www.openoffice.org/ja/ )はいまでもあるぞ。LibreOfficeはOpenOffice.Orgから分かれて出来たもので…。そうだな、よかったら一度sun、oracle、OpenOffice、LibreOfficeあたりのキーワードで検索してLibreOfficeが作られた経緯でも調べてみるといいよ。オープンソフトウェアと企業の関係とか、オープンソフトウェアのライセンスの種類とか、いろいろ考えさせられるものがある。

B: ふーん。ちょっと興味ありますけどAさん、脱線しちゃいけませんよ。

A: わかっとるわい。ここではExcelの画面で説明するが、こんなふうにA列の1行目にsentenceと入れて、その下に表示させたい3つの文を入力する。 1行目がラベルで2行目以降がデータ というわけだね。 ラベルはpythonの変数名として使用できるものでなければいけない ことに注意。入力したら適当な名前で…。そうだな、stim.xlsxという名前で保存しておこうか。

../_images/18-6-01.png

B: .xlsxじゃないとダメなんですか? .xlsは?

A: ダメ。.xlsxが初めて導入されたExcel 2007はリボンUIとかデータファイルの形式変更で散々叩かれたが、実は.xlsxになってExcelのファイルを読み書きするフリーソフトが作りやすくなったんだ。PsychoPyのインストールの時にopenpyxlというパッケージをインストールしたが、これはpythonから.xlsxや.xlsmを読めるようにするものだ。

B: へえ。何が変わったのかなんて考えたことありませんでした。

A: .xlsx形式はイヤだ、Excelなんて持っていないという場合はCSV(カンマ区切りのテキスト)も使える。CSVファイルならテキストエディタでも作れる。今回は1列しかないので単にこんな風に1行ずつ書けばいい。この場合のファイル名はsitm.csvにしとけばいいかな?

../_images/18-6-02.png

B: この程度ならテキストエディタの方が楽ですね。

A: 名前がないとこの後話しづらいので、このファイルを 条件ファイル と呼ぶことにしよう。 条件ファイルをテキストエディタでCSVを作る場合、一つ気を付けてほしいのは PsychoPyは拡張子が.csvじゃないとCSVファイルを読み込んでくれない ということだ。Windowsを使っていて拡張子を表示しない設定にしている人は特に注意が必要で、その辺の操作に自信がない人はExcelやCalcを使って.xlsxか.csvを作成する方がいいかも知れない。

B: 中身を自動判別してくれないんですか?

A: んー。してくれたらありがたいけど、そんなことよりもっと他に改善してほしいことがたくさんあるなあ。使い込んできたらいろいろと細かい不具合があるのもわかってきたし、まずはちゃんと動くようになって欲しい。

B: え、そうなんですか。

A: 不具合の発生条件をまだ把握しきれていないので、もうちょっと把握してから公開するなり修正するなりしたいと思う。ま、その話は今は置いといてBuilderに戻ろう。今まで全然触れてこなかったFlowペインを見てほしい。trialというRoutineだけが表示されている。このRoutineを繰り返すループをこれから追加する。最初だから丁寧にいくぞ。マウスカーソルを含むキャプチャが面倒くさかったからマウスカーソルが写っていないけどそこは想像で補ってくれ。

B: 丁寧なんだか手抜きなんだか…

../_images/18-6-03.png

A: まずLoopを挿入する。画面上部のメニューの[Experiment]から[Insert Loop in Flow]を選ぶか、FlowペインのInsertLoopをクリックする。

../_images/18-6-04.png

A: そうすると下図のようにFlowの中でLoopの始点または終点を挿入できる位置に黒丸が表示される。今回はtrialの前か後ろの2か所しか挿入できる場所がないのでどちらを選択してもいい。間違えて挿入しようとしてしまった場合はCancel Insertを選ぶ。

../_images/18-6-05.png

B: 「2か所しか挿入できる場所がないのでどちらを選択してもいい」というのがよくわかりませんが…

A: Loopには必ず始点と終点があるんだから、2か所しか挿入できる場所がなかったら2か所のうち前が始点で後ろがになるに決まってるだろ。

B: あ、そうか。

A: Loopの始点をクリックすると今度は終点を指定するための黒丸が出るが、指定できる場所は一か所しかないのでそこを指定する。そうすると次のようなダイアログが出現する。

../_images/18-6-06.png

A: ここのダイアログの項目は以下の通り。ただし、 loopTypeでstaircaseを選ぶと項目が全く変わってしまう んだが今回はそれについては説明しない。ちょっと説明しだすとキリがない。

name Flow内でLoopを識別するための名前を指定する。Pythonの変数名として使える文字列しか使用できない。例えば日本語は使用できない。
loopType 繰り返しの種類を指定する。 random, sequential, fullRandom, staircase, interleaved staircases が選べる。staircaseを選択するとダイアログの選択項目が完全に切り替わる。
random seed 乱数のシードを指定する。
nReps 繰り返し回数を指定する。
conditionsFile 条件ファイルを指定する。

B: んー。loopTypeというのがよくわからないかなあ。

A: 簡単に説明するとこんな感じかな。

random 条件ファイルに書かれている条件を無作為な順番で繰り返す。無作為化の範囲は1回のLoop内。
sequential 条件ファイルに書かれている条件をファイルに書かれている順番で繰り返す。
fullRandom 条件ファイルに書かれている条件を無作為な順番で繰り返す。無作為化の範囲はLoop全体。

B: staircaseとinterleaved staircasesは?

A: 聞くな。話すと長ーーーくなるのでまずはこの3種類に話を絞る。ここでわかりにくいのはrandomとfullRandomの違い。言葉で説明するより図で見てもらった方がわかりやすいだろう。

../_images/18-6-07.png

B: ははあ、なるほど。

A: さて、条件ファイルを指定すると下図のようにnRepsの下に読み込まれた条件の概要が表示される。3conditions, 1 parametersとあるが、元の条件ファイルでconditionsが行数、paremetersが列数に一致するはず。ここが一致していなかったらちゃんと読み込まれていないので条件ファイルの内容を確認した方がいい。で、続く[ ]の中には読み込んだ列ラベルが表示されている。

B: ちゃんと読み込めているみたいですね。

../_images/18-6-08.png

A: あと、nRepは「読み込んだ条件ファイルの内容を何回繰り返すか」を指定するので、18-2a.pyを再現するという目的からはnRrep=1とするのが正しい。「文を表示してキー押しを待つという作業を3回繰り返すんだからnRep=3」 ではない ことに注意。nameは何でも良いだろう。seedは空欄でいい。[OK]をクリックすると下図のようにLoopが挿入される。1x3 sequentialというのはnRepが1、条件数が3で繰り返しのタイプがsequentialだということを示している。

../_images/18-6-09.png

B: おお、何だか知らないけど格好良くなった。

A: Loopのパラメータを修正したい時にはこの1x3 sequentialと書いてある部分をクリックするとさっきのダイアログが開く。

B: ちょっとわかりにくいですね。

A: さて、Loopは完成したのでRoutineを作成しよう。まずComponetペインのTextコンポーネントをクリックする。そろそろお馴染みになってきたダイアログだが、今回のポイントはText欄。 条件ファイルの1行目に記入したラベルが変数名として参照できる ので、$sentenceと書けばsentenceというラベルを付けた列の値を参照できる。あと、右側のプルダウンメニューから set every repeatを選択する 。経過時刻のようにフレーム毎に設定する必要はなく、Routineを実行する毎に値が変更されればそれでいいからだ。

../_images/18-6-10.png

B: set every frameにしても動くんですか?

A: 動くことは動くが…。無駄に値を更新するコードが挿入されてしまうのでやめておいた方がいい。

B: 了解です。ええと、じゃあset every repeatに戻して…と。

A: あともう一つのポイント。今回はキーボードのスペースキーを押すまで文字列を表示し続けなければならない。このように 何秒後に終わるかわからない場合はStopの欄を空欄にしておく

../_images/18-6-11.png

B: ははぁ、そういうふうに指定するんですか。

A: 続いてキーボードのキー押し検出を追加しよう。ComponentペインにあるKeyboardコンポーネントをクリックする。

../_images/18-6-12.png

B: おお、やっと新しいコンポーネントが出てきましたね。

A: Keyboardコンポーネントの設定画面は以下の通り。設定項目も表にしておこう。

../_images/18-6-13.png
Name, Start, Stop Textコンポーネントと同じなので省略
Force end of Routine この項目がチェックされているとAllowed keysに挙げられたキーのいずれかが押されるとRoutineが直ちに終了する。
Allowed keys キー押しとして検出するキーを列挙する。
Store 実験結果ファイルに保存するキーを指定する。Force end of Routineがチェックされている場合はlast, first, all keysは同じ。
last : 最後のキー押しを記録する。
first : 最初のキー押しを記録する。
all keys : 全てのキー押しを記録する。
nothing : 記録しない。
Store correct
Correct answer
この項目がチェックされていると、正解か否かを記録する。チェックされるとCorrect answerという欄が出現するのでそこへ正解となるキーを入力しておく。
Discard previous この項目をチェックすると、キー押し検出を開始する前にキー押しイベントをすべて消去する。キー押しイベントはgetKeys()等を実行するまで蓄積されるので、もしこの項目がチェックされていない状態で参加者が反応キーをキー押し検出開始前に押してしまうと、キー押し検出が開始された直後に「キーが押された」というイベントが検出されてしまう。 特別な理由がない限り、この項目はチェックしておくべきである。

B: 最後のDiscard previousってのが何のことかピンときませんでしたが、読んだら納得しました。なるほど。でもこの項目をチェックしない方がいい実験ってあるのかな?

A: さあ? フライングはそれはそれでエラーとして記録したい場合とかかな?

B: あとStoreのfirstとかlastとかいうのもよくわかりませんが、なんでそんなものが必要なんでしょう?

A: この項目はForce end of Routineとセットで考えないといけない。Force end of Routineがチェックされていれば、nothing以外はすべて同じになる。 Force end of RoutineがチェックされていなければkeyboardコンポーネントがStopする前に複数回キーが押される可能性がある わけだから、first、last、all keysの違いが出てくる。

B: ふむふむ。

A: テキトーな例を考えるとだな。参加者がキーを押してもRoutineは終了させたくないが必ず最初のキー押しを反応としたいのならfirst、2秒間の間ならキーの押し直しを許可して最終的に押されたキーを反応としたいのならlast、そもそも複数回押しがあったかどうか、どのキーからどのキーへ押しなおしたのかとかを詳細に分析したいのならall keys。

B: うーん、よくできているなあ。

A: あと、Store correctだが…。これは18-2a.pyを再現するという今の目的には関係ないのでとりあえずパスしておきたい。

B: ええー、これが一番興味あったのに。

A: というわけで、さっきの図のようにStopを空欄、Allowed keysを’space’のみにすれば18-2a.pyの再現が出来る。Force end of Routineは最初からチェックされているはず。確認したら[OK]して。

B: OKしました。

A: さて、ここまでの作業が済めばRoutineペインは以下の図のような表示になっているはず。Timelineの青いバーがRoutineペインの右端へはみ出しているはずだ。Stopが空欄になっていて、何らかの条件が成立しない限りずっとStopしない場合はこのように表示される。では走らせてみよう。

../_images/18-6-14.png

B: じゃ、いきますよ。それっ。

A: …。エラーメッセージが出たな。

B: あれっ? sentenceが定義されてないって?

../_images/18-6-15.png

A: あー。さっそくやっちまったな。B君、TextコンポーネントのText欄をちゃんとset every repeatにしたかね?

B: えっ、僕がそんなつまらないミスを…

A: …。

B: …していました。constantになっていました。がっくし。

A: さっきset every frameにしたらどうなるとかいう話をしていた時にしゃべりながらいじってたから間違えてconstantにしてしまったんだろう。前回も強調した通り set every repeatやset every frameにし忘れるのはよくあるミスだが、その時に出てくるエラーメッセージが今回のように不親切で、読んでも原因が非常にわかりにくい場合がある 。Loopの設定をしたダイアログでちゃんと条件ファイルの内容を読み込めているように表示されているのにこのようなエラーが出てきたときは、set every repeatやset every frameの設定がちゃんとされているか確認しよう。いやB君、なかなか良いミスをしてくれたね。

B: そりゃー作者に都合よくボケるのが僕の役割ですからね。

A: ん? なにか?

B: あ、いや別に。

A: さて、今度こそうまくいくはず。実行してみて。

B: ばっちりですね。スペースキーを押すと次の文に進みます。

../_images/18-6-16.png

A: あともう一息だ。最後に「再生してください」を5秒間表示するRoutineを作成する。このRoutineの中身は例題18-4、18-5で作ってきた「5秒待ちます」のメッセージが「再生してください」に変わるだけなので、例題18-4、18-5をクリアした人なら独力で出来るはず。だからRoutineの中身は復習を兼ねて読者の皆さんに挑戦してもらうとして、新たにRoutineを作成してFlowに組み込むところだけ解説しよう。Routineを新たに作成するには、上のメニューの[Experiment]から[New Routine]を選択する。もしくは下のFlowペインでInsertRoutineを選択する。ここでは後者の方法を画像入りでていねいに見ていこう。まずFlowペインのInsertRoutineを選択する。

../_images/18-6-17.png

A: 挿入するRoutineがリストアップされる。ここにtrialという項目があるのは、一連の実験の中で同じRoutineを条件ファイルを変えて何度も使用したい場合などに、わざわざRoutineを作り直さなくても同一のRoutineを複数回Flowに並べられるようにするためだ。

../_images/18-6-18.png

B: ほうほう、なるほど。

A: ここでは新たなRoutineを作成して追加するので(new)を選ぶ。すると新しいRoutineの名前を聞かれるので、名前を入力する。ここでは実験参加者に再生してもらう場面なのでrecallとでもしておこうか。

../_images/18-6-19.png

A: すると続いてRoutineをFlowのどの場所に挿入するのかを聞いてくる。黒丸の位置に挿入されるので、マウスを使って適切な場所を選んでクリックする。今回はtrialsのLoopが終わった後に1回実行するので、Loopの後ろのこの位置に挿入する。

../_images/18-6-20.png

B: なるほど。

A: で、これが挿入が完了した状態。当然作成したばかりのrecall Routineは空っぽなので、ここに5秒間「再生してください」と表示するRoutineをぜひ皆さんで完成させてほしい。念のため、完成させたものを置いておくのでどうしてもわからない場合はこちらをどうぞ。→ 18-4.zip

../_images/18-6-21.png

B: あのー、Aさん。

A: ん? なんだ?

B: 間違えて変な場所に挿入しちゃったんですが…。

A: ああ、そういう場合は間違えて挿入したRoutineの上でマウスを右クリックしてremoveを選べばよい。

../_images/18-6-22.png

A: removeはRoutineだけじゃなくてLoopに対しても出来るし、Routineペイン内のコンポーネントに対しても出来る。Routine内ではremoveの他にも並び替えも出来る。

../_images/18-6-23.png

B: ん? 並び替えってなにか意味があるんですか?

A: 大ありだ。Routineペインで 上から下へ、並んでいる順番に実行される 。複数の視覚刺激が重なっているような画面を描画する時に、どちらがどちらの前に来るかは非常に重要なのは言うまでもない。手前に来てほしいものを下の方へ並べればよい。ソースをコンパイルしてみるとkeyboardコンポーネントなどもやはり上から下へ実行されるようなので、並べ方を工夫すればいろいろ面白いことが出来るかも知れない。ぐふふっ。

B: な、なんですか最後の気持ち悪いのは。

A: おっと、これは失礼。とにかく、これで18-2a.pyを再現するという目的は無事達成した。次回に持ち越さなかったぞ。

B: ぱちぱちぱちぱちー

A: いや、それにしても長かったね。例題18-4から3回がかりか。

B: 今回は初めての例題n-6っていうのに加えて図が23枚も。これも新記録達成です。

A: いやはや。疲れたー。

B: これで例題18もお開きですかね。お疲れさまでした。

A: いや、例題18はまだ終わらないぞ。

B: えっ?!

A: B君も言っていただろう。KeyboardコンポーネントのStore correct。これがKeyboardコンポーネントで一番知りたいって。これを取り上げずに済ますわけにはいくまい。

B: えーっと、それは僕もおつきあいしないといけないのでしょうか。

A: 当然である。

B: まだ帰省から戻ってきたばかりで今日はゆっくり過ごしたかったのにー。

A: 安心しろ。次回は短めの予定で、この話題が済んだら本当に例題18は終了だ。

B: 悪びれず「見通しが甘すぎた。反省している」とかしれっと言っちゃう人のそんなセリフ信用できませんよー。

A: というわけで、例題18は記録を更新しつつまだ続きます。また次回。