Пример #1
0
    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
Пример #2
0
    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)
Пример #3
0
 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()
Пример #4
0
    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
Пример #5
0
    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()
Пример #6
0
    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'])
Пример #7
0
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")
Пример #8
0
    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()
Пример #9
0
    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))
Пример #10
0
    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)
Пример #11
0
    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
Пример #12
0
    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)
Пример #13
0
    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)
Пример #14
0
    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)
Пример #15
0
 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
Пример #16
0
    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})
Пример #17
0
    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()
Пример #18
0
    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