Skip to content

Instantly share code, notes, and snippets.

@cosacog
Last active January 23, 2019 10:44
Show Gist options
  • Save cosacog/136ad93d55725d7cba7118bf58e86f79 to your computer and use it in GitHub Desktop.
Save cosacog/136ad93d55725d7cba7118bf58e86f79 to your computer and use it in GitHub Desktop.
psychopyでキータイプの配列を練習します。説明は下の方です。
from __future__ import absolute_import, division
from psychopy import locale_setup, sound, gui, visual, core, data, event, logging, clock
from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED,
STOPPED, FINISHED, PRESSED, RELEASED, FOREVER)
import numpy as np # whole numpy lib is available, prepend 'np.'
from numpy import (sin, cos, tan, log, log10, pi, average,
sqrt, std, deg2rad, rad2deg, linspace, asarray)
from numpy.random import random, randint, normal, shuffle
import os # handy system and path functions
import sys # to get file system encoding
win = visual.Window(
size=(1024, 768), fullscr=False, screen=0,
allowGUI=False, allowStencil=False,
monitor='testMonitor', color=[0,0,0], colorSpace='rgb', units='pix',
blendMode='avg', useFBO=True)
# timer
trialClock = core.Clock()
# numbers
px_num_space = 100 # pixel
nums = []
x_pos_list = []
len_num = 5
for ii in range(len_num):
x_pos = -px_num_space*2 + px_num_space*ii
num = visual.TextStim(win=win, name="num"+str(ii),
text='1',
font='Arial',
pos=(x_pos, 0), height=30, wrapWidth=None, ori=0,
color='white', colorSpace='rgb', opacity=1,
languageStyle='LTR',
depth=-1.0);
nums.append(num)
x_pos_list.append(x_pos)
# underline
l_width = 50 # pix
x_pos = x_pos_list[0] # pix
y_pos = -30 # pix
underline = visual.Line(
win=win, name='underline',
start=(-l_width*0.5, 0), end=(l_width*0.5, 0),
ori=0, pos=(x_pos, y_pos),
lineWidth=3, lineColor='white', lineColorSpace='rgb',
fillColor='white', fillColorSpace='rgb',
opacity=1, depth=-1.0, interpolate=True)
# fixation cross
px_fixation_line = 50 # pixel
col_fixation = 'white'
fixation_v = visual.Line(
win=win, name='v_line',
start=(-px_fixation_line*0.5, 0), end=(px_fixation_line*0.5, 0),
ori=0, pos=(0, 0),
lineWidth=3, lineColor=col_fixation, lineColorSpace='rgb',
fillColorSpace='rgb',
opacity=1, depth=-1.0, interpolate=True)
fixation_h = visual.Line(
win=win, name='v_line',
start=(0, -px_fixation_line*0.5), end=(0, px_fixation_line*0.5),
ori=0, pos=(0, 0),
lineWidth=3, lineColor=col_fixation, lineColorSpace='rgb',
fillColorSpace='rgb',
opacity=1, depth=-1.0, interpolate=True)
# text
txt_msg = visual.TextStim(win=win, name="txt_msg",
text='', font='Arial',
pos = (0,0), height = 30, wrapWidth=True,
color='white')
txt_count_down = visual.TextStim(win=win, name="txt_countdown",
text='30', font='Arial',
pos = (300,200), height = 60, wrapWidth=True,
color='white')
# sound
soundG = sound.Sound('G', octave=2, sampleRate=44100, secs=0.5, stereo=True);
# characters: for key press
chars = ['a','s','d','f']
# messages
msg_end = """
終了です。
お疲れさまでした。
"""
#%% functions
def count_down_timer(t):
'''
set count down timer
'''
if int(txt_count_down.text) -1 > int(t):
txt_count_down.text = str(int(t)+1)
win.flip()
def fixation_onoff(onoff='on'):
if onoff=='on':
fixation_v.setAutoDraw(True)
fixation_h.setAutoDraw(True)
else:
fixation_v.setAutoDraw(False)
fixation_h.setAutoDraw(False)
win.flip()
def get_message_init(char_seq):
'''
get message for inital instruction
'''
msg_init = """
数列パターン:{0}
何かナイスな指示をします。
"Enter"を押したらスタートです。
""".format(char_seq)
return msg_init
def get_message_count_down(t_rest, count):
'''
'''
msg = """
休憩です。
{0}秒で再開します。
あと{1}回あります。
""".format(t_rest, count)
return msg
def nums_onoff(onoff = 'on'):
'''
nums.setAutoDraw
onoff: 'on' or 'off'
'''
for num in nums:
if onoff=='on':
num.setAutoDraw(True)
underline.setAutoDraw(True)
else:
num.setAutoDraw(False)
underline.setAutoDraw(False)
# def set_random_numbers():
# '''
# set numbers 1-5
# return numbers, including each of 1,2,3,4
# '''
# import numpy as np
# num_seq = np.random.randint(1,high=5, size=5)
# while len(np.unique(num_seq))<4:
# num_seq = np.random.randint(1,high=5, size=5)
# for ii in range(5):
# nums[ii].text = str(num_seq[ii])
# win.flip()
def set_random_numbers_AB(num_seqs, sequence='A'):
'''
set numbers 1-5
return numbers, including each of 1,2,3,4
'''
import numpy as np
assert sequence.upper() in ['A', 'B'], "'sequence' must be either 'A' or 'B'"
num_seq = num_seqs[sequence]
while len(np.unique(num_seq))<4:
num_seq = np.random.randint(1,high=5, size=5)
for ii in range(5):
nums[ii].text = str(num_seq[ii])
win.flip()
def save_responses2csv(dir_save, responses):
'''
save responses to csv
'''
import pandas as pd
import os
from datetime import datetime as dt
tdatetime = dt.now()
df = pd.DataFrame(responses, columns=['target','response','judge'])
# save path
fname_csv = tdatetime.strftime('%y%m%d%H%M.csv') # 1901231823.csv
path_save = os.path.join(dir_save, fname_csv)
print("Responses were saved to {0}".format(path_save))
df.to_csv(path_save, index=None)
def take_some_rest(msg, wait_time=30, wait_for_keypress=True, use_count_timer=False):
'''
wait and show message
'''
txt_msg.text = msg
txt_msg.setAutoDraw(True)
win.flip()
continueRoutine_tsr = True
t_start_rest = trialClock.getTime()
while continueRoutine_tsr:
t = trialClock.getTime() - t_start_rest
if t > wait_time:
continueRoutine_tsr = False
if use_count_timer:
count_down_timer(wait_time -t)
k = event.getKeys()
if len(k)==0:
continue
if k[0] == 'escape':
core.quit()
if len(k)>0 and wait_for_keypress:
continueRoutine_tsr = False
txt_msg.setAutoDraw(False)
win.flip()
#%% main
# set configurations
num_seqs ={'A':[1,3,2,4,3], 'B':[3,1,4,2,4]}
char_sequence_pattern='A'
set_random_numbers_AB(num_seqs, char_sequence_pattern)
trial_count = 12
t_trial = 30 # secs for trial
t_rest = 30 # secs for rest
nums_onoff('off')
# initial instruction
msg_init = get_message_init(char_sequence_pattern)
take_some_rest(msg_init, wait_time=3, wait_for_keypress=True)
# main loop
responses = []
for idx_trial in np.arange(trial_count):
char_count = -1
trialClock.reset()
continueTrial = True
nums_onoff(onoff='on')
txt_count_down.text = str(t_trial)
txt_count_down.setAutoDraw(True)
win.flip()
while continueTrial:
char_count += 1
continueRoutine = True
idx_num = char_count%len(nums)
# print(idx_num)
# change underline position
underline.pos = (x_pos_list[idx_num], y_pos);win.flip()
# set target character
idx_char = int(nums[idx_num].text) -1 #0-4
char_target = chars[idx_char]
while continueRoutine:
# check time limit
t = trialClock.getTime()
if t > t_trial:
continueTrial = False
# check time and count down
count_down_timer(t_trial - t)
# check key press or not
k = event.getKeys()
if (len(k)==0):
continue
# if press 'escape', quit
if k[0]=='escape':
core.quit()
# judge correct/incorrect key press
# print(k[0])
if (k[0]==char_target):
ans = 'correct'
continueRoutine = False
else:
soundG.setSound('G', octave=2);soundG.play()
ans = 'wrong'
response = [char_target, k[0], ans]
responses.append(response)
nums_onoff(onoff='off')
if idx_trial==trial_count-1:
# last trial-> skip rest
continue
# rest
fixation_onoff(onoff='on')
txt_count_down.text= str(t_rest)
msg_rest = get_message_count_down(t_rest, trial_count - idx_trial -1)
take_some_rest(msg_rest, wait_time=t_rest, wait_for_keypress=False, use_count_timer=True)
fixation_onoff(onoff='off')
# save responses
list_judges = [resp[-1] for resp in responses]
count_chars = len(responses)
count_correct = list_judges.count('correct')
count_wrong = list_judges.count('wrong')
responses.append([
'correct:{0}'.format(count_correct),
'wrong:{0}'.format(count_wrong),
'total:{0}'.format(count_chars)
])
print(responses[-1]) # print result
dir_save = os.getcwd()
save_responses2csv(dir_save, responses)
# end message
take_some_rest(msg_end, wait_time=3, wait_for_keypress=False)
# quit
print('done')
win.close()
core.quit()
@cosacog
Copy link
Author

cosacog commented Jan 23, 2019

片手でキー配列をタイプして練習します

psychopyを使って行動データを取ります。

最初にやること

  • ダウンロードします。右上に"Download zip"のボタンがあります。ファイルをダウンロード、解凍しましょう。
  • Psychopyで開きます。
  • "Run"ボタンを押します。

使い方

  • 画面に従ってタイプします。a,s,d,fを1-4に割当てしてます。
  • 間違えると音が鳴ります。

終わったら

  • スクリプトと同じディレクトリにcsvが結果で保存されます。最後にトータルの正答/不正答の数を表示してます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment