def __init__(self, width, diameter=60, fills={}, ticks=None, location=None): self.width = width self.ticks = ticks self.location = location if location else P.screen_c _fills = {'line': MED_GREY, 'slider': TRANSLUCENT_BLUE} _fills.update(fills) # override default colours if fills provided self.line = kld.Rectangle(width, 2, fill=_fills['line']) self.tick = kld.Rectangle(2, int(diameter/2), fill=_fills['line']) self.button = kld.Ellipse(diameter, fill=_fills['slider']) self.__clicked = False self.__dragging = False self.__drag_offset = 0 self.__abs_pos = self.location
def __init__(self, first, last, width, height, style, registration=None, location=None): BoundaryInspector.__init__(self) self.range = range(first, last+1, 1) self.count = len(self.range) self.response = None self.height = height self.width = width self.circle_size = self.height self.gap = (width - self.circle_size * self.count) / (self.count - 1) self.__location = location if location else P.screen_c self.__registration = registration if registration else 5 self.__init_bounds() numlist = [] for num in self.range: num_txt = message("{0}".format(num), style, blit_txt=False) numlist.append((num, num_txt)) self.numbers = dict(numlist) self.selected = kld.Ellipse(self.circle_size-4, fill=TRANSLUCENT_GREY) self.mouseover = self.selected#kld.Annulus(self.circle_size-4, 6, fill=MED_GREY)
def __init__(self, msg, width, height=None, registration=5, location=None): self.width = width self.height = height if height else width self.hover = kld.Rectangle(self.width, self.height, fill=TRANSLUCENT_GREY) self.msg = msg self.__registration = registration self.__location = location if location else P.screen_c self.__init_bounds()
def setup(self): # Stimulus sizes fixation_size = deg_to_px(0.32) fixation_thickness = deg_to_px(0.08) cue_size = deg_to_px(0.64) cue_thickness = deg_to_px(0.08) arrow_tail_len = deg_to_px(0.48) arrow_tail_width = deg_to_px(0.15) arrow_head_len = deg_to_px(0.25) arrow_head_width = deg_to_px(0.45, even=True) arrow_dimensions = [ arrow_tail_len, arrow_tail_width, arrow_head_len, arrow_head_width ] # Stimuli self.warning_tone = Tone(50, 'sine', frequency=2000, volume=0.5) self.fixation = kld.FixationCross(fixation_size, fixation_thickness, fill=WHITE) self.cue = kld.Asterisk(cue_size, thickness=cue_thickness, fill=WHITE, spokes=8) self.arrow_r = kld.Arrow(*arrow_dimensions, fill=WHITE) self.arrow_l = kld.Arrow(*arrow_dimensions, fill=WHITE, rotation=180) self.arrow_r.render() self.arrow_l.render() # Layout self.height_offset = deg_to_px(1.3) self.flanker_offset = arrow_tail_len + arrow_head_len + deg_to_px(0.16) self.above_loc = (P.screen_c[0], P.screen_c[1] - self.height_offset) self.below_loc = (P.screen_c[0], P.screen_c[1] + self.height_offset) self.cue_locations = {'above': self.above_loc, 'below': self.below_loc} # Insert practice block (when applicable) if P.run_practice_blocks: self.insert_practice_block(block_nums=1, trial_counts=24) self.instructions_presented = False
def present_spatial_array(self, spatial_array): fill() blit(self.fixation, registration=5, location=P.screen_c) if P.development_mode: c = kld.Annulus(deg_to_px(1.0), deg_to_px(0.1), fill=(255, 0, 0, 255)) blit(c, registration=5, location=self.target_loc) for item in spatial_array: blit(item[0], registration=5, location=item[1]) flip()
def _render(self): blit(self.q, location=self.origin, registration=8) for ans in self.order: a = self.answers[ans] ax, ay = a['location'] blit(a['text'], location=(ax, ay + int(self.q_pad*0.55)), registration=8) mouseover = self.which_boundary(mouse_pos()) if mouseover != None: a = self.answers[mouseover] hover = kld.Rectangle(self.width, a['height'], fill=TRANSLUCENT_GREY).render() blit(hover, 8, a['location'])
def test_mask(): # Initialize test surface and masks # NOTE: Testing KLDraw objects further down, since KLD rectangles have 1px # transparent padding that breaks this test loop's logic surface = NumpySurface(width=100, height=100, fill=[255, 0, 0]) nps_mask = NumpySurface(width=50, height=50, fill=[255, 255, 255]) np_mask = nps_mask.render() greyscale_mask = Image.new('L', (50, 50), 0) ImageDraw.Draw(greyscale_mask).rectangle((0, 0, 50, 50), fill=255) rgb_mask = Image.new('RGB', (50, 50), (0, 0, 0)) ImageDraw.Draw(rgb_mask).rectangle((0, 0, 50, 50), fill=(255, 0, 0)) # Test different mask types for mask in [nps_mask, np_mask, greyscale_mask, rgb_mask]: surf = surface.copy() surf.mask(mask, registration=7, location=(0, 0)) assert surf.content[49][49][3] == 0 assert surf.content[50][50][3] == 255 # Test legacy positioning surf = surface.copy() surf.mask(nps_mask, (25, 25)) assert surf.content[0][0][3] == 255 and surf.content[25][25][3] == 0 # Test with mask partially off surface surf = surface.copy() surf.mask(nps_mask, registration=3, location=(25, 25)) assert surf.content[24][24][3] == 0 and surf.content[25][25][3] == 255 surf.mask(nps_mask, registration=7, location=(75, 75)) assert surf.content[74][74][3] == 255 and surf.content[75][75][3] == 0 # Test inverse/non-inverse modes and complete masking circle_mask = kld.Ellipse(50, fill=(255, 255, 255)) for complete in [True, False]: surf = surface.copy() surf.mask(circle_mask, location=(0, 0), invert=True, complete=complete) assert surf.content[0][0][3] == 255 and surf.content[25][25][3] == 0 assert surf.content[-1][-1][3] == (0 if complete else 255) surf = surface.copy() surf.mask(circle_mask, location=(0, 0), invert=False, complete=complete) assert surf.content[0][0][3] == 0 and surf.content[25][25][3] == 255 assert surf.content[-1][-1][3] == (0 if complete else 255) # Test exception for invalid mask type with pytest.raises(TypeError): surf = surface.copy() surf.mask("hello")
def setup(self): self.fix_size = deg_to_px(0.8) self.fix_thickness = deg_to_px(0.1) self.item_size = deg_to_px(0.8) self.fixation = kld.FixationCross(size=self.fix_size, thickness=self.fix_thickness, fill=WHITE) # Create array of possible stimulus locations for spatial search # When it comes time to present stimuli, a random jitter will be applied # to each item presented. locs = [] offset = deg_to_px(3.0) for x in range(0, 3): for y in range(0, 3): locs.append( [P.screen_c[0] + offset * x, P.screen_c[1] + offset * y]) locs.append( [P.screen_c[0] - offset * x, P.screen_c[1] - offset * y]) locs.append( [P.screen_c[0] + offset * x, P.screen_c[1] - offset * y]) locs.append( [P.screen_c[0] - offset * x, P.screen_c[1] + offset * y]) locs.sort() self.spatial_array_locs = list(loc for loc, _ in itertools.groupby(locs)) self.spatial_array_locs.remove([P.screen_c[0], P.screen_c[1]]) coinflip = random.choice([True, False]) if coinflip: self.present_key, self.absent_key = 'z', '/' self.keymap = KeyMap("response", ['z', '/'], [PRESENT, ABSENT], [sdl2.SDLK_z, sdl2.SDLK_SLASH]) else: self.present_key, self.absent_key = '/', 'z' self.keymap = KeyMap("response", ['/', 'z'], [PRESENT, ABSENT], [sdl2.SDLK_SLASH, sdl2.SDLK_z]) self.anykey_txt = "{0}\n\nPress any key to continue..." self.general_instructions = ( "In this experiment you will see a series of items, amongst these items\n" "a target item may, or may not, be presented.\n If you see the target item " "press the '{0}' key, if the target item wasn't presented press the '{1}' instead.\n\n" "The experiment will begin with a few practice rounds to give you a sense of the task." ).format(self.present_key, self.absent_key) self.spatial_instructions = ( "Searching in Space!\n\nIn these trials you will see a bunch of items scattered" "around the screen.\nIf one of them is the target, press the '{0}' key as fast as possible." "\nIf none of them are the target, press the '{1}' key as fast as possible." ).format(self.present_key, self.absent_key) self.temporal_instructions = ( "Searching in Time!\n\nIn these trials you will see a series of items presented one\n" "at a time, centre-screen. If one of these items is the target, press the '{0}' key.\n" "If, by the end, none of them was the target, press the '{1}' key instead." ).format(self.present_key, self.absent_key) # Setup search conditions (blocked) self.spatial_conditions = [[HIGH, LOW], [HIGH, HIGH], [LOW, HIGH], [LOW, LOW]] random.shuffle(self.spatial_conditions) self.temporal_conditions = [[HIGH, LOW], [HIGH, HIGH], [LOW, HIGH], [LOW, LOW]] random.shuffle(self.temporal_conditions) self.practice_conditions = [[HIGH, LOW], [HIGH, HIGH], [LOW, HIGH], [LOW, LOW]] random.shuffle(self.practice_conditions) self.search_type = random.choice([SPACE, TIME]) if P.run_practice_blocks: self.insert_practice_block( block_nums=[1, 2, 3, 4], trial_counts=P.trials_per_practice_block) general_msg = self.anykey_txt.format(self.general_instructions) self.blit_msg(general_msg, "left") any_key()
def create_stimuli(self, tdSimilarity, ddSimilarity): # Setup target properties if P.condition == 'line': self.target_angle = random.randint(0, 179) self.target_height = deg_to_px(0.1) self.target_fill = WHITE self.target_item = kld.Rectangle(width=self.item_size, height=self.target_height, fill=WHITE, rotation=self.target_angle) if tdSimilarity == HIGH: self.ref_angle = self.target_angle else: self.ref_angle = self.target_angle + 90 self.mask = kld.Asterisk(size=self.item_size, thickness=self.target_height, fill=WHITE, spokes=12) else: self.target_height = self.item_size self.palette = kld.ColorWheel(diameter=self.item_size) self.target_angle = random.randint(0, 359) self.target_colour = self.palette.color_from_angle( self.target_angle) self.target_item = kld.Rectangle(width=self.item_size, height=self.target_height, fill=self.target_colour) if tdSimilarity == HIGH: self.ref_angle = self.target_angle else: self.ref_angle = self.target_angle + 180 self.mask = kld.Rectangle(width=self.item_size, fill=WHITE) # Setup distractor(s) properties if ddSimilarity == HIGH: padding = [random.choice([-20, 20])] else: padding = [-40, -20, 20, 40] self.distractors = [] if P.condition == 'line': for p in padding: rotation = self.ref_angle + p self.distractors.append( kld.Rectangle(width=self.item_size, height=self.target_height, fill=WHITE, rotation=rotation)) else: for p in padding: colour = self.palette.color_from_angle(self.ref_angle + p) self.distractors.append( kld.Rectangle(width=self.item_size, height=self.target_height, fill=colour))
def setup(self): # Font styles for feedback self.txtm.add_style(label='correct', color=WHITE) self.txtm.add_style(label='incorrect', color=RED) # Stimulus properties # # Placeholder(s) placeholder_size = deg_to_px(2.0) uncued_thick = deg_to_px(0.2) cued_thick = deg_to_px(0.5) self.cued_stroke = [cued_thick, WHITE, STROKE_CENTER] self.uncued_stroke = [uncued_thick, WHITE, STROKE_CENTER] # Tone tone_type = 'sine' tone_duration = 50 # ms tone_volume = 0.6 # moderate volume # Fixation fix_size = deg_to_px(0.8) fix_thick = deg_to_px(0.1) # Target target_size = deg_to_px(0.8) # Stimlus construction self.fixation = kld.FixationCross(size=fix_size, thickness=fix_thick, fill=WHITE) self.audio_tone = Tone(duration=tone_duration, wave_type=tone_type, volume=tone_volume) self.target = kld.Circle(diameter=target_size, fill=WHITE) self.box_left = kld.Rectangle(width=placeholder_size, stroke=self.uncued_stroke) self.box_right = kld.Rectangle(width=placeholder_size, stroke=self.uncued_stroke) # Stimulus locations offset = deg_to_px(4.0) if P.development_mode else deg_to_px(8.0) # Normal offset too wide for my laptop self.locs = { TOP_LEFT: [P.screen_c[0] - offset, P.screen_c[1] - offset], TOP_RIGHT: [P.screen_c[0] + offset, P.screen_c[1] - offset], BOTTOM_LEFT: [P.screen_c[0] - offset, P.screen_c[1] + offset], BOTTOM_RIGHT: [P.screen_c[0] + offset, P.screen_c[1] + offset] } coinflip = random.choice([True, False]) if coinflip: self.left_key, self.right_key = 'up', 'down' self.keymap = KeyMap( "response", ['left', 'right'], [LEFT, RIGHT], [sdl2.SDLK_UP, sdl2.SDLK_DOWN] ) else: self.left_key, self.right_key = 'down', 'up' self.keymap = KeyMap( "response", ['left', 'right'], [LEFT, RIGHT], [sdl2.SDLK_DOWN, sdl2.SDLK_UP] ) factor_mask = {'cue_type': ['vis_left', 'vis_right', 'temporal', 'temporal', 'no_cue', 'no_cue'], 'tone_trial': [True, False]} self.ctoa_practice = [100, 250, 850] self.ctoa_testing = [100, 250, 850] random.shuffle(self.ctoa_practice) random.shuffle(self.ctoa_testing) self.insert_practice_block(block_nums=[1, 2, 3], trial_counts=12, factor_mask=factor_mask)
def setup(self): box_size = deg_to_px(1.8) box_thick = deg_to_px(0.05) stim_size = deg_to_px(0.95) stim_thick = deg_to_px(0.1) fix_size = deg_to_px(1) fix_offset = deg_to_px(2.8) box_stroke = [box_thick, WHITE, STROKE_CENTER] self.txtm.add_style(label='greentext', color=GREEN) self.target = kld.Annulus(diameter=stim_size, thickness=stim_thick, fill=WHITE) self.distractor = kld.FixationCross(size=stim_size, thickness=stim_thick, fill=WHITE) # Set the rotation of placeholder boxes & fixation to match that of the display (diamond, square) rotate = 45 if P.condition == 'diamond' else 0 self.placeholder = kld.Rectangle(width=box_size, stroke=box_stroke, rotation=rotate) self.fixation = kld.Asterisk(size=fix_size, thickness=stim_thick, fill=WHITE, rotation=rotate, spokes=8) # Which locations are labelled far or near is dependent on arrangement of display # 'near' locations refer to those that lie at the intersection of 'far' locations if P.condition == 'square': self.far_locs = { 1: [ point_pos(P.screen_c, amplitude=fix_offset, angle=315, clockwise=True), 'NorthEast' ], 2: [ point_pos(P.screen_c, amplitude=fix_offset, angle=45, clockwise=True), 'SouthEast' ], 3: [ point_pos(P.screen_c, amplitude=fix_offset, angle=135, clockwise=True), 'SouthWest' ], 4: [ point_pos(P.screen_c, amplitude=fix_offset, angle=225, clockwise=True), 'NorthWest' ] } self.near_locs = { 5: [midpoint(self.far_locs[4][0], self.far_locs[1][0]), 'North'], 6: [midpoint(self.far_locs[1][0], self.far_locs[2][0]), 'East'], 7: [midpoint(self.far_locs[3][0], self.far_locs[2][0]), 'South'], 8: [midpoint(self.far_locs[3][0], self.far_locs[4][0]), 'West'] } else: # if P.condition == 'diamond' self.far_locs = { 1: [ point_pos(P.screen_c, amplitude=fix_offset, angle=270, clockwise=True), 'North' ], 2: [ point_pos(P.screen_c, amplitude=fix_offset, angle=0, clockwise=True), 'East' ], 3: [ point_pos(P.screen_c, amplitude=fix_offset, angle=90, clockwise=True), 'South' ], 4: [ point_pos(P.screen_c, amplitude=fix_offset, angle=180, clockwise=True), 'West' ] } self.near_locs = { 5: [ midpoint(self.far_locs[4][0], self.far_locs[1][0]), 'NorthWest' ], 6: [ midpoint(self.far_locs[1][0], self.far_locs[2][0]), 'NorthEast' ], 7: [ midpoint(self.far_locs[3][0], self.far_locs[2][0]), 'SouthEast' ], 8: [ midpoint(self.far_locs[3][0], self.far_locs[4][0]), 'SouthWest' ] } if not P.development_mode: self.keymap = KeyMap('directional_response', [ 'North', 'NorthEast', 'East', 'SouthEast', 'South', 'SouthWest', 'West', 'NorthWest' ], [ 'North', 'NorthEast', 'East', 'SouthEast', 'South', 'SouthWest', 'West', 'NorthWest' ], [ sdl2.SDLK_KP_8, sdl2.SDLK_KP_9, sdl2.SDLK_KP_6, sdl2.SDLK_KP_3, sdl2.SDLK_KP_2, sdl2.SDLK_KP_1, sdl2.SDLK_KP_4, sdl2.SDLK_KP_7 ]) else: # Don't have a numpad myself, so I need an alternative when developing self.keymap = KeyMap('directional_response', [ 'North', 'NorthEast', 'East', 'SouthEast', 'South', 'SouthWest', 'West', 'NorthWest' ], [ 'North', 'NorthEast', 'East', 'SouthEast', 'South', 'SouthWest', 'West', 'NorthWest' ], [ sdl2.SDLK_i, sdl2.SDLK_o, sdl2.SDLK_l, sdl2.SDLK_PERIOD, sdl2.SDLK_COMMA, sdl2.SDLK_m, sdl2.SDLK_j, sdl2.SDLK_u ]) # Prime items always presented in far locations self.prime_locs = self.far_locs.copy() # Probe items can be far or near, determined conditionally self.probe_locs = dict(self.near_locs.items() + self.far_locs.items()) # So, to get a practice block of 25, we first need to generate the full set of 2048 # possible permutations, trim that down to the 288 legitimate permutations, # then trim that down to 25... self.insert_practice_block(1, 2048) # Because KLibs auto-generates trials for each product of ind_vars.py, # a lot of 'vestigial' trials are generated that we don't want, this sorts # through the trial list and removes those trials. for ind_b, block in enumerate(self.trial_factory.blocks): for trial in block: # targets & distractors cannot overlap within a given display if trial[1] == trial[2] or trial[3] == trial[4]: self.trial_factory.blocks[ind_b].remove(trial) block.i -= 1 block.length = len(block.trials) continue # For 'near' trials, Ts & Ds cannot appear at 'far' locations if trial[0] == 'near': if trial[3] < 5 or trial[4] < 5: self.trial_factory.blocks[ind_b].remove(trial) block.i -= 1 block.length = len(block.trials) # Conversely, cannot appear at 'near' locations on 'far' trials else: if trial[3] > 4 or trial[4] > 4: self.trial_factory.blocks[ind_b].remove(trial) block.i -= 1 block.length = len(block.trials) # We only want 25 trials for practice, this trims the block # to the appropriate length if ind_b == 0: for trial in block: self.trial_factory.blocks[ind_b].remove(trial) block.i -= 1 block.length = len(block.trials) if block.length == 25: break # Set to True once instructions are provided self.instructed = False
def setup(self): # Stimulus sizes fixation_size = deg_to_px(0.5) fixation_thickness = deg_to_px(0.05) cue_size = deg_to_px(0.5) cue_thickness = deg_to_px(0.05) arrow_tail_len = deg_to_px(0.35) arrow_tail_width = deg_to_px(0.1) arrow_head_len = deg_to_px(0.2) arrow_head_width = deg_to_px(0.3, even=True) # Stimuli self.fixation = kld.FixationCross(fixation_size, fixation_thickness, fill=BLACK) self.cue = kld.Asterisk(cue_size, thickness=cue_thickness, fill=BLACK, spokes=8) self.arrow_l = kld.Arrow(arrow_tail_len, arrow_tail_width, arrow_head_len, arrow_head_width, fill=BLACK, rotation=180) self.arrow_r = kld.Arrow(arrow_tail_len, arrow_tail_width, arrow_head_len, arrow_head_width, fill=BLACK) self.line = kld.Rectangle(arrow_tail_len + arrow_head_len, arrow_tail_width, stroke=[0, BLACK, 1], fill=BLACK) self.arrow_l.render() self.arrow_r.render() # Layout height_offset = deg_to_px(1.06) flanker_offset = arrow_tail_len + arrow_head_len + deg_to_px(0.06) self.above_loc = (P.screen_c[0], P.screen_c[1] - height_offset) self.below_loc = (P.screen_c[0], P.screen_c[1] + height_offset) self.above_flanker_locs = [] self.below_flanker_locs = [] for offset in [-2, -1, 1, 2]: x_pos = P.screen_c[0] + (offset * flanker_offset) self.above_flanker_locs.append((x_pos, self.above_loc[1])) self.below_flanker_locs.append((x_pos, self.below_loc[1])) # Initialize feedback messages for practice block timeout_msg = message('Too slow! Please try to respond more quickly.', blit_txt=False) incorrect_str = ( "Incorrect response!\n" "Please respond to left arrows with the 'z' key and right arrows with the '/' key." ) incorrect_msg = message(incorrect_str, align='center', blit_txt=False) self.feedback_msgs = { 'incorrect': incorrect_msg, 'timeout': timeout_msg } # Set up Response Collector to get keypress responses self.rc.uses(KeyPressResponse) self.rc.terminate_after = [1700, TK_MS ] # response period times out after 1700ms self.rc.keypress_listener.interrupts = True self.rc.keypress_listener.key_map = {'z': 'left', '/': 'right'} # Add practice block of 24 trials to start of experiment if P.run_practice_blocks: self.insert_practice_block(1, trial_counts=24)
def setup(self): # ---------------------------------- # # Setup Stimuli # # ---------------------------------- # # Set stimulus sizes line_length = deg_to_px(2) line_thickness = deg_to_px(0.5) thick_rect_border = deg_to_px(0.7) thin_rect_border = deg_to_px(0.3) fix_size = deg_to_px(0.6) fix_thickness = deg_to_px(0.1) square_size = deg_to_px(3) large_text_size = deg_to_px(0.65) # Stimulus layout box_offset = deg_to_px(8.0) self.left_box_loc = (P.screen_c[0] - box_offset, P.screen_c[1]) self.right_box_loc = (P.screen_c[0] + box_offset, P.screen_c[1]) # Generate target colouring # Select target colours from randomly rotated colourwheel # ensuring those selected are unique and equidistant self.color_selecter = kld.ColorWheel(diameter=1, rotation=random.randrange(0, 360)) self.target_colours = [] for i in (0, 120, 240): self.target_colours.append(self.color_selecter.color_from_angle(i)) # Assign colours to payout valences random.shuffle(self.target_colours) self.high_value_colour = self.target_colours[0] self.low_value_colour = self.target_colours[1] self.neutral_value_colour = self.target_colours[2] # Initialize drawbjects self.thick_rect = kld.Rectangle( square_size, stroke=[thick_rect_border, WHITE, STROKE_CENTER]) self.thin_rect = kld.Rectangle( square_size, stroke=[thin_rect_border, WHITE, STROKE_CENTER]) self.high_val_rect = kld.Rectangle( square_size, stroke=[thin_rect_border, self.high_value_colour, STROKE_CENTER]) self.low_val_rect = kld.Rectangle( square_size, stroke=[thin_rect_border, self.low_value_colour, STROKE_CENTER]) self.fixation = kld.Asterisk(fix_size, fix_thickness, fill=WHITE) self.fix_cueback = kld.Asterisk(fix_size * 2, fix_thickness * 2, fill=WHITE) self.go = kld.FixationCross(fix_size, fix_thickness, fill=BLACK) self.nogo = kld.FixationCross(fix_size, fix_thickness, fill=BLACK, rotation=45) self.flat_line = kld.Rectangle(line_length, line_thickness, fill=BLACK) self.tilt_line = kld.Rectangle(line_length, line_thickness, fill=BLACK, rotation=45) self.probe = kld.Ellipse(int(0.75 * square_size)) # ---------------------------------- # # Setup other experiment factors # # ---------------------------------- # # COTOA = Cue-Offset|Target-Onset Asynchrony self.cotoa = 800 # ms self.feedback_exposure_period = 1.25 # sec # Training block payout variables self.high_payout_baseline = 12 self.low_payout_baseline = 8 self.total_score = None self.penalty = -5 # ---------------------------------- # # Setup Response Collectors # # ---------------------------------- # # Initialize response collectors self.probe_rc = ResponseCollector(uses=RC_KEYPRESS) self.training_rc = ResponseCollector(uses=RC_KEYPRESS) # Initialize ResponseCollector keymaps self.training_keymap = KeyMap( 'training_response', # Name ['z', '/'], # UI labels ["left", "right"], # Data labels [sdl2.SDLK_z, sdl2.SDLK_SLASH] # SDL2 Keysyms ) self.probe_keymap = KeyMap('probe_response', ['spacebar'], ["pressed"], [sdl2.SDLK_SPACE]) # --------------------------------- # # Setup Experiment Messages # # --------------------------------- # # Make default font size larger self.txtm.add_style('myText', large_text_size, WHITE) err_txt = "{0}\n\nPress any key to continue." lost_fixation_txt = err_txt.format( "Eyes moved! Please keep your eyes on the asterisk.") probe_timeout_txt = err_txt.format( "No response detected! Please respond as fast and as accurately as possible." ) training_timeout_txt = err_txt.format("Line response timed out!") response_on_nogo_txt = err_txt.format( "\'nogo\' signal (x) presented\nPlease only respond when you see " "the \'go\' signal (+).") self.err_msgs = { 'fixation': message(lost_fixation_txt, 'myText', align='center', blit_txt=False), 'probe_timeout': message(probe_timeout_txt, 'myText', align='center', blit_txt=False), 'training_timeout': message(training_timeout_txt, 'myText', align='center', blit_txt=False), 'response_on_nogo': message(response_on_nogo_txt, 'myText', align='center', blit_txt=False) } self.rest_break_txt = err_txt.format( "Whew! that was tricky eh? Go ahead and take a break before continuing." ) self.end_of_block_txt = "You're done the first task! Please buzz the researcher to let them know!" # -------------------------------- # # Setup Eyelink boundaries # # -------------------------------- # fix_bounds = [P.screen_c, square_size / 2] self.el.add_boundary('fixation', fix_bounds, CIRCLE_BOUNDARY) # --------------------------------- # # Insert training block (line task) # # --------------------------------- # if P.run_practice_blocks: self.insert_practice_block(1, trial_counts=P.trials_training_block)
def setup(self): # Initialize text styles self.txtm.add_style('normal', '0.7deg') self.txtm.add_style('title', '1.0deg') self.txtm.add_style('stream', '1.5deg') # Stimulus sizes mask_size = deg_to_px(1.5) mask_thick = deg_to_px(0.25) acc_size = deg_to_px(0.5) acc_offset = deg_to_px(3.0) arrow_tail_l = deg_to_px(0.5) arrow_tail_w = deg_to_px(0.2) arrow_head_l = deg_to_px(0.3) arrow_head_w = deg_to_px(0.5, even=True) box_size = deg_to_px(2.0) box_stroke = deg_to_px(0.2) # Generate shape stimuli for instructions self.arrow = kld.Arrow(arrow_tail_l, arrow_tail_w, arrow_head_l, arrow_head_w) self.arrow.fill = P.default_color self.target_box = kld.Rectangle(box_size, stroke=[box_stroke, P.default_color]) # Generate shape stimuli for task self.accuracy_rect = kld.Rectangle(acc_offset, acc_offset + acc_size * 2, fill=P.default_color) self.accuracy_mask = kld.Rectangle(acc_offset + 2, acc_offset, fill=P.default_fill_color) self.mask = kld.Asterisk(mask_size, mask_thick, fill=P.default_color) # Select random letters from the alphabet and render for use in task alphabet = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ') random.shuffle(alphabet) self.letter_set = alphabet[:P.set_size] self.letters = {} for letter in self.letter_set: self.letters[letter] = message(letter, style='stream', blit_txt=False) # Initialize thought probes self.probe_condition = P.condition_map[P.condition] self.probe = self._init_probe(self.probe_condition) # Determine proportion of non-nback trials is_nback = self.trial_factory.exp_factors['is_target'] self.nback_rate = sum(is_nback) / len(is_nback) # Determine order of difficulty levels (counterbalancing) self.first_nback = random.choice([1, 2]) # Show task instructions and example thought probe self.instructions() # Add practice blocks to start of task if P.run_practice_blocks: self.insert_practice_block(1, trial_counts=48) self.insert_practice_block(2, trial_counts=48)
def test_init_kldraw(self): d = kld.Ellipse(100, fill=(255, 255, 255)) surf = NumpySurface(d) assert d.surface_height == surf.height and d.surface_width == surf.width assert surf.content[50][50][0] == 255
def setup(self): # Stimulus sizes fixation_size = deg_to_px(0.32) fixation_thickness = deg_to_px(0.08) cue_size = deg_to_px(0.64) cue_thickness = deg_to_px(0.08) arrow_tail_len = deg_to_px(0.48) arrow_tail_width = deg_to_px(0.15) arrow_head_len = deg_to_px(0.25) arrow_head_width = deg_to_px(0.45, even=True) arrow_dimensions = [ arrow_tail_len, arrow_tail_width, arrow_head_len, arrow_head_width ] # Stimuli self.warning_tone = Tone(50.1, 'sine', frequency=2000, volume=0.5) self.fixation = kld.FixationCross(fixation_size, fixation_thickness, fill=BLACK) self.cue = kld.Asterisk(cue_size, thickness=cue_thickness, fill=BLACK, spokes=8) self.arrow_r = kld.Arrow(*arrow_dimensions, fill=BLACK) self.arrow_l = kld.Arrow(*arrow_dimensions, fill=BLACK, rotation=180) self.arrow_r.render() self.arrow_l.render() # Layout self.height_offset = deg_to_px(1.3) self.height_jitter = deg_to_px(0.04) self.flanker_offset = arrow_tail_len + arrow_head_len + deg_to_px(0.16) self.ev_offsets = { 'above': -(self.height_jitter * 4), 'below': self.height_jitter * 4 } self.above_loc = (P.screen_c[0], P.screen_c[1] - self.height_offset) self.below_loc = (P.screen_c[0], P.screen_c[1] + self.height_offset) self.cue_locations = {'above': self.above_loc, 'below': self.below_loc} # Add text styles for PVT and block messages self.txtm.add_style("PVT", '1.5deg', color=RED) self.txtm.add_style("block_msg", '0.6deg', color=BLACK) # If it's the first session, insert practice blocks with feedback if P.run_practice_blocks and P.session_number == 1: ANTI_only = ['ANTI-valid', 'ANTI-invalid', 'ANTI-none'] ANTI_EV = copy(ANTI_only) * 2 + ['EV-above', 'EV-below' ] * 3 # 1/2 ANTI, 1/2 EV ANTI_EV_AV = copy(ANTI_EV) + ['AV'] * 6 # 1/3 ANTI, 1/3 EV, 1/3 AV self.insert_practice_block(1, trial_counts=16, factor_mask={'trial_type': ANTI_only}) self.insert_practice_block(2, trial_counts=32, factor_mask={'trial_type': ANTI_EV}) self.insert_practice_block(3, trial_counts=48, factor_mask={'trial_type': ANTI_EV_AV})
def setup(self): # Stimulus Sizes target_size = deg_to_px(3.0) diamond_size = sqrt(target_size**2/2.0) probe_diameter = deg_to_px(1.0) wheel_diameter = deg_to_px(16.0) # Stimulus Drawbjects self.line_a = kld.Rectangle(width=P.screen_x/2, height=2, fill=WHITE) self.line_b = kld.Rectangle(width=P.screen_x/2, height=2, fill=BLACK) self.diamond_a = kld.Rectangle(diamond_size, fill=WHITE, rotation=45) self.diamond_b = kld.Rectangle(diamond_size, fill=BLACK, rotation=45) self.probe = kld.Ellipse(probe_diameter, fill=None) self.wheel = kld.ColorWheel(wheel_diameter) self.line_a.render() self.line_b.render() self.diamond_a.render() self.diamond_b.render() # Layout self.left_x = P.screen_x/4 self.right_x = 3*P.screen_x/4 self.probe_positions = { "left": (self.left_x, P.screen_c[1]), "right": (self.right_x, P.screen_c[1]) } self.start_baseline = P.screen_y/4 self.end_offset = deg_to_px(5.0) self.left_start = [self.left_x, P.screen_y/4] self.right_start = [self.right_x, 3*P.screen_y/4] self.left_end = [self.left_x, P.screen_c[1]+self.end_offset] self.right_end = [self.right_x, P.screen_c[1]-self.end_offset] # Timing self.motion_duration = 1.5 # seconds # Experiment Messages if not P.condition: P.condition = P.default_condition toj_string = "Which shape {0} {1}?\n(White = 8 Black = 2)" stationary_string = toj_string.format("appeared", P.condition) motion_string = toj_string.format("touched the line", P.condition) self.toj_prompts = { 'stationary': message(stationary_string, align="center", blit_txt=False), 'motion': message(motion_string, align="center", blit_txt=False) } # Initialize ResponseCollector keymaps if P.use_numpad: keysyms = [sdl2.SDLK_KP_8, sdl2.SDLK_KP_2] else: keysyms = [sdl2.SDLK_8, sdl2.SDLK_2] self.toj_keymap = KeyMap( "toj_responses", # Name ['8', '2'], # UI labels ['white', 'black'], # Data labels keysyms # SDL2 Keysyms ) # Initialize second ResponseCollector object for colour wheel responses self.wheel_rc = ResponseCollector() # Generate practice blocks default_soas = self.trial_factory.exp_factors['t1_t2_soa'] toj_soas = [soa for soa in default_soas if soa!=0.0] toj_only = {"t1_t2_soa": toj_soas} probe_only = {"t1_t2_soa": [0.0]} if P.run_practice_blocks: num = P.trials_per_practice_block self.insert_practice_block(1, trial_counts=num, factor_mask=toj_only) self.insert_practice_block((2,4), trial_counts=num, factor_mask=probe_only) self.trial_factory.dump()
def setup(self): # Initialize stimulus sizes mask_size_x = deg_to_px(3.0) mask_size_ring = deg_to_px(4.0) mask_thick = deg_to_px(0.3) # Initialize text styles self.txtm.add_style('normal', '0.7deg') self.txtm.add_style('title', '1.0deg') self.mask_x = kld.Asterisk(mask_size_x, mask_thick, fill=P.default_color, spokes=8) self.mask_ring = kld.Annulus(mask_size_ring, mask_thick, fill=P.default_color) self.digits = {} digits = [1, 2, 3, 4, 5, 6, 7, 8, 9] for digit in digits: self.digits[digit] = {} self.sizes = ['1.5deg', '2.0deg', '2.5deg', '3.0deg', '3.5deg'] for size in self.sizes: self.txtm.add_style(size, size) for digit in digits: for size in self.sizes: self.digits[digit][size] = message(str(digit), style=size, blit_txt=False) # Initialize thought probes p_title = message(P.probe_question, "title", blit_txt=False) p_responses = P.probe_responses p_order = P.probe_order p_origin = (P.screen_c[0], P.screen_x // 10) self.probe = ThoughtProbe(p_responses, p_title, int(P.screen_x * 0.8), p_origin, p_order) # Initialize effort probes qeffort_text = "How much effort were you putting into staying on-task?" self.effort_q = message(qeffort_text, "title", blit_txt=False) self.mineffort_msg = message("0%", "normal", blit_txt=False) self.maxeffort_msg = message("100%", "normal", blit_txt=False) self.submit_msg = message("Continue", "normal", blit_txt=False) pad = int(self.submit_msg.height * 0.75) self.submit = Button(self.submit_msg, int(self.submit_msg.width + pad * 1.5), self.submit_msg.height + pad, registration=8, location=(P.screen_c[0], int(P.screen_y * 0.8))) # Randomly distribute probes across session, avoiding placing them less than 20 sec. apart self.probe_trials = [] noprobe_span = [False] * P.noprobe_span probe_span = [True] + [False] * (P.probe_span - 1) while len(self.probe_trials) < (P.trials_per_block * P.blocks_per_experiment): random.shuffle(probe_span) self.probe_trials += noprobe_span + probe_span # Show task instructions and example thought probe self.instructions() # Add practice blocks to start of task self.first_nonpractice = 1 if P.run_practice_blocks: num_nonpractice = P.blocks_per_experiment self.insert_practice_block(1, trial_counts=9, factor_mask={'number': range(1, 10)}) self.insert_practice_block(2, trial_counts=9, factor_mask={'number': range(1, 10)}) self.first_nonpractice = P.blocks_per_experiment - num_nonpractice + 1