8. グラフィカルインターフェースを活用しよう¶
8.1. この章の実験の概要¶
第7章 ではキーボードを用いてプローブ刺激の長さを調節しました。しかし、実際に実行してみた方は「カーソルキーを何度もカチカチ押すのは面倒くさい」と思われたのではないでしょうか。 BuilderのKeyboardコンポーネントでは、基本的に「キーを押した」か「(既に押してある)キーを放した」のいずれかのイベントしか検出しません。ですから、「押しっぱなしにしていたらその間伸び縮みする」という動作を実現することが難しいのです。まあCodeコンポーネントを使うと可能ですので、Codeコンポーネントの使い方を極めるという中級から上級者向けの練習問題としては面白そうですが、そんな難しいことをしなくてもぱぱっと実現できてしまった方がいいに決まっています。 残念ながら現在のBuilder(執筆時点で2024.2.5)ではキーボードを使う限りどうしても難しくなってしまうのですが、マウスを使うとキーボードよりはずっと簡単に実現可能です。 本章では、まず 第7章 の実験をマウスを使って操作するように改造します。 その後、マウスの使い方をもう少し覚えようということで 第6章 章の実験にも少し改造を加えます。 それぞれの章の実験を完成させたところから解説を始めますのでご注意ください。
8.3. ミューラー・リヤー錯視の実験をマウスで操作できるようにしよう¶
第7章 の作業を最後までおこなった状態(練習問題は除く)から作業する前提で手順を解説します。
- 実験設定ダイアログ
「スクリーン」タブの [マウスカーソルを表示] をチェックする。
- trialルーチン
配置済みのKeyboardコンポーネントを削除する。
- Buttonコンポーネントを1つ配置し、以下のように設定する。
「基本」タブの [名前] を
buttonOK
にして、 [開始] を「時刻(秒)」の0.5
にする。 [Routineを終了] がチェックされていることを確認し、 [ボタンのテキスト] をOK
に変更する。「レイアウト」タブの [サイズ [w, h] $] を
(0.1, 0.04)
に、 [位置 [x, y] $] を(0, -0.3)
にする。「書式」タブの [フォント] を
Yu Gothic
(Windowsの場合)、Hiragino Sans
(MacOSの場合)など、各自のPCで使用できる日本語フォントにする。 [文字の高さ] を0.03
にする。ルーチンの一番上になるように並び替える。buttonOKが一番上にあり、そのすぐ下がCodeコンポーネントになっていることを確認する。
- buttonOKをコピーし、buttonOKのアイコンを右クリックしてメニューの「下に貼り付け(buttonOK)」を選択して
buttonLonger
の名前で貼り付ける。 ルーチンペイン上で一番上にbuttonOKがあり、そのすぐ下にbuttonLonger、さらにその下にcodeになっていることを確認 してから以下のように設定する。 「基本」タブの [Routineを終了] のチェックを外す。 [ボタンのテキスト] に
長く
と入力し、 [クリック毎に1回実行] がチェックされていることを確認する。基本」タブの [コールバック関数] に
probeLen = min(probeLen+0.005, 0.35)
と入力する。「レイアウト」タブの [位置 [x, y] $] を
(0.15, -0.3)
にする。
- buttonOKをコピーし、buttonOKのアイコンを右クリックしてメニューの「下に貼り付け(buttonOK)」を選択して
- buttonLongerをコピーし、 buttonLongerのアイコンを右クリックしてメニューの「下に貼り付け(buttonLonger)」を選択して
buttonLonger_2
の名前で貼り付けてから以下のように設定する。 「基本」タブの [ボタンのテキスト] に
長く(長押し)
と入力し、 [クリック毎に1回実行] のチェックを外す。「レイアウト」タブの [サイズ [w, h] $] を
(0.2, 0.04)
に、 [位置 [x, y] $] を(0.35, -0.3)
にする。
- buttonLongerをコピーし、 buttonLongerのアイコンを右クリックしてメニューの「下に貼り付け(buttonLonger)」を選択して
- buttonLongerをコピーし、 buttonLonger_2のアイコンを右クリックしてメニューの「下に貼り付け(buttonLonger)」を選択して
buttonShorter
の名前で貼り付けてから以下のように設定する。 「基本」タブの [ボタンのテキスト] に
短く
と入力する。基本」タブの [コールバック関数] に
probeLen = max(probeLen-0.005, 0.05)
と入力する。「レイアウト」タブの [位置 [x, y] $] を
(-0.15, -0.3)
にする。
- buttonLongerをコピーし、 buttonLonger_2のアイコンを右クリックしてメニューの「下に貼り付け(buttonLonger)」を選択して
- buttonLonger_2をコピーし、 buttonShorterのアイコンを右クリックしてメニューの「下に貼り付け(buttonLonger_2)」を選択して
buttonShorter_2
の名前で貼り付けてから以下のように設定する。 「基本」タブの [ボタンのテキスト] に
短く(長押し)
と入力する。基本」タブの [コールバック関数] に
probeLen = max(probeLen-0.005, 0.05)
と入力する。「レイアウト」タブの [位置 [x, y] $] を
(-0.35, -0.3)
にする。
- buttonLonger_2をコピーし、 buttonShorterのアイコンを右クリックしてメニューの「下に貼り付け(buttonLonger_2)」を選択して
配置済みのCodeコンポーネントの [フレーム毎] に入力してあるコードをすべて削除する。
ここまで作業したら、trialルーチンには上からButtonコンポーネントが5つ並び、続いてCodeコンポーネントがひとつ、さらに続いてPolygonコンポーネントが6つ並んでいるはずです。作業手順上、各Buttonコンポーネントをどの位置に貼り付けるか指定しましたが、5つのButtonコンポーネント間の順序は異なっていても動作には影響ありません。
実行すると、 図8.3 のように刺激とプローブの下に5つのボタンが表示されます。「長く(長押し)」と「短く(長押し)」にマウスカーソルを合わせてマウスの左ボタンを押しっぱなしにすると、長さ0.05から0.35の範囲内でプローブの長さが変化し続けることを確認してください。また、「長く」と「短く」のボタンはKeyboardコンポーネントの時のように、マウスのボタンを押したときに1回だけ長さが変化することも確認してください。 [クリック毎に1回実行] をチェックする、しないの違いがおわかりいただけると思います。 「OK」と書かれたボタンをクリックすると次の試行へ進みます。

