Exemple #1
0
    def start_trial_button(self):

        fill()
        blit(self.next_trial_box,
             5,
             self.next_trial_button_loc,
             flip_x=P.flip_x)
        blit(self.next_trial_msg,
             5,
             self.next_trial_button_loc,
             flip_x=P.flip_x)
        flip()

        if P.demo_mode or P.dm_always_show_cursor:
            show_mouse_cursor()

        flush()
        clicked = False
        while not clicked:
            event_queue = pump(True)
            for e in event_queue:
                if e.type == SDL_MOUSEBUTTONDOWN:
                    clicked = self.within_boundary("next trial button",
                                                   [e.button.x, e.button.y])
                elif e.type == SDL_KEYDOWN:
                    ui_request(e.key.keysym)

        if not (P.demo_mode or P.dm_always_show_cursor):
            hide_mouse_cursor()
Exemple #2
0
    def imagery_trial(self):

        fill()
        blit(self.origin_inactive, 5, self.origin_pos, flip_x=P.flip_x)
        flip()

        start = self.evm.trial_time
        if P.demo_mode or P.dm_always_show_cursor:
            show_mouse_cursor()

        at_origin = False
        while not at_origin:
            x, y, button = mouse_pos(return_button_state=True)
            left_button_down = button == 1
            if self.within_boundary('origin', (x, y)) and left_button_down:
                at_origin = True
                self.rt = self.evm.trial_time - start
            ui_request()
        fill()
        blit(self.origin_active, 5, self.origin_pos, flip_x=P.flip_x)
        flip()

        while at_origin:
            x, y, button = mouse_pos(return_button_state=True)
            left_button_down = button == 1
            if not (self.within_boundary('origin',
                                         (x, y)) and left_button_down):
                at_origin = False
        self.mt = self.evm.trial_time - (self.rt + start)
        if P.demo_mode:
            hide_mouse_cursor()
Exemple #3
0
    def trial_prep(self):
        # Grab locations (and their cardinal labels) for each T & D
        self.T_prime_loc = list(self.prime_locs[self.prime_target])
        self.D_prime_loc = list(self.prime_locs[self.prime_distractor])
        self.T_probe_loc = list(self.probe_locs[self.probe_target])
        self.D_probe_loc = list(self.probe_locs[self.probe_distractor])

        # Grab distance between each item pair
        self.T_prime_to_T_probe = line_segment_len(self.T_prime_loc[0],
                                                   self.T_probe_loc[0])
        self.T_prime_to_D_probe = line_segment_len(self.T_prime_loc[0],
                                                   self.D_probe_loc[0])
        self.D_prime_to_T_probe = line_segment_len(self.D_prime_loc[0],
                                                   self.T_probe_loc[0])
        self.D_prime_to_D_probe = line_segment_len(self.D_prime_loc[0],
                                                   self.D_probe_loc[0])

        # Once locations selected, determine which trial type this trial would fall under.
        self.trial_type = self.determine_trial_type()

        # Hide mouse cursor throughout trial
        hide_mouse_cursor()

        # Present fixation & start trial
        self.present_fixation()
Exemple #4
0
    def trial(self):
        # Set to true once played (to avoid repeats)
        tone_played = False

        # Prior to target onset, present fixation, tone & cue (when applicable)
        while self.evm.before('target_on'):
            fill()

            blit(self.fixation, registration=5, location=P.screen_c)

            # Tone
            if self.tone_trial and self.evm.between('tone_on', 'tone_off'):
                if not tone_played:
                    self.warning_tone.play()
                    tone_played = True

            # Cue
            if self.cue_location is not None and self.evm.between(
                    'cue_on', 'cue_off'):
                loc = self.cue_locations[self.cue_location]
                blit(self.cue, registration=5, location=loc)

            flip()
        # For some reason the cursor reappears here...
        hide_mouse_cursor()

        # Present target
        fill()
        blit(self.fixation, registration=5, location=P.screen_c)
        for shape, loc in self.arrows:
            blit(shape, registration=5, location=loc)
        flip()

        # Listen for response
        self.rc.collect()

        # Record response value & rt
        response, rt = self.rc.keypress_listener.response()
        # If no (valid) response made before timeout
        if rt == klibs.TIMEOUT:
            response = 'na'

        # Label response as correct/incorrect
        accuracy = int(response == self.target_direction)

        # Record trial data to database
        return {
            "block_num": P.block_number,
            "trial_num": P.trial_number,
            "practicing": P.practicing,
            "tone_trial": self.tone_trial,
            "tone_onset": self.tone_onset,
            "cue_type": self.cue_type,
            "congruent": self.congruent,
            "target_location": self.target_location,
            "target_direction": self.target_direction,
            "accuracy": accuracy,
            "response": response,
            "rt": rt
        }
