この記事では、PsychoPyを使って、円を描くように刺激を動かす方法を解説します。
実験の参加者は、刺激が動いていあいだ、何度でもキーを押せることにします。
そして、キーを押したときの刺激の位置を記録します。
刺激は5秒間呈示されると消えるものとします。
今回のプログラムは、Builderだけでは作れない(作りにくい)例です。Codeコンポーネントを使いますが、それでもまだ作りにくく、Coderを使用します。(注: CodeコンポーネントとCoderは別物です)
刺激(今回の例では青い正方形とします)は、注視点を中心とした円周上を動きます。
この例では、簡単な三角関数を使います。以下の図の意味が分からないときは、三角関数についてまずは復習してください。
半径がrの円を正方形が移動するとき、正方形の座標は (x, y) = (r * cos(θ), r * sin(θ)) となります。
以下の図を参考にして、code, polygon, keyboardの3つのコンポーネントを配置してください。
polygonコンポーネント
色を青にするには「高度」タブを開きます。手動で、$[-1, -1, 1]
と打ち込んでもよいですが、数字が書いてある場所を右クリックすると色を選択することができます。
keyboardコンポーネント
変更箇所は次の通りです。

今回の実験では、何回もキー入力ができるので「Routineを終了」のチェックを外し、記録を「全てのキー」とします。
Codeコンポーネント
「フレーム毎」のタブを開き、次のコードを入力します。
radius = 5 # deg
angle_deg_sec = 45 # deg/sec
current_deg = angle_deg_sec * t
polygon.pos = (radius * cos(deg2rad(current_deg)), radius * sin(deg2rad(current_deg)))
円の半径(radius)を視角5度(degree)としています。刺激が動く速度(angle_deg_sec)は45度/秒です。つまり、1秒で45度進みます。
tは、PsychoPyが準備している変数で、Routineの開始時からの時間(秒)になります。
距離(今回の例では移動角度) = 速度 x 時間
という関係を思い出してくださいね。
polygon.pos =
の行で、polygonの座標を決定しています。
以上の作業をフレーム毎、つまり、画面が書き換わるタイミングごとに実行されるようにします。
ここまでの作業はBuilderで可能です。プログラムを実行してみてください。青い正方形が円上を移動するはずです。
Coderを使って、キーが押されたときの刺激の位置を記録しよう
まずはBuilderで実行して、刺激が移動しているあいだに、3回ほどスペースキーを押してみてください。
その後、dataフォルダにある csvファイルを開いてください。
上の図のようにスペースキーが3回押されて、それぞれの反応時間が記録されていることが分かります。
これらのデータと同じように、スペースキーが押されたときの刺激の位置を記録してみましょう。
刺激の位置は(x, y)の座標ですが、説明を簡略化するため、角度(θ)を記録することにします。角度が分かれば、(x, y)の座標も計算可能です。
重要な注意点です。 Coderで変更したあとにBuilderで変更を加えると、Coderの変更が上書きされてしまうため、まずはファイルを別名で保存するようにしましょう。
key_resp.keys
やkey_resp.rt
のように記録したいので、これらが記述されているところを見つけ出します。なお、ここからの作業は、Coderよりも、Visual Studio CodeやAtomなどのテキストエディタを使うほうが便利だと思います。
# update component parameters for each repeat
key_resp.keys = []
key_resp.rt = []
この箇所を見つけてください。これはデータを記録するためのリストを作るためのコードです。初期化とも言います。
角度のデータを保存するため、初期化のコードを追加してみましょう。
# update component parameters for each repeat
key_resp.keys = []
key_resp.rt = []
key_resp.angle = []
次に、以下のコードを探してください。
key_resp.keys.append(theseKeys.name) # storing all keys
key_resp.rt.append(theseKeys.rt)
これはキーを押すたびに実行される箇所で、どのキーが押されたか、そしてその反応時間を保存しています。ここで角度のデータも同じように保存しましょう。
保存したい角度のデータは、current_deg
になります。どうしてcurrent_deg
を保存するのか分からないときは、上で説明したCodeコンポーネントのところを読み返してみてください。
次のように追記します。注意点として、インデントを上の2行とそろえてください。Pythonではインデントが重要な意味を持ちます。
key_resp.keys.append(theseKeys.name) # storing all keys
key_resp.rt.append(theseKeys.rt)
key_resp.angle.append(current_deg)
最後に、以下のコードを探してください。
thisExp.addData('key_resp.keys',key_resp.keys)
if key_resp.keys != None: # we had a response
thisExp.addData('key_resp.rt', key_resp.rt)
Routineの終了時に、すべてのキーの情報と、その反応時間をCSVファイルに保存しています。2行目にif文がありますが、これは「キーが一度でも押されていたら」という意味です。一度もキーが押されないこともあり得るのでこのような書き方になっています。
一度でもキーが押されていたら、反応時間と一緒に、角度が保存されるようにしましょう。
thisExp.addData('key_resp.keys',key_resp.keys)
if key_resp.keys != None: # we had a response
thisExp.addData('key_resp.rt', key_resp.rt)
thisExp.addData('key_resp.angle', key_resp.angle)
以上で変更は終わりです。
実行するときは、Builderの実行ボタンではなく、Coderの実行ボタンを押します。
角度のデータが保存されていることを確認してください。