図8.3 マウスでプローブの長さを調節する。¶
[コールバック関数] に入力した probeLen = min(probeLen+0.005, 0.35) と言う式は少し補足が必要でしょうか。 min( )は 表5.2 で紹介した関数で、引数の中から最小の値を返します。ここではprobeLen+0.005と0.35を引数として与えていますので、probeLen+0.005が0.35より小さければその値が、0.35より大きければ0.35を返します。これによって、「長さを0.005増加させるが0.35を越えないようにする」という処理が1行で実現できています。 同様に、probeLen = max(probeLen-0.005, 0.05)は「長さを0.005減少させるが0.05未満にならないようにする」処理を実現しています。 これは「 5.7:練習問題:パラメータが適切な範囲を超えないようにしよう 」のヒントにもなっていますので、わからなかった方はこのテクニックを念頭において改めて「 5.7:練習問題:パラメータが適切な範囲を超えないようにしよう 」を考えてみてください。
以上のコードにより、Codeコンポーネントの [フレーム毎] で行っていた処理はすべて実現できてしまっているので、 [フレーム毎] のコードはすべて削除しました。しかし、 [Routine開始時] と [Routine終了時] の処理がまだ必要なのでCodeコンポーネント自体は残さないといけません。 Variableコンポーネントを使用すれば完全にCodeコンポーネントを削除してしまうことができますが、それは練習問題としておきましょう。Codeコンポーネントでは probeLenに加えてtheseKeysも初期化しなければいけないこと、theseKeysの値は実験記録ファイルに出力する必要がないことの2点がポイントとなるでしょう。
8.4. SliderコンポーネントとFormコンポーネント¶
本章をButtonコンポーネントの話だけで終えてしまうのも物足りないので、マウスと相性がよいSliderコンポーネントとFormコンポーネントを紹介しておきましょう。いずれもコンポーネントペインの「反応」カテゴリにあります。

