Last active
January 23, 2019 10:44
-
-
Save cosacog/136ad93d55725d7cba7118bf58e86f79 to your computer and use it in GitHub Desktop.
psychopyでキータイプの配列を練習します。説明は下の方です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
片手でキー配列をタイプして練習します
psychopyを使って行動データを取ります。
最初にやること
使い方
終わったら