Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1bf68d6
Making changes to main GUI to support new pre-trial action settings (…
ryang-123 Sep 19, 2019
e663190
Minor fix to GUI: Disabling Settings button on Run
ryang-123 Sep 19, 2019
19165c1
Implementation for the arrow in exp.py added (not functioning yet. Do…
ryang-123 Sep 24, 2019
348e682
Arrow added to the screen. Aim still does not work fully (must use wi…
ryang-123 Sep 26, 2019
0311e50
It finally works. Full arrow functionality. Now making it work only w…
ryang-123 Oct 3, 2019
c4f17a7
Successfully connected GUI entry to Exp.py. Can now check boolean val…
ryang-123 Oct 8, 2019
f77eb49
Functionality of if statement works. Now to complete hold on home
ryang-123 Oct 8, 2019
1b70c61
Further changes to ensure GUI works with Exp
ryang-123 Oct 8, 2019
94539cf
Updating slider values for Hold at Home
ryang-123 Oct 30, 2019
4f61897
Adding in hold_home test to see if data is stored. NOTE: Will have to…
ryang-123 Oct 30, 2019
8875fd4
Removed sleep for hold. Hold compares current time now with hold time…
ryang-123 Nov 5, 2019
29bac03
aiming: Can only aim on trial now. Must fix so arrow updates origin p…
ryang-123 Nov 12, 2019
9716c5c
aiming: aim option boolean and aim value in degrees successfully adde…
ryang-123 Nov 14, 2019
f964060
aiming: aim updated so arrow starts at proper home position
ryang-123 Nov 21, 2019
2665012
aiming: Aiming arrow starts 10 degrees away from target to make user …
ryang-123 Nov 21, 2019
d226d61
Aiming: Cleaned up print statements and other bugs. Added random for …
ryang-123 Nov 26, 2019
f67a3d1
changes
ryang-123 Feb 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 218 additions & 5 deletions Exp.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from psychopy.visual import Window, Circle, ShapeStim, TextStim, ImageStim
from psychopy import event, core
from pyglet.window import key
from os import path, listdir
from json import dump
from numpy import sqrt, arctan2, cos, sin, linalg, clip, ndarray, array, diff, mean, arange, pi, dot
import csv
import math
import random
#import time
import scipy as sp
from pandas import concat, DataFrame
from random import choice, seed, shuffle
from Tkinter import Tk
Expand All @@ -17,7 +21,7 @@
except:
pass

from time import time
from time import time, sleep

root = Tk()
def addWorkSpaceLimits(screen):
Expand Down Expand Up @@ -220,6 +224,140 @@ def angle_split(min_angle, max_angle, num_splits):
# myWin.flip()
# event.waitKeys(keyList=['space'])

####################################PRE AIM STUFF#########################################################

class myHomeArrow:

def __init__(self,cfg,ori=0,color='#999999',size=1):
self.ori = ori
self.color = color
self.size = size
self.rightArrow = ShapeStim(win=cfg['win'],
lineWidth=0,
lineColorSpace='rgb',
lineColor=None,
fillColorSpace='rgb',
fillColor=self.color,
closeShape=True,
size=self.size,
ori=self.ori,
vertices=((-.1,0),(.9,0),(-.636,-.636))
)
self.leftArrow = ShapeStim(win=cfg['win'],
lineWidth=0,
lineColorSpace='rgb',
lineColor=None,
fillColorSpace='rgb',
fillColor=self.color,
closeShape=True,
size=self.size,
ori=self.ori,
vertices=((-.1,0),(.9,0),(-.636,.636))
)

def draw(self):
self.rightArrow.ori = self.ori
self.leftArrow.ori = self.ori
self.rightArrow.fillColor = self.color
self.leftArrow.fillColor = self.color
self.rightArrow.size = self.size
self.leftArrow.size = self.size
self.rightArrow.draw()
self.leftArrow.draw()

cfg['home_arrow'] = myHomeArrow(cfg,size=cfg['radius'])

def doAiming(cfg,isAim):

#print "IN doAiming FUNCTION"

cfg['aim'] = sp.NaN
cfg['aimtime_ms'] = sp.NaN
cfg['keyboard'] = key.KeyStateHandler()
cfg['win'].winHandle.push_handlers(cfg['keyboard'])

cfg['end_circle'].draw()
cfg['aim_arrow'].ori = (-1 * cfg['target_angle']) + random.randint(-10,10)
cfg['aim_arrow'].draw()
cfg['win'].flip()
#print "drew arrow"

aimDecided = False

#event.clearEvents()

#startaiming = time.time()

while(aimDecided == False):
#print 'entered loop'
if (cfg['keyboard'][key.ENTER]):
cfg['aim'] = -1 * cfg['aim_arrow'].ori
aimDecided = True
#print 'aim decided'
cfg['aim_arrow'].ori = cfg['aim_arrow'].ori % 360
#print cfg['aim_arrow'].ori --->PRINTS DEGREE
#cfg['win'].flip()
#print "Aim Decided " + str(aimDecided)
break
return cfg['aim_arrow'].ori
#sys.exit('Aim chosen and exited')
#stopaiming = time.time()

#NOTE: RYAN CHANGED key.NUM_LEFT and key.NUM_RIGHT to key.LEFT and key.RIGHT --> Local change only
elif cfg['keyboard'][key.LEFT]:
cfg['aim_arrow'].ori = cfg['aim_arrow'].ori - 1
#cfg['aim_arrow'].draw()
#print "LEFT"
#time.sleep(0.5)
#print(cfg['aim_arrow'].ori)
elif cfg['keyboard'][key.RIGHT]:
cfg['aim_arrow'].ori = cfg['aim_arrow'].ori + 1
#cfg['aim_arrow'].draw()
#print "RIGHT"
#time.sleep(0.5)
#print(cfg['aim_arrow'].ori)
#print(cfg['keyboard'])
cfg['aim_arrow'].ori = cfg['aim_arrow'].ori % 360
cfg['end_circle'].draw()
cfg['aim_arrow'].draw()
cfg['win'].flip()


if cfg['keyboard'][key.ESCAPE]:
sys.exit('escape key pressed')

#if (cfg['aim'] < 0) or (cfg['aim'] > 360):
#cfg['aim'] = cfg['aim'] % 360
#cfg['aimtime_ms'] = int((stopaiming - startaiming) * 1000)
#cfg['aimtime_ms'] = int((stopaiming - startaiming) * 1000)

#print(cfg['tasks'][cfg['taskno']]['target'][cfg['trialno']])
#print(cfg['aim'])


#return(cfg)
#print "we done"
return cfg['aim_arrow'].ori

def hold_at_home_function(holdHome):
if (holdHome >= 50 and isHold == True):
firstTime = time()
print firstTime
holdTime = firstTime + holdHome
print holdTime
holding = True
while (holding == True):
currentTime = time()
print currentTime
if (currentTime >= holdTime):
holding = False
break
else:
print "still holding"
currentTime = time()
print currentTime
break
print "We held"

def trial_runner(cfg={}):
try:
Expand Down Expand Up @@ -329,6 +467,27 @@ def trial_runner(cfg={}):
if (cfg['use_score']):
myCircle.lineColor = myCircle.fillColor = [0, 0, 0]
endCircle.lineColor = endCircle.fillColor = [0, 0, 0]
#doAiming(cfg,isAim)
global aimValue
aimValue = -1
# if (isAim == True):
# show_home = False
# show_cursor = False

if (preTrialAction == True and isAim == True):
winSize = cfg['win'].size
PPC = max(winSize)/31.
cfg['NSU'] = PPC * 8
#print startPos
#print startPos[0]
#print startPos[1]
arrowvertices = ((-.02,-.02),(0.82,-.02),(0.8,-.08),(1,0),(0.8,.08),(0.82,.02),(-.02,.02))
cfg['aim_arrow'] = ShapeStim(win=cfg['win'], lineWidth=cfg['NSU']*0.005, lineColorSpace='rgb', lineColor='#CC00CC', fillColorSpace='rgb', fillColor=None, vertices=arrowvertices, closeShape=True, size=PPC*7)
cfg['aim_arrow'].pos = startPos
cfg['aim_arrow'].ori = cfg['target_angle']
#print cfg['aim_arrow'].pos
aimValue = doAiming(cfg,isAim)
#print "AIM VALUE: " + str(aimValue)

except Exception as e:
print "error in Block 1" # what is block 1?
Expand Down Expand Up @@ -437,17 +596,22 @@ def trial_runner(cfg={}):
pass

# SHOW OBJECTS

try:
if (pos_buffer == 0):
pos_buffer = pos_buffer + 1
if (show_home == True):
#print "PRINT START CIRCLE HERE"
startCircle.draw() # home position
#cfg['aim_arrow'].draw()
#doAiming(cfg)
if (show_target == True):
endCircle.draw() # target position
if (show_arrow == True):
arrow.draw()
arrowFill.draw()
if (show_cursor == True):
#print "PRINT MY CURSOR HERE"
myCircle.draw() # cursor
# Show the score text only in cursor and error-clamp
if (cfg['use_score'] and cfg['trial_type'] != 'no_cursor' and cfg['trial_type'] != 'pause'):
Expand All @@ -456,8 +620,6 @@ def trial_runner(cfg={}):
print('Failed to show object: ')
print(e)
pass

# phase 1 is getting to the home position (usually over very soon)
try:
if (phase_1 == False):
if (cfg['trial_type'] == 'cursor'):
Expand Down Expand Up @@ -516,6 +678,7 @@ def trial_runner(cfg={}):
if (get_dist(circle_pos, endPos) < dist_criterion and velocity < 35 and cfg['terminal_feedback'] == False):
phase_2 = True
show_home = True

show_target = False

# If we are using end of reach to show feedback, change the colours for
Expand Down Expand Up @@ -555,6 +718,7 @@ def trial_runner(cfg={}):
score_text.draw()

# show feedback:
#print "PRINT END CIRCLE HERE 2"
endCircle.draw()
myCircle.draw()

Expand Down Expand Up @@ -622,6 +786,7 @@ def trial_runner(cfg={}):

while (show_terminal):
# show feedback:
#print "PRINTING END CIRCLE HERE 3"
endCircle.draw()
myCircle.draw()
myWin.flip()
Expand Down Expand Up @@ -689,12 +854,18 @@ def trial_runner(cfg={}):
timePos_dict['targetdistance_percmax'] = int(cfg['target_distance_ratio']*100)

timePos_dict['accuracy_reward'] = [cfg['score_points']] * len(mouseposXArray)
timePos_dict['pre_reach_aim'] = cfg['pre_reach_aim']
timePos_dict['aim_value'] = 0



if (cfg['use_score']):
timePos_dict['accuracy_reward_bool'] = ['True'] * len(mouseposXArray)
else:
timePos_dict['accuracy_reward_bool'] = ['False'] * len(mouseposXArray)

#print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
#print timePos_dict['aim_value']
return timePos_dict

elif ((cfg['trial_type'] == 'no_cursor' or cfg['trial_type'] == 'error_clamp' or (cfg['trial_type'] == 'cursor' and cfg['terminal_feedback'] == True)) and get_dist(circle_pos, startPos) <= 3*get_dist(startPos, endPos)/20):
Expand Down Expand Up @@ -743,6 +914,20 @@ def run_experiment(participant, experiment = {}):
task_save = DataFrame({})
running = deepcopy(experiment['experiment']) # why copy this? set up a window, a mouse object and add those, plus a task-index to your cfg, then simply loop through the tasks, and throw that to a run-task function?
settings = deepcopy(experiment['settings']) # same here...
#print running
#print "---------------------------------------------------------------------------------"
global preTrialAction
global isAim
global holdHome
global isHold
preTrialAction = running[0]['pre_trial_check']
isAim = running[0]['pre_reach_aim']
holdHome = running[0]['hold_home']
isHold = running[0]['hold_on_home']
#print "Pre Trial: " + str(preTrialAction)
#print "Is Aim: " + str(isAim)
#print "Hold at home run_experiment: " + str(holdHome)


cfg = {}
#### Generate seed ####
Expand All @@ -760,8 +945,22 @@ def run_experiment(participant, experiment = {}):

configureWindow(cfg, experiment)

#print cfg.keys()
cfg['psyMouse'] = event.Mouse(visible = False, newPos = None, win = cfg['win'])

#winSize = cfg['win'].size

# PPC = max(winSize)/31.
#
# cfg['NSU'] = PPC * 8
#
# arrowvertices = ((-.02,-.02),(0.82,-.02),(0.8,-.08),(1,0),(0.8,.08),(0.82,.02),(-.02,.02))
#
# cfg['aim_arrow'] = ShapeStim(win=cfg['win'], lineWidth=cfg['NSU']*0.005, lineColorSpace='rgb', lineColor='#CC00CC', fillColorSpace='rgb', fillColor=None, vertices=arrowvertices, closeShape=True, size=PPC*7)

#doAiming(cfg)


class myMouse:
def Pos(self):
#print('PsychoPy mouse')
Expand Down Expand Up @@ -1017,15 +1216,29 @@ def Pos(self):
running[i]['target_distance'] = int(running[i]['max_distance']*running[i]['target_distance_ratio'])

running[i]['time'] = core.getTime()

#checking if we must do a pre-trail action, if yes: do it then proceed to do trial
#if (preTrialAction == True):
#if (isAim == True):
#doAiming(cfg,isAim)
#elif (isHold == True):
#hold_at_home_function(holdHome)

exp = trial_runner(running[i]) # but this runs a whole task, not a single trial, right? since we are going from the experiment runner straight to task... is the function misnamed or is the code not organized?
if (isAim == True):
#print cfg
#print "==============================================================="
exp['aim_value'] = aimValue
#print exp['aim_value']
#timePos_dict['aim_value'] = cfg['aim_arrow'].ori

if exp == 'escaped':
running[i]['win'].close()
return DataFrame({})
else:
# is this where the data is saved?
# would make more sense to me to do that in the trial function, as it is the trial data that is being stored?
df_exp = DataFrame(exp, columns=['task_num','task_name', 'trial_type', 'trial_num', 'terminalfeedback_bool','rotation_angle','targetangle_deg','targetdistance_percmax','homex_px','homey_px','targetx_px','targety_px', 'time_s', 'mousex_px', 'mousey_px', 'cursorx_px', 'cursory_px', 'accuracy_reward', 'accuracy_reward_bool'])
df_exp = DataFrame(exp, columns=['task_num','task_name', 'trial_type', 'trial_num', 'terminalfeedback_bool','rotation_angle','targetangle_deg','targetdistance_percmax','homex_px','homey_px','targetx_px','targety_px', 'time_s', 'mousex_px', 'mousey_px', 'cursorx_px', 'cursory_px', 'accuracy_reward', 'accuracy_reward_bool', 'pre_reach_aim', 'aim_value'])
df_exp.to_csv(path_or_buf = path.join("data", settings['experiment_folder'], participant, running[i]['task_name'] + "_" + str(trial_num) + ".csv"), index=False)
task_save = concat([task_save, df_exp])
end_exp = concat([end_exp, df_exp])
Expand Down Expand Up @@ -1340,7 +1553,7 @@ def Pos(self):
running[i]['win'].close()
return end_exp
else:
df_exp = DataFrame(exp, columns=['task_num','task_name', 'trial_type', 'trial_num', 'terminalfeedback_bool','rotation_angle','targetangle_deg','targetdistance_percmax','homex_px','homey_px','targetx_px','targety_px', 'time_s', 'mousex_px', 'mousey_px', 'cursorx_px', 'cursory_px', 'accuracy_reward', 'accuracy_reward_bool'])
df_exp = DataFrame(exp, columns=['task_num','task_name', 'trial_type', 'trial_num', 'terminalfeedback_bool','rotation_angle','targetangle_deg','targetdistance_percmax','homex_px','homey_px','targetx_px','targety_px', 'time_s', 'mousex_px', 'mousey_px', 'cursorx_px', 'cursory_px', 'accuracy_reward', 'accuracy_reward_bool', 'pre_reach_aim'])
df_exp.to_csv(path_or_buf = path.join("data", settings['experiment_folder'], participant, running[i]['task_name'] + "_" + str(trial_num) + ".csv"), index=False)
end_exp = concat([end_exp, df_exp])

Expand Down
Loading