図8.4 SliderコンポーネントとFormコンポーネント¶
Sliderコンポーネントは、定規のような「尺度」をスクリーン上に提示して、尺度上の位置を参加者に選択させることによって反応を記録するためのコンポーネントです。心理学実験ではこの種の反応を求める課題は少なくないので、覚えておくときっと役に立つはずです。 表8.2 に主なプロパティを示します。 [Routineを終了] やフォントの設定に関することなどはButtonコンポーネントと同様なので省略してあります。
データ属性, 概要 |
|
---|---|
[スタイル] |
尺度の見た目を決定します。slider, rating, radio, scrollbar, choiceのいずれかを選択します。slider, rating, scrollbarは離散値と連続値の両方の記録に使用できますが、radio, choiceは整数個の選択肢のなかからの選択にのみ使用できます。 |
[目盛 $] |
尺度の目盛位置をカンマ区切りの数値で指定します。 [スタイル] がradioの場合は設定できません。 |
[ラベル $] |
目盛につけるラベルをカンマ区切り指定します。 [スタイル] がradioの場合は必ず指定しないといけませんが、その他の場合は省略できます(ラベルは表示されません)。 [目盛 $] の要素数と [ラベル $] の要素数が異なる場合、 [ラベル $] が2個なら尺度の両端のラベルとなります。 [ラベル $] が3個以上で [目盛 $] の個数と一致しない場合、エラーになりませんがそのような設定は避けるべきでしょう。 |
[精度 $] |
[スタイル] がslider, rating, scrollbarのとき、マーカー位置の最小間隔を指定します。例えば [目盛 $] が1, 2, 3, 4, 5で [精度 $] が1の場合、マーカー位置は1刻みでしか置くことができないので五段階の尺度となります。0を指定すると実験の実験環境における最小間隔となり、実質的に連続値の尺度となります。radioではこの項目は無効になるほか、choiceでは値の設定はできますが無視されます(2024.2.5で確認)。 |
[初期値 $] |
Sliderコンポーネントが開始された時のマーカーの位置を指定します。空欄の場合、マーカーがどこにも置かれていない状態で開始されます。 |
[サイズ [w, h] $] |
他のコンポーネントと同様ですが、高さよりも幅が大きければ横向き、幅よりも高さが大きければ縦向きの尺度が描かれます。 |
[回転角度 $] |
他のコンポーネントと同様ですが、表示が乱れることが多いため0度以外での使用はお勧めしません。縦にする場合は [サイズ [w, h] $] で指定してください。 |
[反転] |
通常、ラベルは尺度の下または左に表示されますが、この項目がチェックされていると下または右に表示されます。 |
[履歴を記録] |
最終的なマーカー位置だけでなく、それまでのマーカー位置の変更履歴(位置と時刻)も記録します。 [Routineを終了] がチェックされている場合は意味を持ちません。 |
[スタイル] は尺度の見た目を決めるもので、 表8.2 の中から選びます。さらに [目盛 $] と [ラベル $] で細かな設定をしていきますが、これらのパラメータと [スタイル] の関係が複雑なうえ、PsychoPyのバージョンアップの過程でいくつか仕様変更もおこなわれており、すべてを解説するのは大変です。多くの方にとってはそんな踏み込んだ話よりもお勧めの使用パターンを紹介した方が有益だと思いますので、以下にいくつか示します。

図8.5 Sliderコンポーネントのスタイル¶
カテゴリカルな尺度ではradioを使うのが良いと思います。radioでは [ラベル $] を省略すると実行時にエラーになります(2024.2.5で確認)。
離散的な順序尺度ではratingを使うのが良いと思います。ratingでは [目盛 $] を1, 2, 3, 4, 5のように間隔1の整数にして、 [精度 $] を1にすれば目盛の位置しかマーカーを置けない尺度になります。 [ラベル $] は両端の2個を指定するか、 [目盛 $] の要素数と一致する個数を指定するかをお勧めします。ラベルの位置が気に入らない場合は [ラベル $] を空欄にして、Textコンポーネントを使って自分でラベルを配置するとよいでしょう。
連続的な値の尺度ではrating, slider, scrollbarのいずれかが良いと思います。 [精度 $] を0にすれば実験の実行環境で最も細かな位置調整ができますが、 [目盛 $] を0, 100として [精度 $] を1としたり、 [目盛 $] を0, 1として [精度 $] を0.02とするなど、実験の目的に応じた精度を積極的に指定するのもよいでしょう。
「レイアウト」タブでは他のコンポーネントと同様に尺度のサイズや位置、回転角度などを指定できますが、 ラベルの表示などがおかしくなることが多いのでSlider、Sliderコンポーネントを回転させるのはお勧めしません 。 初期値ではSliderコンポーネントは横向きの尺度を描画しますが、表8.2 のように、 [サイズ [w, h] $] で高さの方が幅よりも長くなるように値を設定すると縦向きの尺度を描画します。ほとんどの用途に置いて、横向きまたは縦向きの尺度を描画できれば十分でしょう。