Exemple #5
0
    def trial_prep(self):
        # Establish cue condition based on cue validity
        if self.cue_type == 'valid':
            self.cue_location = self.target_location

        elif self.cue_type == 'none':
            self.cue_location = None

        else:
            self.cue_location = 'above' if self.target_location == 'below' else 'below'

        # Establish remaining trial factors
        self.target_direction = random.choice(['left', 'right'])
        self.tone_onset = random.randrange(400, 1650, 50)

        # Generate target & flanker arrows
        self.arrows = self.generate_arrows()

        # Establish sequence of events
        events = []
        events.append(['tone_on', self.tone_onset])
        events.append(['tone_off', events[-1][1] + 50])
        events.append(['cue_on', events[-1][1] + 350])
        events.append(['cue_off', events[-1][1] + 50])
        events.append(['target_on', events[-1][1] + 50])

        # Register sequence w/ event manager
        for e in events:
            self.evm.register_ticket(e)

        # Hide cursor during trial
        hide_mouse_cursor()
Exemple #6
0
    def get_effort(self):

        slider_loc = (P.screen_c[0], int(P.screen_y * 0.55))
        slider_cols = {'line': WHITE, 'slider': TRANSLUCENT_WHITE}
        scale = Slider(int(P.screen_x * 0.75),
                       ticks=5,
                       location=slider_loc,
                       fills=slider_cols)
        label_pad = scale.tick.surface_height

        show_mouse_cursor()
        onset = time.time()
        while True:
            sq = pump(True)
            ui_request(queue=sq)
            fill()
            blit(self.effort_q, 5, (P.screen_c[0], int(P.screen_y * 0.3)))
            blit(self.mineffort_msg, 8,
                 (scale.xmin, slider_loc[1] + label_pad))
            blit(self.maxeffort_msg, 8,
                 (scale.xmax, slider_loc[1] + label_pad))
            scale.draw()
            if scale.pos != None:
                self.submit.draw()
            flip()
            scale.listen(sq)
            if scale.pos != None:
                if self.submit.listen(sq) or key_pressed('Return', queue=sq):
                    rt = time.time() - onset
                    hide_mouse_cursor()
                    return (scale.pos, rt)
