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 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): # 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