図8.6 [サイズ [w, h] $] で高さの方が幅より大きな値にすると縦向きの尺度になる¶
実験の実行中にSliderコンポーネントでマーカーが置かれている位置の値を得る必要がある時には、ratingいうデータ属性にアクセスします。例えばresp_sliderという名前のSliderコンポーネントがあるとき、
resp_slider.rating
と書けば現在のマーカー位置の値が得られます。
ratingやslider、scrollbarのように連続量を扱えるスタイルでは、 [精度 $] で整数値しかとらないように制限していても浮動小数点数値(float型)となります。
radioでは、選択されている項目が [ラベル $] で数値として与えられているなら数値、文字列として与えられているなら文字列となります。
あまり現実的な実験ではない状況でしょうが、 [ラベル $] の要素がそれぞれ違うデータ型の場合、そのラベルのデータ型がそのまま反映されます。
具体的に言うと、 [ラベル $] に1, 2.0, '3'と定義してあるなら、1を選択すればint型、2.0を選択すればfloat型、'3'を選択すればstr型の値が得られます。
注意が必要なのは、 参加者がSlider上をクリックする前はratingの値はNoneである という点です。 [初期値 $] でマーカーの位置を指定していて既にマーカーが表示されていても、参加者がまだクリックしていなければNoneですので間違えないようにしてください。
現在どの位置にマーカーが表示されているかを知るにはmarkerPosという属性を使います。例えばresp_sliderという名前のSliderコンポーネントがあって、3.2の位置にマーカーがあるなら
resp_slider.markerPos
の値は3.2となります。
markerPosに値を代入すれば、コードでマーカー位置を変更することも可能です。以下のコードをCodeコンポーネントを使って実行すると、マーカーの位置を0.0へ移動させることができます。
resp_slider.markerPos = 0.0
注意が必要なのはSliderコンポーネントの [スタイル] がradioのときで、markerPosでは最初のラベルを0.0、2番目のラベルを1.0、…という具合に浮動小数点数で「マーカーの位置」を返してきます。 [目盛 $] が0からN-1(Nはラベルの個数)の整数を並べたもの、 [精度 $] が1に設定されていると考えれば他のスタイルと統一的に扱えます。 [スタイル] がradioの時に [初期値 $] を設定する場合も同様に考えて、最初のラベルなら0、2番目のラベルなら1という具合に指定してください。 なぜ最初のラベルを1ではなく0として数えるのかは、おそらくPythonにおけるシーケンスの位置の数え方と密接な関係があります。 第9章 で説明する予定です。
この「参加者がまだクリックしていなければデータ属性ratingの値がNoneである」ということをうまく利用すると、スクリーン上に [Routineを終了] のチェックを外したSliderコンポーネントを複数配置して「スクリーン上のすべてのSliderコンポーネントに反応すればルーチンを終了する」といった動作をCodeコンポーネントを使って実現することが可能です(「8.6.1:同一ルーチンに配置されている複数のSliderコンポーネントが回答済みか判定する 」参照)。 しかし、コードを書くのが少々面倒ですし、なにより複数のSliderコンポーネントをラベルのことまで考慮しながらサイズと位置を調整するのはなかなか骨が折れる作業です。 こういう時に非常に便利なコンポーネントがFormコンポーネントです。 表8.3 に主なプロパティを示します。
データ属性, 概要 |
|
---|---|
[項目] |
Formコンポーネントで管理する尺度などのパラメータを定義したxlsxファイルやCSVファイルを指定します。 |
[無作為化] |
項目をxlsxファイル等で定義したとおりの順序で配置するか、実行の度に無作為に並び替えるかを選択します。 |
[データフォーマット] |
実験記録ファイルに結果を出力する際に、各Sliderの値を行方向に出力するか列方向に出力するかを選択します。 |
[項目間の余白] |
項目間の余白を指定します。CSSなどに詳しい方はtableのpaddingに対応すると考えてください。 |
[スタイル] |
配色をdark, light, カスタム...の中から選択します。カスタム...にした場合、「外観」タブの色に関する項目が設定可能になります。 |
Formコンポーネントを使いこなす鍵は [項目] に指定する設定ファイルです。具体例を見てみましょう。 図8.7 上は設定ファイルの例です。条件ファイルと同様、1行目はパラメータ名で、2行目以降は1行につきひとつの見出しや尺度などの項目に対応しています。 この設定ファイルを実際にFormコンポーネントの [項目] に指定した実行した結果が 図8.7 下です。 Sliderコンポーネントで作成できるような尺度が整然と並んで表示されています。もちろん、マウスを使ってそれぞれの項目を操作することが可能です。 右端にある縦長の長方形はスクロールバーです。 項目数が多くてFormコンポーネントの [サイズ [w, h] $] に入りきらなかった場合、このように自動的にスクロールバーが出現して上下にスクロールさせることができます。 Sliderコンポーネントを複数並べて自分で位置調整するのとは比べ物にならない簡単さです。

