diff --git a/Images/AntiSaccadeInstruct2.tif b/Images/AntiSaccadeInstruct2.tif new file mode 100644 index 0000000..1691dcc Binary files /dev/null and b/Images/AntiSaccadeInstruct2.tif differ diff --git a/Images/BinocularRivalryImages/face2nC_11-160.tif b/Images/BinocularRivalryImages/face2nC_11-160.tif deleted file mode 100755 index bded802..0000000 Binary files a/Images/BinocularRivalryImages/face2nC_11-160.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/face2nS_11-160.tif b/Images/BinocularRivalryImages/face2nS_11-160.tif deleted file mode 100755 index 76bee28..0000000 Binary files a/Images/BinocularRivalryImages/face2nS_11-160.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/face2n_11-160.tif b/Images/BinocularRivalryImages/face2n_11-160.tif deleted file mode 100755 index 1241c31..0000000 Binary files a/Images/BinocularRivalryImages/face2n_11-160.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/grating_180.tif b/Images/BinocularRivalryImages/grating_180.tif deleted file mode 100755 index 150187d..0000000 Binary files a/Images/BinocularRivalryImages/grating_180.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/grating_90.tif b/Images/BinocularRivalryImages/grating_90.tif deleted file mode 100755 index e18fde4..0000000 Binary files a/Images/BinocularRivalryImages/grating_90.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/horizontal.tif b/Images/BinocularRivalryImages/horizontal.tif deleted file mode 100755 index a972f4b..0000000 Binary files a/Images/BinocularRivalryImages/horizontal.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/horizontal_hi.tif b/Images/BinocularRivalryImages/horizontal_hi.tif deleted file mode 100755 index 308823d..0000000 Binary files a/Images/BinocularRivalryImages/horizontal_hi.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/horizontal_lo.tif b/Images/BinocularRivalryImages/horizontal_lo.tif deleted file mode 100755 index c734dca..0000000 Binary files a/Images/BinocularRivalryImages/horizontal_lo.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/house.tif b/Images/BinocularRivalryImages/house.tif deleted file mode 100755 index 208c7d8..0000000 Binary files a/Images/BinocularRivalryImages/house.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/house3n_11-130.tif b/Images/BinocularRivalryImages/house3n_11-130.tif deleted file mode 100755 index 48304f2..0000000 Binary files a/Images/BinocularRivalryImages/house3n_11-130.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/house3n_11-160.tif b/Images/BinocularRivalryImages/house3n_11-160.tif deleted file mode 100755 index 242e402..0000000 Binary files a/Images/BinocularRivalryImages/house3n_11-160.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/house3n_21-140.tif b/Images/BinocularRivalryImages/house3n_21-140.tif deleted file mode 100755 index 0362fe0..0000000 Binary files a/Images/BinocularRivalryImages/house3n_21-140.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/house4.tif b/Images/BinocularRivalryImages/house4.tif deleted file mode 100755 index 29ed0fa..0000000 Binary files a/Images/BinocularRivalryImages/house4.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/house4n_11-160.tif b/Images/BinocularRivalryImages/house4n_11-160.tif deleted file mode 100755 index 3f99a7e..0000000 Binary files a/Images/BinocularRivalryImages/house4n_11-160.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/leftA.tif b/Images/BinocularRivalryImages/leftA.tif deleted file mode 100755 index c51f6ec..0000000 Binary files a/Images/BinocularRivalryImages/leftA.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/leftA_hi.tif b/Images/BinocularRivalryImages/leftA_hi.tif deleted file mode 100755 index 40362fd..0000000 Binary files a/Images/BinocularRivalryImages/leftA_hi.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/leftA_lo.tif b/Images/BinocularRivalryImages/leftA_lo.tif deleted file mode 100755 index ccc3af8..0000000 Binary files a/Images/BinocularRivalryImages/leftA_lo.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/man.tif b/Images/BinocularRivalryImages/man.tif deleted file mode 100755 index f866070..0000000 Binary files a/Images/BinocularRivalryImages/man.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/rightA.tif b/Images/BinocularRivalryImages/rightA.tif deleted file mode 100755 index a130851..0000000 Binary files a/Images/BinocularRivalryImages/rightA.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/rightA_hi.tif b/Images/BinocularRivalryImages/rightA_hi.tif deleted file mode 100755 index 2471533..0000000 Binary files a/Images/BinocularRivalryImages/rightA_hi.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/rightA_lo.tif b/Images/BinocularRivalryImages/rightA_lo.tif deleted file mode 100755 index 5f6dfff..0000000 Binary files a/Images/BinocularRivalryImages/rightA_lo.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/vertical.tif b/Images/BinocularRivalryImages/vertical.tif deleted file mode 100755 index 140a48b..0000000 Binary files a/Images/BinocularRivalryImages/vertical.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/vertical_hi.tif b/Images/BinocularRivalryImages/vertical_hi.tif deleted file mode 100755 index 6dea6f5..0000000 Binary files a/Images/BinocularRivalryImages/vertical_hi.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/vertical_lo.tif b/Images/BinocularRivalryImages/vertical_lo.tif deleted file mode 100755 index 2e11e61..0000000 Binary files a/Images/BinocularRivalryImages/vertical_lo.tif and /dev/null differ diff --git a/Images/BinocularRivalryImages/woman.tif b/Images/BinocularRivalryImages/woman.tif deleted file mode 100755 index ef7fb37..0000000 Binary files a/Images/BinocularRivalryImages/woman.tif and /dev/null differ diff --git a/Images/Necker1.png b/Images/Necker1.png deleted file mode 100644 index 708b5fb..0000000 Binary files a/Images/Necker1.png and /dev/null differ diff --git a/Images/ResponseBox1.tif b/Images/ResponseBox1.tif deleted file mode 100644 index 2d9ab94..0000000 Binary files a/Images/ResponseBox1.tif and /dev/null differ diff --git a/Images/ResponseBox2.tif b/Images/ResponseBox2.tif deleted file mode 100644 index e576125..0000000 Binary files a/Images/ResponseBox2.tif and /dev/null differ diff --git a/Images/ResponseBox4.tif b/Images/ResponseBox4.tif deleted file mode 100644 index 2290155..0000000 Binary files a/Images/ResponseBox4.tif and /dev/null differ diff --git a/Images/ResponseBox4.xcf b/Images/ResponseBox4.xcf deleted file mode 100644 index b284fdc..0000000 Binary files a/Images/ResponseBox4.xcf and /dev/null differ diff --git a/SaccadePursuit.py b/SaccadePursuit.py index 82653ce..fbaa27c 100755 --- a/SaccadePursuit.py +++ b/SaccadePursuit.py @@ -50,18 +50,6 @@ data_fields = [ 'Locations', ] -gender_options = [ - 'Male', - 'Female', - 'Other/Choose Not To Respond', -] - -# Add additional questions here -questionaire_dict = { - 'Age': 0, - 'Gender': gender_options, -} - def warning_on_one_line(message, category, filename, lineno, file=None, line=None): return ' %s:%s: %s:%s' % (filename, lineno, category.__name__, message) @@ -90,7 +78,9 @@ class SPtask(template.BaseExperiment): rivalry_scale,rivalry_border_color, rivalry_border_width, rivalry_distance, new_trial_sound, - questionaire_dict=questionaire_dict, **kwargs): + questionaire_dict=None, + questionaire_order=None, + **kwargs): self.new_trial_sound = new_trial_sound @@ -253,8 +243,8 @@ class SPtask(template.BaseExperiment): tempCoord = circleN+1 tempStim = psychopy.visual.Circle( self.experiment_window, radius=self.stimulus_size/2, - pos=[tempCoord,0], fillColor=self.saccade_fixation_color, - lineColor=self.saccade_fixation_color, units='deg') + pos=[tempCoord,0], fillColor=self.saccade_dot_color, + lineColor=self.saccade_dot_color, units='deg') stimList.append(tempStim) for frameN in range(int(round(stim_time*60))): @@ -286,8 +276,8 @@ class SPtask(template.BaseExperiment): tempCoord = circleN+1 tempStim = psychopy.visual.Circle( self.experiment_window, radius=self.stimulus_size/2, - pos=[tempCoord,0], fillColor=self.saccade_fixation_color, - lineColor=self.saccade_fixation_color, units='deg') + pos=[tempCoord,0], fillColor=self.saccade_dot_color, + lineColor=self.saccade_dot_color, units='deg') stimList.append(tempStim) for frameN in range(int(round(stim_time*60))): diff --git a/SaccadePursuitEyeTracking.py b/SaccadePursuitEyeTracking.py index 5108ef5..4ede059 100755 --- a/SaccadePursuitEyeTracking.py +++ b/SaccadePursuitEyeTracking.py @@ -32,8 +32,6 @@ monitor_px = [1440,900] window_screen = 1 disableTracker = True # For Debugging -conditions = ['Fixation', 'Pursuit', 'Saccade', 'AntiSaccade', 'Necker'] #, 'Rivalry'] -#conditions = ['Necker'] isi_time = 2 # Interstimulus Interval data_directory = os.path.join( os.path.expanduser('~'), 'Desktop', 'ExperimentalData', 'SaccadePursuitEyeTracking') @@ -47,7 +45,10 @@ saccade_distance = 15 # Degrees per direction saccade_time = 3 # Maximum Time stimulus_size = 0.3 stim_color = [1,-1,-1] -saccade_fixation_color = [100,100,100] +saccade_fixation_color = [255,255,255] +saccade_dot_color = [100,100,100] +antisaccade_instruct_file = os.path.join(image_directory,'AntiSaccadeInstruct2.tif') +antisaccade_file_scale = 2.5 # Pursuit Parameters number_of_pursuit_trials = 1 @@ -98,8 +99,31 @@ data_fields = [ 'Locations', ] +# Add additional questions here +questionaire_dict = { + 'Run Fixation': True, + 'Run Smooth Pursuit': True, + 'Run Saccade': True, + 'Run Anti-Saccade': True, + 'Run Necker Cube': True, + 'Run Binocular Rivalry': False, +} + +questionaire_order=[ + 'Subject Identifier', + 'Age', + 'Experimenter Initials', + 'Gender', + 'Run Fixation', + 'Run Smooth Pursuit', + 'Run Saccade', + 'Run Anti-Saccade', + 'Run Necker Cube', + 'Run Binocular Rivalry', +] + instruct_text = [ - ('Welcome to the experiment. Press space to continue.'), + ('Welcome to the experiment. Press any key to continue.'), ('In this experiment you will be following targets.\n\n' 'Each trial will start with a fixation cross. ' 'Focus on the fixation cross until a stimulus appears.\n\n' @@ -112,61 +136,80 @@ instruct_text = [ '\n\n' 'Do not move your head during the trials of this ' 'experiment. Move only your eyes to follow the targets.' - 'You will get breaks in between blocks.\n\n' + 'You will be offered breaks in between sections.\n\n' 'Press any key to continue.'), ] saccade_instruct_text = ( - 'For these trials, focus on the fixation cross. When the target ' - 'appears, move your gaze to the target. Move your gaze back to ' - 'the fixation point after the target disappears.\n\n' - 'Try not to blink after the target appears.\n\n' + 'For this experiment, we want to know how accurately your ' + 'eyes can move from one position to another. You will see ' + 'many gray dots and a cross on the screen. Please focus on ' + 'the fixation cross in the beginning. When the red dot ' + 'appears, move your eyes to the red dot as quickly as ' + 'possible and fixate on the red dot. When you hear a sound, ' + 'move your eyes back to the fixation cross.\n\n' + 'Try not to blink while a red dot is displayed.\n\n' + 'You can then blink or close your eyes to rest for a few seconds.\n\n' 'Press any key to continue.' ) antisaccade_instruct_text = ( - 'For these trials, focus on the fixation cross. When the target ' - 'appears, move your gaze to the OPPOSITE direction of the target ' - 'at approximately the same distance from the fixation cross as ' - 'the target. Move your gaze back to the fixation point after ' - 'the target disappears.\n\n' - 'Try not to blink after the target appears.\n\n' + 'For this experiment, we also want to know how accurately your ' + 'eyes can move from one point to another. Please focus on the ' + 'fixation cross. When the red dot appears, move your eyes to ' + 'the OPPOSITE direction of the target at approximately the ' + 'same distance from the fixation cross as the target as shown ' + 'by the arrow in the image below this text. The arrow will ' + 'not be present during the experiment. Move your eyes back ' + 'to the fixation point after each target disappears.\n\n' + 'Try not to blink while a red dot is displayed.\n\n' + 'You can then blink or close your eyes to rest for a few seconds.\n\n' 'Press any key to continue.' ) pursuit_instruct_text = ( - 'For these trials, when the circle target appears, follow the ' - 'target with your eyes.\n\n' - 'Try not to blink while the circle is moving.\n\n' + 'For this experiment, we want to know how well your eyes can ' + 'follow a target at different speeds. Please fixate the cross. ' + 'When the dot appears, follow the target with your eyes. You ' + 'will hear a sound when the trial is done. You may blink ' + 'until the next trial begins. A new trial will begin after ' + 'two seconds.\n\n' + 'Try not to blink while the dot is moving.\n\n' + 'You can then blink or close your eyes to rest for a few seconds.\n\n' 'Press any key to continue.' ) fixation_instruct_text = ( - 'For these trials, when the cross appears, fixate on it.\n\n' - 'Try not to move your eyes from the cross while it ' - 'remains visible.\n\n' + 'For this experiment, we want to know how well you can keep ' + 'your eyes fixed on a target without moving. When the cross ' + 'appears, please fixate on it.\n\n' + 'Try not to move your eyes from the cross or blink until it ' + 'disappears.\n\n' + 'You can then blink or close your eyes to rest for a few seconds.\n\n' 'Press any key to continue.' ) necker_instruct_text = ( - 'For these trials, focus on the square. When your ' - 'perception is that the square is pointing down and ' - 'to the left, press the left button. As soon as it ' - 'switches to up and to the right, press the right ' - 'button.\n\n' + 'For this experiment, focus on the square. When you see the ' + 'square is pointing down and to the left, press the left ' + 'button. As soon as it switches to up and to the right, ' + 'press the right button. Refer to the image below this ' + 'text. The center button is not used during this experiment.\n\n' 'Respond at any time during the stimulus.\n\n' + 'Try not to blink after the cube appears.\n\n' + 'You can blink or close your eyes to rest after the cube ' + 'disappears.\n\n' 'Press any key to continue.' ) rivalry_instruct_text = ( - 'For these trials, the experimenter will move a ' - 'system in front of your field of view. Look through ' - 'the mirrors to see a different image in each eye.\n\n' - 'If you perceive a face, press the right button. If ' - 'you perceive a house, press the left button. If ' - 'you perceive a combination of the face and house, ' - 'press the middle button.\n\n' - 'Respond at any time during the stimuli.\n\n' + 'For this experiment, you will see different images in your ' + 'left and right eyes through the mirrors.\n\n' + 'If you see a face, press the right button. If you see a ' + 'house, press the left button. If you perceive a mixture of ' + 'the face and house, press the center button.\n\n' + 'You can blink or close your eyes to rest for a few seconds ' + 'after the pictures disappear.\n\n' 'Press any key to continue.' ) @@ -201,6 +244,8 @@ class EyeTrackingSaccadePursuit(SaccadePursuit.SPtask): self.necker_response_box_file = necker_response_box_file self.necker_response_box_scale = necker_response_box_scale self.response_box_scale = response_box_scale + self.antisaccade_instruct_file = antisaccade_instruct_file + self.antisaccade_file_scale = antisaccade_file_scale super(EyeTrackingSaccadePursuit, self).__init__(**kwargs) @@ -222,12 +267,28 @@ class EyeTrackingSaccadePursuit(SaccadePursuit.SPtask): self.chdir() print('Note: EDF file will be overwritten if identical subject identifiers are used!') - ok = self.get_experiment_info_from_dialog(self.questionaire_dict) + ok = self.get_experiment_info_from_dialog( + additional_fields_dict=questionaire_dict, + field_order=questionaire_order) if not ok: print('Experiment has been terminated.') sys.exit(1) + conditions = [] + if self.experiment_info['Run Fixation']: + conditions.append('Fixation') + if self.experiment_info['Run Smooth Pursuit']: + conditions.append('Pursuit') + if self.experiment_info['Run Saccade']: + conditions.append('Saccade') + if self.experiment_info['Run Anti-Saccade']: + conditions.append('AntiSaccade') + if self.experiment_info['Run Necker Cube']: + conditions.append('Necker') + if self.experiment_info['Run Binocular Rivalry']: + conditions.append('Rivalry') + self.save_experiment_info() self.open_csv_data_file() self.open_window(screen=self.window_screen) @@ -252,10 +313,10 @@ class EyeTrackingSaccadePursuit(SaccadePursuit.SPtask): self.tracker.display_eyetracking_instructions() self.tracker.setup_tracker() - #random.shuffle(self.conditions) + #random.shuffle(conditions) condition_counter = 0 - for condition in self.conditions: + for condition in conditions: condition_counter += 1 numBlocks = 1 numTrials = 1 @@ -264,7 +325,9 @@ class EyeTrackingSaccadePursuit(SaccadePursuit.SPtask): numBlocks = self.number_of_saccade_blocks numTrials = self.number_of_saccade_trials elif condition=='AntiSaccade': - self.display_text_screen(text=antisaccade_instruct_text) + self.display_text_screen(text=antisaccade_instruct_text, + image_file = antisaccade_instruct_file, + image_scale = self.antisaccade_file_scale) numBlocks = self.number_of_saccade_blocks numTrials = self.number_of_saccade_trials elif condition=='Fixation': @@ -301,7 +364,7 @@ class EyeTrackingSaccadePursuit(SaccadePursuit.SPtask): for trial_num, trial in enumerate(block): print( - "Condition: ",condition,"(",condition_counter,"/",len(self.conditions),")", + "Condition: ",condition,"(",condition_counter,"/",len(conditions),")", "Block ",block_num+1,"/",numBlocks, " Trial ",trial_num+1,"/",len(block) ) @@ -335,7 +398,9 @@ class EyeTrackingSaccadePursuit(SaccadePursuit.SPtask): if condition == 'Saccade': self.display_text_screen(text='Remember:\n\n' + saccade_instruct_text) elif condition=='AntiSaccade': - self.display_text_screen(text='Remember:\n\n' + antisaccade_instruct_text) + self.display_text_screen(text='Remember:\n\n' + antisaccade_instruct_text, + image_file = antisaccade_instruct_file, + image_scale = self.antisaccade_file_scale) elif condition=='Fixation': self.display_text_screen(text='Remember:\n\n' + fixation_instruct_text) elif condition=='Pursuit': @@ -368,12 +433,12 @@ experiment = EyeTrackingSaccadePursuit( monitor_width=monitor_width, monitor_px=monitor_px, monitor_distance=distance_to_monitor, - conditions=conditions, pursuit_time=pursuit_time, stim_color=stim_color, pursuit_frequencies=pursuit_frequencies, saccade_distance=saccade_distance, saccade_time=saccade_time, saccade_fixation_color=convert_color_value(saccade_fixation_color), + saccade_dot_color = convert_color_value(saccade_dot_color), isi_time=isi_time, stimulus_size=stimulus_size, fixation_size=fixation_size, pursuit_distance=pursuit_distance, diff --git a/__pycache__/SaccadePursuitEyeTracking.cpython-36.pyc b/__pycache__/SaccadePursuitEyeTracking.cpython-36.pyc index 8f85909..2125d2a 100644 Binary files a/__pycache__/SaccadePursuitEyeTracking.cpython-36.pyc and b/__pycache__/SaccadePursuitEyeTracking.cpython-36.pyc differ diff --git a/template.py b/template.py index 8978399..1256a44 100755 --- a/template.py +++ b/template.py @@ -25,6 +25,11 @@ import psychopy.gui import psychopy.core import psychopy.event +gender_options = [ + 'Male', + 'Female', + 'Other/Choose Not To Respond', +] # Convenience def convert_color_value(color): @@ -97,6 +102,7 @@ class BaseExperiment(object): self.experiment_window = None self.overwrite_ok = None + self.gender_options = gender_options self.experiment_monitor = psychopy.monitors.Monitor( self.monitor_name, width=self.monitor_width, @@ -121,7 +127,7 @@ class BaseExperiment(object): return overwrite_dlg.OK - def get_experiment_info_from_dialog(self, additional_fields_dict=None): + def get_experiment_info_from_dialog(self, additional_fields_dict=None, field_order=None): """Gets subject info from dialog box. Parameters: @@ -132,18 +138,22 @@ class BaseExperiment(object): self.experiment_info = {'Subject Identifier': 'XX00', 'Age': '0', 'Experimenter Initials': 'MT', + 'Gender': self.gender_options, } if additional_fields_dict is not None: self.experiment_info.update(additional_fields_dict) + if field_order is None: + field_order=['Subject Identifier', + 'Age', + 'Experimenter Initials', + 'Gender', + ] # Modifies experiment_info dict directly exp_info = psychopy.gui.DlgFromDict( self.experiment_info, title=self.experiment_name, - order=['Subject Identifier', - 'Age', - 'Experimenter Initials', - ], + order=field_order, screen=0 )