Example #1
0
 def __init__(self, bar, button_text, button_size, location, callback=None):
     super(Button, self).__init__()
     super(EnvAgent, self).__init__()
     self.bar = bar
     self.size = button_size
     self.button_text = button_text
     self.button_rtext_a = message(button_text,
                                   "button_active",
                                   blit_txt=False)
     self.button_rtext_i = message(button_text,
                                   "button_inactive",
                                   blit_txt=False)
     self.frame_i = Rectangle(button_size[0],
                              button_size[1],
                              fill=None,
                              stroke=(5, (255, 255, 255)))
     self.frame_a = Rectangle(button_size[0],
                              button_size[1],
                              fill=None,
                              stroke=(5, (150, 255, 150)))
     self.active = False
     self.location = location
     self.text_location = (self.location[0] + self.size[0] // 2,
                           self.location[1] + self.size[1] // 2)
     self.create_boundary()
     self.callback = callback
Example #2
0
    def __init__(self, y_pos, bar_length, bar_height, handle_radius, bar_fill,
                 handle_fill):
        BoundaryInspector.__init__(self)
        EnvAgent.__init__(self)
        self.boundaries = {}
        self.pos = (P.screen_c[0] - bar_length // 2, y_pos)  # upper-left
        self.message_pos = (P.screen_c[0], y_pos - 50)
        self.__handle_pos = (self.pos[0], self.pos[1] + bar_height // 2)
        self.handle_color = handle_fill
        self.handle_radius = handle_radius
        self.handle_stroke = None
        self.handle_boundary = None
        self.bar = None
        self.bar_size = (bar_length, bar_height)
        self.bar_color = bar_fill
        self.bar_stroke = None
        self.show_increment_ticks = True
        self.show_increment_text = False
        self.increment_count = None
        self.increments = []
        self.increment_by = 1
        self.increment_surfs = {}
        self.lower_bound = None
        self.upper_bound = None
        self.handle = Ellipse(self.handle_radius * 2,
                              fill=self.handle_color,
                              stroke=self.handle_stroke)
        self.bar = Rectangle(self.bar_size[0],
                             self.bar_size[1],
                             fill=self.bar_color,
                             stroke=self.bar_stroke)
        self.add_boundary("handle", [
            (self.pos[0] + self.handle_radius, self.pos[1]), self.handle_radius
        ], CIRCLE_BOUNDARY)
        self.msg = message("How many corners did the dot traverse?",
                           "default",
                           blit_txt=False)
        self.lb_msg = None
        self.ub_msg = None
        self.ok_text = message("OK", blit_txt=False)
        self.ok_inactive_button = Rectangle(100,
                                            50,
                                            stroke=(1, (255, 255, 255)),
                                            fill=(125, 125, 125)).render()
        self.ok_active_button = Rectangle(100,
                                          50,
                                          stroke=(1, (255, 255, 255)),
                                          fill=(5, 175, 45)).render()
        self.button_active = False
        self.button_pos = (P.screen_c[0], y_pos + bar_height + 50)
        button_upper_left = (self.button_pos[0] - 50, self.button_pos[1] - 25)
        button_botton_right = (self.button_pos[0] + 50,
                               self.button_pos[1] + 25)
        self.add_boundary("button", (button_upper_left, button_botton_right),
                          RECT_BOUNDARY)

        self.response = None
    def construct_placeholder(self):
        stroke = [self.rect_thickness, WHITE, STROKE_CENTER]
        # width = None
        # height = None

        # Horizontal/vertical indicates directionality of placeholders length
        if self.box_alignment == VERTICAL:
            width, height = self.rect_short_side, self.rect_long_side

        else:
            height, width = self.rect_short_side, self.rect_long_side

        return Rectangle(width=width, height=height, stroke=stroke)
Example #4
0
    def __init__(self, data):

        self.media_type = IMAGE_FILE
        self.height = None
        self.width = None
        self.duration = None

        if data.text:
            # todo: make style optional
            self.contents = message(data.text.string,
                                    data.text.style,
                                    align="center",
                                    blit_txt=False)
        elif data.drawbject:
            d = data.drawbject
            if d.shape == "rectangle":
                self.contents = Rectangle(d.width, d.height, d.stroke,
                                          d.fill).render()
            if d.shape == "ellipse":
                self.contents = Ellipse(d.width, d.height, d.stroke,
                                        d.fill).render()
            if d.shape == "annulus":
                self.contents = Annulus(d.diameter, d.ring_width, d.stroke,
                                        d.fill).render()
        else:
            self.media_type = data.file.media_type
            if self.is_audio:
                self.duration = data.file
                self.contents = AudioClip(
                    join(P.resources_dir, "audio", data.file.filename))
            else:
                # If asset is image file, import and scale for current screen size (animations
                # originally hard-coded at 1920x1080 so we scale relative to that)
                img = Image.open(join(P.image_dir, data.file.filename))
                target_size = (P.screen_x, (P.screen_x / 16.0) * 9
                               )  # corrected for aspect ratio
                scaled_size = scale(img.size, (1920, 1080),
                                    target_size,
                                    center=False)
                self.contents = np.asarray(
                    img.resize(scaled_size, Image.BILINEAR))

        try:
            self.height = self.contents.height
            self.width = self.contents.width
        except AttributeError:
            try:
                self.height = self.contents.shape[0]
                self.width = self.contents.shape[1]
            except AttributeError:
                pass  # ie. audio file
Example #5
0
    def setup(self):

        # Generate messages to be displayed during experiment
        self.err_msgs = {}
        if P.saccade_response_cond:
            self.err_msgs['eye'] = "Moved eyes too soon!"
            self.err_msgs['key'] = "Please respond with eye movements only."
            self.err_msgs['early'] = self.err_msgs[
                'key']  # for convenience in logic
        else:
            self.err_msgs['eye'] = "Moved eyes!"
            self.err_msgs['key'] = "Please respond with the spacebar only."
            self.err_msgs['early'] = "Responded too soon!"

        # Stimulus sizes
        self.target_width = deg_to_px(
            0.5, even=True)  # diameter of target circle (0.5 degrees)
        self.cue_size = deg_to_px(
            0.5, even=True)  # size of asterisk/fixations (0.5 degrees)
        self.box_size = deg_to_px(
            0.8, even=True)  # size of placeholder boxes (0.8 degrees)

        # Stimulus Drawbjects
        self.box = Rectangle(self.box_size, stroke=(2, WHITE)).render()
        self.cross_r = FixationCross(self.cue_size, 2, fill=RED).render()
        self.cross_w = FixationCross(self.cue_size, 2, fill=WHITE).render()
        self.circle = Circle(self.target_width, fill=WHITE).render()
        self.asterisk = SquareAsterisk(self.cue_size, 2, fill=WHITE).render()

        # Layout of stimuli

        # offset between centre of boxes and centre of screen, in degrees
        offset_size_deg = P.dm_offset_size if P.development_mode else 7.0
        self.offset_size = deg_to_px(offset_size_deg)
        self.target_locs = {
            TOP: (P.screen_c[0], P.screen_c[1] - self.offset_size),
            RIGHT: (P.screen_c[0] + self.offset_size, P.screen_c[1]),
            BOTTOM: (P.screen_c[0], P.screen_c[1] + self.offset_size),
            LEFT: (P.screen_c[0] - self.offset_size, P.screen_c[1])
        }

        # prepare all animation locations for both rotation directions and starting axes
        self.animation_frames = 15
        animation_duration = 300  # ms
        self.frame_duration = animation_duration / self.animation_frames
        rotation_increment = (pi / 2) / self.animation_frames
        cx, cy = P.screen_c
        self.frames = {
            V_START_AXIS: {
                ROT_CW: [],
                ROT_CCW: []
            },
            H_START_AXIS: {
                ROT_CW: [],
                ROT_CCW: []
            }
        }
        for i in range(0, self.animation_frames):
            l_x_cw = -self.offset_size * cos(i * rotation_increment)
            l_y_cw = self.offset_size * sin(i * rotation_increment)
            l_x_ccw = self.offset_size * cos(i * rotation_increment)
            l_y_ccw = -self.offset_size * sin(i * rotation_increment)
            cw_locs = [(cx + l_x_cw, cy + l_y_cw), (cx - l_x_cw, cy - l_y_cw)]
            ccw_locs = [(cx + l_x_ccw, cy - l_y_ccw),
                        (cx - l_x_ccw, cy + l_y_ccw)]
            self.frames[H_START_AXIS][ROT_CW].append(ccw_locs)
            self.frames[H_START_AXIS][ROT_CCW].append(cw_locs)
            self.frames[V_START_AXIS][ROT_CW].insert(0, cw_locs)
            self.frames[V_START_AXIS][ROT_CCW].insert(0, ccw_locs)

        # Define keymap for ResponseCollector
        self.keymap = KeyMap(
            "speeded response",  # Name
            ["spacebar"],  # UI Label
            ["spacebar"],  # Data Label
            [SDLK_SPACE]  # SDL2 Keycode
        )

        # Boundaries for stimuli
        self.fixation_boundary = deg_to_px(
            3.0)  # radius of 3 degrees of visual angle
        self.el.add_boundary("drift_correct",
                             [P.screen_c, self.fixation_boundary],
                             CIRCLE_BOUNDARY)
Example #6
0
    def setup(self):

        # Set up custom text styles for the experiment
        self.txtm.add_style('instructions', 18, [255, 255, 255, 255])
        self.txtm.add_style('error', 18, [255, 0, 0, 255])
        self.txtm.add_style('tiny', 12, [255, 255, 255, 255])
        self.txtm.add_style('small', 14, [255, 255, 255, 255])

        # Pre-render shape stimuli
        dot_stroke = [P.dot_stroke, P.dot_stroke_col, STROKE_OUTER
                      ] if P.dot_stroke > 0 else None
        self.tracker_dot = Ellipse(P.dot_size,
                                   stroke=dot_stroke,
                                   fill=P.dot_color).render()
        self.origin_active = Ellipse(P.origin_size,
                                     fill=self.origin_active_color).render()
        self.origin_inactive = Ellipse(
            P.origin_size, fill=self.origin_inactive_color).render()

        # If capture figures mode, generate, view, and optionally save some figures
        if P.capture_figures_mode:
            self.fig_dir = os.path.join(P.resources_dir, "figures")
            self.capture_figures()
            self.quit()

        # Initialize participant ID and session options, reloading ID if it already exists
        self.session = TraceLabSession()
        self.user_id = self.session.user_id

        # Once session initialized, show loading screen and finish setup
        self.loading_msg = message("Loading...", "default", blit_txt=False)
        fill()
        blit(self.loading_msg, 5, P.screen_c)
        flip()

        # Scale UI size variables to current screen resolution
        P.btn_s_pad = scale((P.btn_s_pad, 0), (1920, 1080))[0]
        P.y_pad = scale((0, P.y_pad), (1920, 1080))[1]

        # Initialize messages and response buttons for control trials
        control_fail_txt = "Please keep your finger on the start area for the complete duration."
        self.control_fail_msg = message(control_fail_txt,
                                        'error',
                                        blit_txt=False)
        ctrl_buttons = ["1", "2", "3", "4", "5"]
        self.control_bar = ButtonBar(buttons=[(i, P.btn_size, None)
                                              for i in ctrl_buttons],
                                     button_size=P.btn_size,
                                     screen_margins=P.btn_s_pad,
                                     y_offset=P.y_pad,
                                     message_txt=P.control_q)

        # Initialize 'next trial' button
        button_x = 250 if self.handedness == LEFT_HANDED else P.screen_x - 250
        button_y = P.screen_y - 100
        self.next_trial_msg = message(P.next_trial_message,
                                      'default',
                                      blit_txt=False)
        self.next_trial_box = Rectangle(300,
                                        75,
                                        stroke=(2, (255, 255, 255),
                                                STROKE_OUTER))
        self.next_trial_button_loc = (button_x, button_y)
        bounds = [(button_x - 150, button_y - 38),
                  (button_x + 150, button_y + 38)]
        self.add_boundary("next trial button", bounds, RECT_BOUNDARY)

        # Initialize instructions and practice button bar for each condition
        self.instruction_files = {
            PHYS: {
                'text': "physical_group_instructions.txt",
                'frames': "physical_key_frames"
            },
            MOTR: {
                'text': "imagery_group_instructions.txt",
                'frames': "imagery_key_frames"
            },
            CTRL: {
                'text': "control_group_instructions.txt",
                'frames': "control_key_frames"
            }
        }
        self.practice_instructions = message(P.practice_instructions,
                                             "instructions",
                                             align="center",
                                             blit_txt=False)
        practice_buttons = [('Replay', [200, 100], self.practice),
                            ('Practice', [200, 100], self.__practice__),
                            ('Begin', [200, 100], any_key)]
        self.practice_button_bar = ButtonBar(practice_buttons, [200, 100],
                                             P.btn_s_pad,
                                             P.y_pad,
                                             finish_button=False)

        # Import all pre-generated figures needed for the current session
        figures = list(set(self.trial_factory.exp_factors["figure_name"]))
        figures.append(P.practice_figure)
        for f in figures:
            if f != "random":
                ui_request()
                fig_path = os.path.join(P.resources_dir, "figures", f)
                self.test_figures[f] = TraceLabFigure(fig_path)
Example #7
0
    def setup(self):

        # Bandit Variables

        self.high_payout_baseline = 12
        self.low_payout_baseline = 8
        self.total_score = None
        self.penalty = -5

        # Stimulus Sizes

        thick_rect_border = deg_to_px(0.5)
        thin_rect_border = deg_to_px(0.1)
        star_size = deg_to_px(0.6)
        star_thickness = deg_to_px(0.1)
        square_size = deg_to_px(3)
        text_size = deg_to_px(0.65)
        large_text_size = deg_to_px(0.85)

        # Generate bandit colours from colour wheel

        self.bandit_colour_combos = []
        if P.blocks_per_experiment > 4:
            msg = (
                "Only 4 sets of colours available, experiment script must be modified if more"
                "than 4 blocks total are wanted.")
            raise RuntimeError(msg)
        for angle in [0, 45, 90, 135]:
            combo = [const_lum[angle], const_lum[angle + 180]]
            self.bandit_colour_combos.append(combo)
        random.shuffle(self.bandit_colour_combos)

        # Stimulus Drawbjects

        self.thick_rect = Rectangle(
            square_size, stroke=[thick_rect_border, WHITE, STROKE_CENTER])
        self.thin_rect = Rectangle(
            square_size, stroke=[thin_rect_border, WHITE, STROKE_CENTER])
        self.left_bandit = Rectangle(
            square_size, stroke=[thin_rect_border, WHITE, STROKE_CENTER])
        self.right_bandit = Rectangle(
            square_size, stroke=[thin_rect_border, WHITE, STROKE_CENTER])
        self.neutral_box = self.thin_rect.render()
        self.star = Asterisk(star_size, star_thickness, fill=WHITE)
        self.star_cueback = Asterisk(star_size * 2,
                                     star_thickness * 2,
                                     fill=WHITE)
        self.star_muted = Asterisk(star_size, star_thickness, fill=GREY)
        self.probe = Ellipse(int(0.75 * square_size), fill=WHITE).render()

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

        # Timing

        # Note: cotoa = cue-offset target-onset asynchrony
        self.cotoa_min = 700  # ms
        self.cotoa_max = 1000  # ms
        self.feedback_exposure_period = 1.25  # sec

        # EyeLink Boundaries

        fix_bounds = [P.screen_c, square_size / 2]
        self.el.add_boundary('fixation', fix_bounds, CIRCLE_BOUNDARY)

        # Experiment Messages

        self.txtm.styles[
            'default'].font_size = text_size  # re-define default font size in degrees
        self.txtm.add_style("score up", large_text_size, PASTEL_GREEN)
        self.txtm.add_style("score down", large_text_size, PASTEL_RED)
        self.txtm.add_style("timeout", 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.")
        too_soon_txt = err_txt.format(
            "Responded too soon! Please wait until the 'go' signal to "
            "make a response.")
        probe_timeout_txt = err_txt.format(
            "No response detected! Please answer louder or faster.")
        bandit_timeout_txt = err_txt.format("Bandit selection timed out!")
        wrong_response_txt = err_txt.format(
            "Wrong response type!\nPlease make vocal responses "
            "to probes and keypress responses to bandits.")

        self.err_msgs = {
            'fixation':
            message(lost_fixation_txt, align='center', blit_txt=False),
            'too_soon':
            message(too_soon_txt, align='center', blit_txt=False),
            'probe_timeout':
            message(probe_timeout_txt,
                    'timeout',
                    align='center',
                    blit_txt=False),
            'bandit_timeout':
            message(bandit_timeout_txt,
                    'timeout',
                    align='center',
                    blit_txt=False),
            'wrong_response':
            message(wrong_response_txt, align='center', blit_txt=False)
        }

        # Initialize separate ResponseCollectors for probe and bandit responses

        self.probe_rc = ResponseCollector(uses=[RC_AUDIO, RC_KEYPRESS])
        self.bandit_rc = ResponseCollector(uses=[RC_AUDIO, RC_KEYPRESS])

        # Initialize ResponseCollector keymap

        self.keymap = KeyMap(
            'bandit_response',  # Name
            ['z', '/'],  # UI labels
            ["left", "right"],  # Data labels
            [sdl2.SDLK_z, sdl2.SDLK_SLASH]  # SDL2 Keysyms
        )

        # Add practice block of 20 trials to start of experiment

        if P.run_practice_blocks:
            self.insert_practice_block(1, trial_counts=20)
Example #8
0
    def setup(self):

        # Stimulus sizes
        thick_rect_border = deg_to_px(0.5)
        thin_rect_border = deg_to_px(0.1)
        star_size = deg_to_px(0.6)
        star_thickness = deg_to_px(0.1)
        square_size = deg_to_px(3)
        large_text_size = 0.65

        # Stimulus drawbjects
        self.thick_rect = Rectangle(
            square_size, stroke=[thick_rect_border, WHITE, STROKE_CENTER])
        self.thin_rect = Rectangle(
            square_size, stroke=[thin_rect_border, WHITE, STROKE_CENTER])
        self.neutral_box = self.thin_rect.render()

        self.star = Asterisk(star_size, star_thickness, fill=WHITE)
        self.star_cueback = Asterisk(star_size * 2,
                                     star_thickness * 2,
                                     fill=WHITE)

        self.go = FixationCross(star_size, star_thickness, fill=BLACK)
        self.go.render()
        self.nogo = FixationCross(star_size,
                                  star_thickness,
                                  fill=BLACK,
                                  rotation=45)
        self.nogo.render()

        self.left_bandit = Ellipse(int(0.75 * square_size))
        self.right_bandit = Ellipse(int(0.75 * square_size))
        self.probe = Ellipse(int(0.75 * square_size))

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

        # Set cotoa
        self.cotoa = 800  # ms

        self.feedback_exposure_period = 1.25  # sec

        # Bandit payout variables
        self.high_payout_baseline = 12
        self.low_payout_baseline = 8
        self.total_score = None
        self.penalty = -5

        # Generate colours from colour wheel
        self.target_colours = [const_lum[0], const_lum[120], const_lum[240]]
        random.shuffle(self.target_colours)

        # Assign to bandits & neutral probe
        self.high_value_colour = self.target_colours[0]
        self.low_value_colour = self.target_colours[1]
        self.neutral_value_colour = self.target_colours[2]

        # EyeLink Boundaries
        fix_bounds = [P.screen_c, square_size / 2]
        self.el.add_boundary('fixation', fix_bounds, CIRCLE_BOUNDARY)

        # Initialize response collectors
        self.probe_rc = ResponseCollector(uses=RC_KEYPRESS)
        self.bandit_rc = ResponseCollector(uses=RC_KEYPRESS)

        # Initialize ResponseCollector keymaps
        self.bandit_keymap = KeyMap(
            'bandit_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])

        # Experiment Messages
        self.txtm.add_style("payout", large_text_size, WHITE)
        self.txtm.add_style("timeout", 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."
        )
        bandit_timeout_txt = err_txt.format("Bandit selection 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, align='center', blit_txt=False),
            'probe_timeout':
            message(probe_timeout_txt,
                    'timeout',
                    align='center',
                    blit_txt=False),
            'bandit_timeout':
            message(bandit_timeout_txt,
                    'timeout',
                    align='center',
                    blit_txt=False),
            'response_on_nogo':
            message(response_on_nogo_txt, 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!"

        # Insert bandit block
        if P.run_practice_blocks:
            self.insert_practice_block(1, trial_counts=P.trials_bandit_block)