図8.7 上:項目ファイルの内容。下:Formコンポーネントで実行した例。¶
設定ファイルでは、 図8.7 で示したものだけでなくさまざまなパラメータを指定することができます(表8.4)。 typeでSliderコンポーネントのrating, slider, radio, choice(ただしFormコンポーネントではradioと同じ)を選べるほか、headingで見出し行、descriptionで教示文を配置することもできます。 Textコンポーネントの [文字列] を条件ファイルで変更するときと同様、複数行のテキストを入力することも可能です。一方、Textコンポーネントとは異なり、長い文字列を入力すると日本語であっても表示範囲に収まるように自動的に改行されます。ただし、改行位置の調整があまりスマートではないことや、英単語の途中で改行するときのようにハイフンが入ってしまったりしますので、手作業で改行した方がよい出力が得られるでしょう。 xlsx形式で設定ファイルを作成する場合、セル内で改行すればその通りに反映されますが、CSV形式で設定ファイルをする場合は、 図8.7 の「ratingの例」のtickLabelsのように改行する位置に\nと書いて改行を表すことができます(「6.9.2:改行文字を使った複数行の文字列の表現(上級) 」参照)。
index |
項目の順序を整数で指定します。省略すると自動的に番号が割り振られます。刺激の描画には影響しませんが、 [無作為化] した時にデータファイルの出力を項目順に並び替えるときに役に立ちます。 |
itemText |
表示したい文を指定します。 |
type |
項目の種類を指定します。rating,slider,radioはSliderコンポーネントと同じです。choiceも指定できますがradioと同じになります(2024.2.5で確認)。heading,descriptionは教示などの文だけを表示したいときに使います(headingはやや大き目でボールド体になる)。heading, descriptionを選んだ場合はoptions, ticks, ticklabels, layout, responseColor, responseWidth, granularityは意味を持ちません。ほかに文字列を入力できるfree textを指定できますが、現状では日本語入力には使い物になりません(「8.6.2:日本語環境におけるFormコンポーネント(およびTextBoxコンポーネント)の文字入力機能 」参照)。 |
ticks |
スライダーの目盛をカンマ区切りで指定します。 |
tickLabels |
スライダーの目盛をカンマ区切りで指定します。 |
options |
スライダーのラベルをカンマ区切りで指定します。ラベルに対応する値は自動的に決まります。 旧バージョンではticks, tickLabelsがなかったためoptionsで指定していましたが、現在はticks, tickLabelsで指定する方がよいでしょう。 |
layout |
スライダーの方向をhoriz、vertのいずれかで指定します。horizなら水平方向、vertなら垂直方向です。省略するとhorizになります。 |
itemColor |
質問文の文字色を指定します。省略するとwhiteになります。Formコンポーネントの [スタイル] がcustom...の場合のみ有効です。 |
itemWidth |
Formコンポーネントの [サイズ$] で指定した幅のうち、質問文が占める幅の割合を0.0から1.0指定します。 |
responseColor |
スライダーの色を指定します。省略するとwhiteになります。Formコンポーネントの [スタイル] がcustom...の場合のみ有効です。 |
responseWidth |
Formコンポーネントの [サイズ$] で指定した幅のうち、スライダーが占める幅の割合を0.0から1.0指定します。itemWidthとresponseWidthの合計が1.0を越えるとレイアウトが崩れますので注意してください。 |
granularity |
Sliderコンポーネントの [精度 $] に対応します。typeがsliderの時のみ有効です。rating, radio, choiceの時は目盛の位置しか選択できません。 |
font |
使用するフォントはFormコンポーネントのプロパティダイアログの [フォント] で指定しますが、特定の項目だけ別のフォントを指定したい場合はここでフォント名を指定します。 |
Sliderの左側のテキストとSliderの幅のバランスはitemWidthとresponseWidthで調整します。それぞれの項目で異なる値を指定できるので、 図8.7 の例のように複数の種類のSliderを使い分ける際に種類ごとに異なるバランスにしたり、左側のテキストがどうしても長くする必要がある項目だけすこしitemWidthの幅を広げるといったこともできます。 itemWidth, responseWidthはFormコンポーネントの幅に対する相対値ですので、合計で1.0を超えないように注意してください。1.0を超えた場合、エラーにはなりませんが表示が崩れる場合があります。
項目ごとに色を指定したい場合のためにitemColor, responseColorというパラメータが用意されていますが、これらのパラメータを有効にするにはFormコンポーネントの [スタイル] をcustom...にする必要があります。それ以外の場合、itemColorとresponseColorは無視されます(書いてあってもエラーにはなりません)。 fontによる項目ごとのフォント指定は [スタイル] の設定に関係なく有効です。
設定ファイルの説明はこのくらいにして、その他の注意点を挙げていきましょう。まず [データフォーマット] ですが、これは実験記録ファイルへのデータの出力形式を選択するパラメータです。 言葉で説明するとわかりにくいので 図8.8 をご覧ください。 「行」であれば、Formコンポーネントに含まれる各Sliderの値が1行ずつ出力されていきます。「列」の場合は、実験内の他のパラメータと同様に、各Sliderの値が列方向にずらずらと出力されていきます。 おそらく、人の目で確認するときに見やすいのは「行」です。「列」にした場合、Sliderひとつに対して複数列の値が出力されるため、実験記録ファイルの列数が非常に多くなり一画面におさまらない可能性が高いですし、評定値が出力されているセルが飛び飛びになるためExcel上でマウスで選択して別のファイルにコピーするといった操作が非常に面倒になります。 一方、本書では解説しませんがPythonやRのスクリプトを書いてデータをまとめて処理する場合は、「1試行=1行」の鉄則が守られる「列」形式の方がプログラムを書くのが楽かも知れません。実験が完成してしまえば何列目が目的の評定値なのかは変化しないのですから、その列が飛び飛びであろうとプログラムで処理する際には問題にならないでしょう。好みに応じて使い分けてください。