Exemple #7
0
	def drift_correct(self, location=None, target=None, fill_color=None, draw_target=True):
		"""Checks the accuracy of the eye tracker's calibration by presenting a fixation
		stimulus and requiring the participant to press the space bar while looking directly at
		it. If there is a large difference between the gaze location at the time the key was
		pressed and the true location of the fixation, it indicates that there has been drift
		in the calibration.

		In TryLink mode, drift correct targets are still displayed the same as with a hardware
		eye tracker. Simulated drift corrects are performed by clicking the drift correct target
		with the mouse.

		Args:
			location (Tuple(int, int), optional): The (x,y) pixel coordinates where the drift
				correct target should be located. Defaults to the center of the screen.
			target: A :obj:`Drawbject` or other :func:`KLGraphics.blit`-able shape to use as
				the drift correct target. Defaults to a circular :func:`drift_correct_target`.
			fill_color: A :obj:`List` or :obj:`Tuple` containing an RGBA colour to use for the
				background for the drift correct screen. Defaults to the value of
				``P.default_fill_color``.
			draw_target (bool, optional): A flag indicating whether the function should draw
				the drift correct target itself (True), or whether it should leave it to the
				programmer to draw the target before :meth:`drift_correct` is called (False). 
				Defaults to True.

		"""
		show_mouse_cursor()

		target = drift_correct_target() if target is None else target
		draw_target = EL_TRUE if draw_target in [EL_TRUE, True] else EL_FALSE
		location = P.screen_c if location is None else location
		if not iterable(location):
			raise ValueError("'location' must be a pair of (x,y) pixel coordinates.")
		dc_boundary = CircleBoundary('drift_correct', location, P.screen_y // 30)
		
		while True:
			event_queue = pump(True)
			ui_request(queue=event_queue)
			if draw_target == EL_TRUE:
				fill(P.default_fill_color if not fill_color else fill_color)
				blit(target, 5, location)
				flip()
			else:
				SDL_Delay(2) # required for pump() to reliably return mousebuttondown events
			for e in event_queue:
				if e.type == SDL_MOUSEBUTTONDOWN and dc_boundary.within([e.button.x, e.button.y]):
					hide_mouse_cursor()
					if draw_target == EL_TRUE:
						fill(P.default_fill_color if not fill_color else fill_color)
						flip()
					return 0
Exemple #8
0
    def collect(self):

        show_mouse_cursor()
        response = None
        onset = time.time()

        while response == None:
            fill()
            self._render()
            flip()
            response = self._collect()

        rt = time.time() - onset
        hide_mouse_cursor()
        return Response(response, rt)
Exemple #9
0
    def __trial__(self, trial, practice):
        """
		Private method; manages a trial.
		"""
        from klibs.KLUtilities import pump, show_mouse_cursor, hide_mouse_cursor

        # At start of every trial, before setup_response_collector or trial_prep are run, retrieve
        # the values of the independent variables (factors) for that trial (as generated earlier by
        # TrialFactory) and set them as attributes of the experiment object.
        factors = list(self.trial_factory.exp_factors.keys())
        for iv in factors:
            iv_value = trial[factors.index(iv)]
            setattr(self, iv, iv_value)

        pump()
        self.setup_response_collector()
        self.trial_prep()
        tx = None
        try:
            if P.development_mode and (P.dm_trial_show_mouse or
                                       (P.eye_tracking
                                        and not P.eye_tracker_available)):
                show_mouse_cursor()
            self.evm.start_clock()
            if P.eye_tracking and not P.manual_eyelink_recording:
                self.el.start(P.trial_number)
            P.in_trial = True
            self.__log_trial__(self.trial())
            P.in_trial = False
            if P.eye_tracking and not P.manual_eyelink_recording:
                self.el.stop()
            if P.development_mode and (P.dm_trial_show_mouse or
                                       (P.eye_tracking
                                        and not P.eye_tracker_available)):
                hide_mouse_cursor()
            self.evm.stop_clock()
            self.trial_clean_up()
        except TrialException as e:
            P.trial_id = False
            self.trial_clean_up()
            self.evm.stop_clock()
            tx = e
        if P.eye_tracking and not P.manual_eyelink_recording:
            # todo: add a warning, here, if the recording hasn't been stopped when under manual control
            self.el.stop()
        if tx:
            raise tx
Exemple #10
0
 def collect_response(self):
     self.start = time.time()
     finished = False
     selection = None
     last_selected = None
     flush()
     mt_start = None
     while not finished:
         show_mouse_cursor()
         events = pump(True)
         for e in events:
             if e.type == sdl2.SDL_KEYDOWN:
                 ui_request(e.key.keysym)
             elif e.type == sdl2.SDL_MOUSEBUTTONDOWN:
                 selection = None
                 for b in self.buttons:
                     if self.within_boundary(b.button_text,
                                             [e.button.x, e.button.y]):
                         self.toggle(b)
                         if not self.rt:
                             self.rt = time.time() - self.start
                             mt_start = time.time()
                         if b.active:
                             selection = b
                             last_selected = b
                             if callable(b.callback):
                                 if self.finish_b is None:
                                     return b.callback
                                 else:
                                     b.callback()
                     try:
                         if self.finish_b.active and self.within_boundary(
                                 "Done", [e.button.x, e.button.y]):
                             self.response = int(last_selected.button_text)
                             self.mt = time.time() - mt_start
                             finished = True
                     except AttributeError:
                         pass
         try:
             self.finish_b.active = selection is not None
         except AttributeError:
             pass
         self.render()
     fill()
     flip()
     hide_mouse_cursor()
Exemple #11
0
    def collect(self):

        show_mouse_cursor()
        onset = time.time()

        while self.scale.response == None:
            q = pump(True)
            ui_request(queue=q)
            fill()
            blit(self.q, location=self.origin, registration=8)
            self.scale.response_listener(q)
            flip()

        response = self.scale.response
        rt = time.time() - onset
        hide_mouse_cursor()
        self.scale.response = None  # reset for next time
        return Response(response, rt)
Exemple #12
0
    def trial_prep(self):
        if self.search_type == SPACE:
            self.search_stimuli = self.prepare_spatial_array()
            self.rc.display_callback = self.present_spatial_array
            self.rc.display_kwargs = {'spatial_array': self.search_stimuli}

        else:
            self.search_stimuli = self.prepare_temporal_stream()
            self.rc.display_callback = self.present_temporal_stream
            self.rc.display_kwargs = {'temporal_stream': self.search_stimuli}

        events = [[1000, 'present_example_target']]
        events.append([events[-1][0] + 1000, 'present_fixation'])
        events.append([events[-1][0] + 1000, 'search_onset'])

        for e in events:
            self.evm.register_ticket(ET(e[1], e[0]))

        self.trial_sw = Stopwatch()
        self.present_target()
        hide_mouse_cursor()
    def trial(self):
        hide_mouse_cursor()

        while self.evm.before('cue_on'):
            ui_request()

        self.display_refresh(cue=self.cue_type, tone=self.tone_trial)

        while self.evm.before('cue_off'):
            ui_request()

        self.display_refresh()

        while self.evm.before('target_on'):
            ui_request()

        self.rc.collect()

        if self.rc.keypress_listener.response_count != 0:
            response, rt = self.rc.keypress_listener.response()

        else:
            response, rt = NA, NA

        self.present_feedback(rt=rt, response=response)

        clear()

        return {
            "block_num": P.block_number,
            "trial_num": P.trial_number,
            "practicing": str(P.practicing),
            'cue_type': self.cue_type,
            'ctoa': self.ctoa,
            'target_loc': self.target_loc,
            'target_side': self.target_side,
            'tone_trial': str(self.tone_trial),
            'response': response,
            'rt': rt
        }
Exemple #14
0
	def drift_correct(self, location=None, target=None, fill_color=None, draw_target=True):
		"""Checks the accuracy of the EyeLink's calibration by presenting a fixation stimulus
		and requiring the participant to press the space bar while looking directly at it. If
		there is a large difference between the gaze location at the time the key was pressed
		and the true location of the fixation, it indicates that there has been drift in the
		calibration.

		On older EyeLink models (EyeLink I & II), the recorded drift is used to adjust the
		calibration for improved accuracy on future trials. On recent models (EyeLink 1000 and
		up), drift corrections will *check* for drift and prompt the participant to try again
		if the drift is large, but they do not affect the tracker's calibration.

		Args:
			location (Tuple(int, int), optional): The (x,y) pixel coordinates where the drift
				correct target should be located. Defaults to the center of the screen.
			target: A :obj:`Drawbject` or other :func:`KLGraphics.blit`-able shape to use as
				the drift correct target. Defaults to a circular :func:`drift_correct_target`.
			fill_color: A :obj:`List` or :obj:`Tuple` containing an RGBA colour to use for the
				background for the drift correct screen. Defaults to the value of
				``P.default_fill_color``.
			draw_target (bool, optional): A flag indicating whether the function should draw
				the drift correct target itself (True), or whether it should leave it to the
				programmer to draw the target before :meth:`drift_correct` is called (False). 
				Defaults to True.

		Raises:
			TrialException: If repeated EyeLink errors are encountered while attempting to
				perform the drift correct.

		"""
		hide_mouse_cursor()

		target = drift_correct_target() if target is None else target
		draw_target = EL_TRUE if draw_target in [EL_TRUE, True] else EL_FALSE
		location = P.screen_c if location is None else location
		if not valid_coords(location):
			raise ValueError("'location' must be a pair of (x,y) pixel coordinates.")

		try:
			while True:
				if draw_target == EL_TRUE:
					fill(P.default_fill_color if not fill_color else fill_color)
					blit(target, 5, location)
					flip()
				ret = self.doDriftCorrect(location[0], location[1], draw_target, EL_TRUE)
				if ret != 27: # 27 means we hit Esc to enter calibration, so redo drift correct
					break
			if draw_target == EL_TRUE:
				fill(P.default_fill_color if not fill_color else fill_color)
				flip()
			return self.applyDriftCorrect()
		except RuntimeError:
			try:
				self.setOfflineMode()
			except RuntimeError:
				self._unresolved_exceptions += 1
				if self._unresolved_exceptions > 5:
					cso("\n<red>*** Fatal Error: Unresolvable EyeLink Error ***</red>")
					print(full_trace())
					self._unresolved_exceptions = 0
					raise TrialException("EyeLink not ready.")
			return self.drift_correct(location, target, fill_color, draw_target)
Exemple #15
0
    def give_instructions(self):
        button_map = {
            'North':
            message("8", align='center', blit_txt=False, style='greentext'),
            'East':
            message("6", align='center', blit_txt=False, style='greentext'),
            'South':
            message("2", align='center', blit_txt=False, style='greentext'),
            'West':
            message("4", align='center', blit_txt=False, style='greentext'),
            'NorthEast':
            message("9", align='center', blit_txt=False, style='greentext'),
            'NorthWest':
            message("7", align='center', blit_txt=False, style='greentext'),
            'SouthWest':
            message("1", align='center', blit_txt=False, style='greentext'),
            'SouthEast':
            message("3", align='center', blit_txt=False, style='greentext')
        }

        hide_mouse_cursor()

        txt = (
            "In this experiment, your task is to indicate the location of the target 'o'\n"
            "while ignoring the distractor '+'."
            "\n\n(press the '5' on the numpad to continue past each message)")

        instruction_msg = message(txt, align='center', blit_txt=False)

        fill()
        blit(instruction_msg, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        txt = (
            "Each trial will begin with a fixation cross, when you see this\n"
            "you may begin the trial by pressing the '5' key on the numpad.\n"
            "Shortly after which an array will appear")

        instruction_msg = message(txt, align='center', blit_txt=False)

        fill()
        blit(instruction_msg,
             location=(P.screen_c[0], int(P.screen_c[1] * 0.3)),
             registration=5)
        blit(self.fixation, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        fill()
        blit(instruction_msg,
             location=(P.screen_c[0], int(P.screen_c[1] * 0.3)),
             registration=5)
        for value in self.probe_locs.values():
            blit(self.placeholder, registration=5, location=value[0])
        blit(self.fixation, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        txt = (
            "Shortly after the array appears, both the target 'o' and distractor '+'\n"
            "will appear in random locations within the array...")

        instruction_msg = message(txt, align='center', blit_txt=False)

        t_loc = self.prime_locs[1][0]
        d_loc = self.prime_locs[3][0]

        fill()
        blit(instruction_msg,
             location=(P.screen_c[0], int(P.screen_c[1] * 0.3)),
             registration=5)
        for value in self.probe_locs.values():
            blit(self.placeholder, registration=5, location=value[0])
        blit(self.target, location=t_loc, registration=5)
        blit(self.distractor, location=d_loc, registration=5)
        blit(self.fixation, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        txt = (
            "Once they appear, please indicate the location of the 'o' as quickly and\n"
            "accurately as possible, using the numpad ('8' for North, '9' for Northeast, etc.,)\n"
            "Each trial will actually consist of two displays, each requiring their own response,\n"
            "one after the other")

        instruction_msg = message(txt, align='center', blit_txt=False)

        fill()
        blit(instruction_msg,
             location=(P.screen_c[0], int(P.screen_c[1] * 0.3)),
             registration=5)
        for value in self.probe_locs.values():
            blit(self.placeholder, registration=5, location=value[0])
            blit(button_map[value[1]], registration=5, location=value[0])
        blit(self.target, location=t_loc, registration=5)
        blit(self.distractor, location=d_loc, registration=5)
        blit(self.fixation, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        txt = (
            "Once you have made both responses, you will be provided with feedback,\n"
            "the upper and lower line referring to your performance\n"
            "in the first and second display, respectively.\n"
            "Please press spacebar to skip past the feedback display")

        instruction_msg = message(txt, align='center', blit_txt=False)

        fill()
        blit(instruction_msg, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        txt = "For correct responses, your reaction time will be provided to you."
        fb_txt = "360\n412"

        instruction_msg = message(txt, align='center', blit_txt=False)
        fb_msg = message(fb_txt, align='center', blit_txt=False)

        fill()
        blit(instruction_msg,
             location=(P.screen_c[0], int(P.screen_c[1] * 0.3)),
             registration=5)
        blit(fb_msg, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        txt = "For incorrect responses, your reaction time will be replaced by the word WRONG."
        fb_txt = "323\nWRONG"

        instruction_msg = message(txt, align='center', blit_txt=False)
        fb_msg = message(fb_txt, align='center', blit_txt=False)

        fill()
        blit(instruction_msg,
             location=(P.screen_c[0], int(P.screen_c[1] * 0.3)),
             registration=5)
        blit(fb_msg, location=P.screen_c, registration=5)
        flip()

        self.continue_on()

        continue_txt = (
            "Throughout the task, please keep your fingers rested on the numpad,\n"
            "with your middle finger resting on the '5' key\n\n"
            "The experiment will begin with a short practice round to familiarize you with the task\n\n"
            "When you're ready, press the '5' key to begin...")

        continue_msg = message(continue_txt, align='center', blit_txt=False)

        fill()
        blit(continue_msg, location=P.screen_c, registration=5)
        flip()

        self.continue_on()
Exemple #16
0
    def trial(self):
        hide_mouse_cursor()

        # Begin with empty array...
        self.present_empty_array()

        smart_sleep(500)

        # 500ms later present prime array & record response
        self.prime_rc.collect()

        # If response, log, otherwise NA
        response_prime, rt_prime = 'NA', 'NA'

        if len(self.prime_rc.keypress_listener.response()):
            response_prime, rt_prime = self.prime_rc.keypress_listener.response(
            )

        # Reset to empty array following response
        self.present_empty_array()

        smart_sleep(300)

        # 300ms later present probe array
        self.probe_rc.collect()

        response_probe, rt_probe = 'NA', 'NA'

        if len(self.probe_rc.keypress_listener.response()):
            response_probe, rt_probe = self.probe_rc.keypress_listener.response(
            )

        # Determine accuracy of responses (i.e., whether target selected)
        prime_correct = response_prime == self.T_prime_loc[1]
        probe_correct = response_probe == self.T_probe_loc[1]

        # Present feedback on performance (mean RT for correct, 'WRONG' for incorrect)
        self.present_feedback(prime_correct, rt_prime, probe_correct, rt_probe)

        prime_choice, probe_choice = 'NA', 'NA'

        if response_prime == self.T_prime_loc[1]:
            prime_choice = 'target'
        elif response_prime == self.D_prime_loc[1]:
            prime_choice = 'distractor'
        else:
            prime_choice = "empty_cell"

        if response_probe == self.T_probe_loc[1]:
            probe_choice = 'target'
        elif response_probe == self.D_probe_loc[1]:
            probe_choice = 'distractor'
        else:
            probe_choice = "empty_cell"

        return {
            "block_num": P.block_number,
            "trial_num": P.trial_number,
            "practicing": str(P.practicing),
            "far_near": self.far_or_near,
            'trial_type': self.trial_type,
            'prime_rt': rt_prime,
            'probe_rt': rt_probe,
            'prime_correct': str(prime_correct),
            'probe_correct': str(probe_correct),
            't_prime_to_t_probe': self.T_prime_to_T_probe,
            't_prime_to_d_probe': self.T_prime_to_D_probe,
            'd_prime_to_t_probe': self.D_prime_to_T_probe,
            'd_prime_to_d_probe': self.D_prime_to_D_probe,
            'prime_choice': prime_choice,
            'probe_choice': probe_choice,
            'prime_response': response_prime,
            'probe_response': response_probe,
            't_prime_loc': self.T_prime_loc[1],
            'd_prime_loc': self.D_prime_loc[1],
            't_probe_loc': self.T_probe_loc[1],
            'd_probe_loc': self.D_probe_loc[1]
        }