図8.8 [データフォーマット] の設定によるFormコンポーネントの出力の違い¶
二つめの注意点は、 Formコンポーネントには [Routineを終了] がないので他の方法でルーチンを終了させる必要がある という点です。 この点はKeyboardコンポーネントやButtonコンポーネントの [Routineを終了] を併用すれば解決できますが、何も考えずにこれらのコンポーネントを配置すると「(故意か誤操作かはともかく)参加者がまだフォームに回答していないのに次のルーチンへ進んでしまう」ということが起こりかねません。 実験の内容によってはそれでもいい場合もあるでしょうが、多くの用途では「すべて回答してからでなければ次へ進まない」方が望ましいのではないでしょうか。 こういった時に便利なのがFormコンポーネントに対応するFormオブジェクトのデータ属性completeです。このデータ属性は、当該フォームのすべての項目が回答済みであればTrue、未回答の項目があればFalseとなります。これを利用して、
[開始] を「条件式」にしてform.completeにすれば、formという名前のFormコンポーネントのすべての項目に回答した時点でそのコンポーネントが有効になる
[終了] を「条件式」にしてform.completeにすれば、formという名前のFormコンポーネントのすべての項目に回答した時点でそのコンポーネントが終了する
といった動作が可能になります。 1はKeyboardコンポーネントやButtonコンポーネントなど、 [Routineを終了] を設定しているコンポーネントに適用すれば、すべての項目に回答し終えた後に参加者が自分でキーを押すなりボタンを押すなりしてルーチンを終了させるという使い方がよいでしょう。 特にButtonコンポーネントの場合、 ルーチンの開始時にはボタンが表示されていなくて、回答を終えた瞬間に次のルーチンへ進むためのボタンが出現する という動作になるので参加者にとってもわかりやすいと思います(Keyboardコンポーネントだとキーが押せるようになったことがわかりにくい)。
2はFormコンポーネント自身に対して適用して、すべての項目に回答し終えたらFormコンポーネントが終了するという使い方がよいでしょう。 Formコンポーネント以外に教示用のTextコンポーネントなどが配置されている場合、それらのコンポーネントがすべて終了するように設定しないとルーチンが終了しない点に注意してください。 最後の項目に回答した瞬間にフォームが消えてしまうので参加者は最初少し驚くかもしれませんが、いちいち回答終了のためにキーやボタンを押すといった操作をしなくて済むのは楽かもしれません。 最後の項目に回答した後にも参加者に回答の変更を許可したい場合は、1の方法がよいでしょう。
最後の注意点は、 Formコンポーネントを配置したルーチンをループで繰り返す場合、2回目以降の繰り返しでは前回の回答が残ったままになっている という点です。回答済みを表すデータ属性completeもTrueのままです。 おそらくフォームへの入力内容を後続のルーチンで使用することを考えての仕様なのでしょうが、繰り返し毎に未入力の状態に戻ってほしい場面も多いでしょう。 そういった場合はFormオブジェクトのreset( )というメソッドを使用します。Codeコンポーネントを配置して [Routine開始時] に
form.reset( )
というコードを実行するとよいでしょう(formの部分は初期化したいFormコンポーネントの [名前] にする)。
コンポーネントの解説はこのくらいにして、次はSliderコンポーネントとFormコンポーネントを使用して 第6章 の実験をマウスで反応できるようにしてみましょう。
- チェックリスト
Sliderコンポーネントで縦向き・横向きのスライダーを描画できる。
Sliderコンポーネントでラジオボタンを用いた多肢選択を描画できる。
Sliderコンポーネントで数値を回答させる際にマーカーの最小間隔を設定できる。
Sliderコンポーネントで参加者の回答を取得するコードを書ける。
Formコンポーネントで複数の質問項目とスライダーのペアをルーチンに配置することができる。
Formコンポーネントのすべての項目に回答したらルーチン終了のボタンを表示させることができる。
Formコンポーネントのすべての項目に回答したらフォームを終了させることができる。
ループの中でFormコンポーネントを使う時に繰り返しのたびに反応を初期化することができる。
8.5. 概念識別の実験をマウスで反応できるようにしよう¶
第7章 の作業を最後までおこなった状態(練習問題は除く)から作業する前提で手順を解説します。
- 実験設定ダイアログ
「スクリーン」タブの [マウスカーソルを表示] をチェックする。
- instructionルーチン
配置済みのKeyboardコンポーネントを削除する。
- Buttonコンポーネントをひとつ配置し、以下のように設定する。
「基本」タブの [名前] を
buttonInst
にして、 [終了] を空欄にする。 [ボタンのテキスト] をOK
に変更する。「レイアウト」タブの [サイズ [w, h] $] を
(0.8, 0.04)
にする。 [位置 [x, y] $] を(0, -0.4)
にする。「書式」タブの [フォント] を日本語に対応したフォントにする。 [文字の高さ $] を
0.03
にする。「データ」タブの [クリックを記録] を「なし」にする。
- trialルーチン
配置済みのtextYes, textNo (それぞれTextコンポーネント)、key_choice (Keyboardコンポーネント)を削除する。
- Sliderコンポーネントを配置し、以下のように設定する。
「基本」タブの [名前] を
sliderResponse
にする。 [Routineを終了] がチェックされていること、 [スタイル] が rating であることを確認する(いずれも初期値でそうなっているはず)。「基本」タブの [目盛 $] を
(0, 1, 2, 3)
にする。 [ラベル $] に'いいえ','多分いいえ','多分はい','はい'
と入力する。区切りのカンマや各ラベルを囲む' 'は日本語入力をOFFにして(つまり半角で)入力すること。「基本」タブの [精度 $] を
1
にする。「レイアウト」タブの [サイズ [w, h] $] を
(0.8, 0.03)
にする。 [位置 [x, y] $] を(0, -0.3)
にする。 [反転] をチェックする。「書式」タブの [フォント] を日本語に対応したフォントにする。 [文字の高さ $] を
0.03
にする。
配置済みのCodeコンポーネントを一番下に移動させて(通常、sliderResponseを追加したことでsliderResponseが一番下になっている)、 [Routine終了時] のコードを以下のように変更する。
res = sliderResponse.getRating()
if res>1.5 and correctAns=='left':
feedbackMsg = '正解'
elif res<1.5 and correctAns=='right':
feedbackMsg = '正解'
else:
feedbackMsg = '不正解'
- feedbackルーチン
配置済みのKeyboardコンポーネントを削除する。
instructionルーチンに配置済みの buttonInst をコピーして、
buttonFeedback
という名前でfeedbackルーチンに貼り付ける。
- reportルーチン
配置済みのコンポーネントを全て削除する。
- Formコンポーネントを配置して、以下のように設定する。
「基本」タブの [名前] を
formReport
にする。 [項目] は後で設定する。「レイアウト」タブの [サイズ [w, h] $] を
(1.3, 0.7)
にする。 [項目間の余白] を0.01
にする。「書式」タブの [テキストの高さ $] を
0.03
、 [フォント] を日本語に対応したフォントにする。
- instructionルーチンに配置済みの buttonInst をコピーして、
buttonReport
という名前でfeedbackルーチンに貼り付けて以下のように設定する。 「基本」タブの [終了] を「条件式」にして、
formReport.complete
と入力する。
- instructionルーチンに配置済みの buttonInst をコピーして、
- 項目定義ファイル
実験のpsyexpファイルと同じフォルダに 図8.9 に示す内容のxlsxファイルを作成し、reportルーチンの [項目] に設定する。

図8.9 実験用の項目定義ファイル¶
以上で作業は終了です。実行すると、 図8.10 左のように、顔画像を見て判断する画面でスクリーンの下の方に「いいえ」「多分いいえ」「多分はい」「はい」の4段階の尺度が表示され、尺度上をクリックすることで回答できます。 選択肢の中間をクリックすると、最も近い位置の選択肢が記録されます。 すべての画像について回答を終えると、 図8.10 右のように「はい」が正答となる条件はなんだったかを選択式で回答するフォームが表示されます。すべての項目に回答すると画面下にOKボタンが表示されて、このOKボタンをクリックすると実験が終了します。

図8.10 実験の実行画面。左は各画像について回答中。右は最後の質問フォーム。すべての項目が回答済みでOKボタンが表示されている。¶
おおむね前節の解説でおわかりいただける作業内容だと思いますが、OKボタンの位置と大きさについて少し補足しておきます。 sliderResponseは(0, -0.3)の位置、buttonFeedbackは(0, -0.4)の位置に置かれているため、参加者は刺激画像を判断して尺度をクリックした後、フィードバックを見て少しマウスを下に動かしてOKボタンをクリックしないといけません。そして次の画像について反応するためにまた少しマウスカーソルを上に動かす必要があります。 この実験を実行してみて、この上下移動を面倒に感じた方もおられるのではないでしょうか。 両者のY座標を揃えればこの上下移動をせずに済みますが、もし sliderResponseをクリックしたときのマウスカーソルの位置が、フィードバック画面でのbuttonFeedbackと重なっていたら、フィードバック画面に切り替わった瞬間にbuttonFeedbackをクリックしたと判定されてフィードバック画面が終了する という問題が生じます。 本節で作成したように、sliderResponseとbuttonFeedbackが重ならないように位置をずらしておけば、この問題を避けるためなのです。 少しでもマウスカーソルを動かす負担を軽減できるよう、buttonFeedbackの幅をsliderResponseと同じ幅にしておいて、sliderResponseのどの位置をクリックしても左右方向にほとんどカーソルを動かさずにbuttonFeedbackをクリックできるようにしてあります。
どうしても上下移動を避けたい場合は、buttonFeedbackの [開始] を0.5秒や1.0秒などに設定して、画面が切り替わった直後にはボタンが表示されないようにしておきましょう。 [開始] を遅らせるほど問題が生じる危険性が低下しますが、参加者を待たせることになります。フィードバック画面のOKボタンの表示を遅らせるのではなく、次の試行に入る時に完全に画面がブランクになる時間を設ける(つまりtrialルーチンのすべてのコンポーネントの [開始] を遅くする)方が違和感が少ないかも知れません。 「こうすれば間違いない」といった絶対的な方法はないと思いますので、各自でいろいろと試してみられるとよいと思います。
8.6. この章のトピックス¶
8.6.1. 同一ルーチンに配置されている複数のSliderコンポーネントが回答済みか判定する¶
trialルーチンにslider1, slider2というSliderルーチンが配置されているとします。参加者がslider1に回答していれば、slider1.ratingの値はNone以外になっています。NoneはPythonの文法において特殊な値で、変数xの値がNoneであるか判定するにはx is Noneという式を書きます(NoneであればTrue, なければFalse)。Noneではないときに真になるようにしたければ、否定演算子notを使ってx is not Noneと書きます。従って、以下のような式をif文を書けば、slider1が回答済みの時に処理を行わせるコードが書けます。
if slider1.rating is not None:
# slider1が回答済みのときにしたい処理
slider1, slider2の両方が回答済みという条件にしたい場合は、論理演算子andを使って
if slider1.rating is not None and slider2.rating is not None:
# slider1と2が回答済みのときにしたい処理
と書くことができます。さらにSliderコンポーネントの数が増えると、いちいち is not None と書くのは面倒ですし、式が長いです。 そんな場合はin演算子を使って
if None not in (slider1.rating, slider2.rating, slider3.rating, slider4.rating):
# slider1から4が回答済みのときにしたい処理
という具合に「( )内にNoneがない」という条件として書くと、is not Noneを繰り返さなくていい分簡潔になります。
8.6.2. 日本語環境におけるFormコンポーネント(およびTextBoxコンポーネント)の文字入力機能¶
第6章 の実験では最後に「答えが『はい』になる条件は何か?」ということを口頭で自由報告させていましたが、本章ではこれを選択問題に変更しました。 Formコンポーネントの使い方を解説するためとはいえ、これは実験の結果に影響しかねない大きな変更です。 「自由報告させたいけど、実験者が横で聞き取って記録しなくても済むようにしたい」という場合、Builderにこだわらなければ色々方法があると思いますが(例えば紙に書かせて後から紙を回収するなど)、本書はBuilderの解説本ですので、なんとかBuilderで実現できる方法を考えたいところです。
とりあえずぱっと思いつくのは、PCに接続されたマイクを利用して音声を録音するMicrophoneコンポーネントを使うことです。ただ、音声データはファイルサイズが大きいですし、後で再生して文字起こしする手間もかかりますので、参加者が多い実験ではあまり使いたくありません(筆者の個人的な意見ですが)。 他に良さげな候補は、ということで挙がってくるのがFormコンポーネントのfree textです。これはフォーム上にキーボードを使って文字を入力できるボックスを設けるもので、自由に回答できるという点はクリアしていますし、録音のようにファイルサイズが大きくなる問題も後で文字起こしをするという手間もありません。 第6章 の実験の改良として非常に魅力的なのですが、残念ながら現在(執筆時点でバージョン2024.2.5)のFormコンポーネントでは日本語入力のようにIME(Imput Method Editor: ローマ字入力やかな入力、漢字変換などの機能を提供するソフトウェア)を使った文字入力画面をうまく表示できないのです。

図8.11 Formコンポーネントのfree textで日本語を入力するとIMEの表示がおかしくなる。¶
図8.11 はfree textを持つFormコンポーネントをPilotモードで実行して日本語を入力しようとした様子ですが(OSはWindows 11)、タイプした文字が表示されるべき右下の白い枠内には文字が表示されず、画面左上の角に小さなウィンドウが開いてその中に表示されてしまっています。 この状態は不便ではありますが、「入力注の文字列が左上に表示されている」ということに気づきさえすれば、通常の操作で文字の入力は一応可能です。 問題はフルスクリーンモードで実験を実行した場合で、左上に出現するウィンドウが隠れて全く見えなくなってしまいます。ひらがな程度ならなんとか入力できなくもありませんが、漢字変換は変換候補が見えないためお手上げです。 本文で「free textは現状では日本語入力には使い物になりません」と書いたのはこのためです。
PsychoPyはマルチプラットフォームであり、Windows、MacOS、Linuxなどさまざまな環境をサポートしなければいけないため、IMEのようにOSに大きく依存する機能に対応するのは難しいです。 残念ながら、おそらく数年内にこの問題が解決されて自然な日本語入力が可能になることはないでしょう。 本実験のように、実験の最後に一度だけ文字入力を求めるのであれば、Builderでの実験をいったん終了させてしまって何か別の方法で文字入力してもらう方が簡単でしょう。 実験手続きの途中で入力が必要な場合、ちょっと抜け道的な使い方ですが「オンライン実験」をローカルブラウザで実行するという方法もあります。詳しくは「 13.7:実験中に日本語文字入力をさせたい方のために:「オンライン実験」をローカル環境でで実行する 」をご覧ください。