Ejemplo n.º 1
0
def create_common_experiment_objects(exp_info):
    """
    Create configuration for the experiment - object common to several paradigms.
    
    exp_info.trials must be set before calling this function.

    :param exp_info: 
    :type exp_info: trajtracker.paradigms.num2pos.ExperimentInfo
    """

    if exp_info.trials is None:
        raise ttrk.InvalidStateError('Please update exp_info.trials before calling create_common_experiment_objects()')

    create_start_point(exp_info)
    create_textbox_target(exp_info)
    create_generic_target(exp_info)
    create_fixation(exp_info)
    create_errmsg_textbox(exp_info)
    create_traj_tracker(exp_info)
    create_validators(exp_info, direction_validator=True, global_speed_validator=True,
                      inst_speed_validator=True, zigzag_validator=True)
    create_confidence_slider(exp_info)

    #-- Initialize experiment-level data
    exp_info.exp_data['WindowWidth'] = exp_info.screen_size[0]
    exp_info.exp_data['WindowHeight'] = exp_info.screen_size[1]
    exp_info.exp_data['nExpectedTrials'] = len(exp_info.trials)
    exp_info.exp_data['nTrialsCompleted'] = 0
    exp_info.exp_data['nTrialsFailed'] = 0
    exp_info.exp_data['nTrialsSucceeded'] = 0
Ejemplo n.º 2
0
    def right_resp_text(self, target):
        if self._right_resp_text is not None:
            raise ttrk.InvalidStateError(
                "ExperimentInfo.right_resp_text cannot be set twice")

        self._right_resp_text = target
        self.stimuli.add(target.stimulus, "right_resp_text")
Ejemplo n.º 3
0
 def trial_configured_event(self, event):
     _u.validate_attr_type(self, "registration_event", event, Event)
     if self._event_manager is not None:
         raise ttrk.InvalidStateError(("{:}.trial_configured_event cannot be changed after " +
                                       "registering to the event manager".format(_u.get_type_name(self))))
     self._trial_configured_event = event
     self._log_property_changed("trial_configured_event")
Ejemplo n.º 4
0
    def save_to_file(self, trial_num):
        """
        Save the tracked trajectory (ever since the last reset() call) to a CSV file

        :param trial_num:
        :return: The number of rows printed to the file
        """
        if self._filename is None:
            raise trajtracker.InvalidStateError(
                'TrajectoryTracker.save_to_file() was called before calling init_output_file()'
            )

        fh = self._open_file(self._filename, 'a')

        rows = self.get_xyt()
        for x, y, t in rows:
            x = ('%d' %
                 x) if isinstance(x, int) else '%.*f' % (self._xy_precision, x)
            y = ('%d' %
                 y) if isinstance(y, int) else '%.*f' % (self._xy_precision, y)
            fh.write("%d,%.*f,%s,%s\n" %
                     (trial_num, self._time_precision, t, x, y))

        fh.close()

        if self._log_level:
            expyriment._active_exp._event_file_log(
                "Trajectory,SavedTrial,%s,%d,%d" %
                (self._filename, trial_num, len(rows)), 2)

        return len(rows)
    def _validate_time(self, time):

        if len(self._prev_locations
               ) > 0 and self._prev_locations[-1][2] > time:
            raise trajtracker.InvalidStateError(
                "{0}.mouse_at() was called with time={1} after it was previously called with time={2}"
                .format(self.__class__, time, self._prev_locations[-1][2]))
Ejemplo n.º 6
0
    def save_to_file(self, trial_num):
        """
        Save the tracked trajectory (ever since the last reset() call) to a CSV file

        :param trial_num:
        :return: The number of rows printed to the file
        """
        if not self._out_file_initialized:
            raise ttrk.InvalidStateError(
                'TrajectoryTracker.save_to_file() was called before calling init_output_file()'
            )

        fh = self._open_file(self._filename, 'a')

        rows = self.get_xyt()
        for x, y, t in rows:
            x = ('%d' %
                 x) if isinstance(x, int) else '%.*f' % (self._xy_precision, x)
            y = ('%d' %
                 y) if isinstance(y, int) else '%.*f' % (self._xy_precision, y)
            fh.write("%d,%.*f,%s,%s\n" %
                     (trial_num, self._time_precision, t, x, y))

        fh.close()

        self._log_write_if(
            ttrk.log_debug, "Saved trial #{:} (with {:} rows) to {:}".format(
                trial_num, len(rows), self._filename), True)

        return len(rows)
Ejemplo n.º 7
0
    def target_pointer(self, value):
        if self._target_pointer is not None:
            raise ttrk.InvalidStateError(
                "ExperimentInfo.target_pointer cannot be set twice")

        self._target_pointer = value
        self.stimuli.add(value, "target_pointer", visible=False)
Ejemplo n.º 8
0
 def numberline(self, nl):
     if self._numberline is not None:
         raise ttrk.InvalidStateError(
             "ExperimentInfo.numberline cannot be set twice")
     self._numberline = nl
     self.stimuli.add(nl, "numberline")
     self._trajectory_sensitive_objects.append(nl)
     self._event_sensitive_objects.append(nl)
Ejemplo n.º 9
0
 def can_exit_in_any_direction(self, value):
     if self._preloaded:
         raise ttrk.InvalidStateError(
             "{:}.can_exit_in_any_direction cannot be set after the object was preloaded"
             .format(_u.get_type_name(self)))
     _u.validate_attr_type(self, "can_exit_in_any_direction", value, bool)
     self._can_exit_in_any_direction = value
     self._log_property_changed("can_exit_in_any_direction")
Ejemplo n.º 10
0
    def _validate_time(self, time):

        #-- Validate that times are provided in increasing order
        prev_time = self._recent_points[-1][2] if len(
            self._recent_points) > 0 else self._time0
        if prev_time is not None and prev_time > time:
            raise trajtracker.InvalidStateError(
                "{0}.update_xyt() was called with time={1} after it was previously called with time={2}"
                .format(self.__class__, time, prev_time))
Ejemplo n.º 11
0
    def colour(self, value):
        if self._preloaded:
            raise ttrk.InvalidStateError(
                "{:}.colour cannot be set after the object was preloaded".
                format(_u.get_type_name(self)))

        _u.validate_attr_rgb(self, "colour", value)
        self._colour = value

        self._log_property_changed("colour")
Ejemplo n.º 12
0
    def get_traj_point(self, time):
        """
        Return the trajectory info at a certain time

        :param time: in seconds
        :returns: a dict with the coordinates ('x' and 'y' entries).
        """

        _u.validate_func_arg_type(self, "get_xy", "time", time, numbers.Number)
        if self._start_point is None:
            raise trajtracker.InvalidStateError(
                "{:}.get_xy() was called without setting start_point".format(
                    _u.get_type_name(self)))
        if self._end_point is None:
            raise trajtracker.InvalidStateError(
                "{:}.get_xy() was called without setting end_point".format(
                    _u.get_type_name(self)))
        if self._duration is None:
            raise trajtracker.InvalidStateError(
                "{:}.get_xy() was called without setting duration".format(
                    _u.get_type_name(self)))

        max_duration = self._duration * (2 if self._return_to_start else 1)
        if self._cyclic:
            time = time % max_duration
        else:
            time = min(time, max_duration)

        if time > self._duration:
            #-- Returning to start
            time -= self._duration
            start_pt = self._end_point
            end_pt = self._start_point
        else:
            start_pt = self._start_point
            end_pt = self._end_point

        time_ratio = time / self._duration
        x = start_pt[0] + time_ratio * (end_pt[0] - start_pt[0])
        y = start_pt[1] + time_ratio * (end_pt[1] - start_pt[1])

        return dict(x=x, y=y)
Ejemplo n.º 13
0
    def rotation(self, value):
        if self._preloaded:
            raise ttrk.InvalidStateError(
                "{:}.rotation cannot be set after the object was preloaded".
                format(_u.get_type_name(self)))

        _u.validate_attr_numeric(self, "rotation", value)
        value = value % 360
        self._rotation = value

        self._log_property_changed("rotation")
Ejemplo n.º 14
0
    def mark_as_initialized(self):
        """
        Force the StartPoint object into an "init" :attr:`~trajtracker.movement.StartPoint.State`, as if
        it was touched by the mouse/finger. This is useful in case trial initiation was triggered in another way.
        """
        if self._state not in (StartPoint.State.reset,
                               StartPoint.State.mouse_up):
            raise ttrk.InvalidStateError(
                "StartPoint.mark_as_initialized() called but the StartPoint's present state is {:}"
                .format(self._state))

        self._state = StartPoint.State.init
Ejemplo n.º 15
0
 def enable_events(self, value):
     value = _u.validate_attr_is_collection(self,
                                            "enable_events",
                                            value,
                                            none_allowed=True)
     for v in value:
         _u.validate_attr_type(self, "enable_events", v, Event)
     if self._registered:
         raise trajtracker.InvalidStateError(
             "{:}.enable_events cannot be set after the object was registered to the event manager"
             .format(_u.get_type_name(self)))
     self._enable_events = tuple(value)
     self._log_property_changed("enable_events")
Ejemplo n.º 16
0
    def on_registered(self, event_manager):

        if self.enable_event is None:
            raise trajtracker.InvalidStateError(
                "{:} was registered to an event manager before updating enable_event"
                .format(_u.get_type_name(self)))

        #-- Intercept the event that indicates when the movement started

        if self._registered:
            raise trajtracker.InvalidStateError(
                "{:} cannot be registered twice to an event manager".format(
                    _u.get_type_name(self)))

        # noinspection PyUnusedLocal
        def callback_start(time_in_trial, time_in_session):
            self.movement_started(time_in_trial)

        event_manager.register_operation(
            self.enable_event,
            callback_start,
            recurring=True,
            description="{:}.movement_started()".format(
                _u.get_type_name(self)))

        #-- Intercept the event that indicates when the movement terminates

        # noinspection PyUnusedLocal
        def callback_end(t1, t2):
            if self._show_guide:
                self._guide.stimulus.visible = False
                self._should_set_guide_visible = False

        event_manager.register_operation(
            self.disable_event,
            callback_end,
            recurring=True,
            description="{:}: hide speed guide".format(_u.get_type_name(self)))
Ejemplo n.º 17
0
    def get_traj_point(self, time):
        """
        Return the trajectory info at a certain time

        :param time: in seconds
        :returns: a dict with the coordinates ('x' and 'y' entries).
        """

        _u.validate_func_arg_type(self, "get_xy", "time", time, numbers.Number)
        if not hasattr(self, "_center"):
            raise trajtracker.InvalidStateError(
                "trajtracker error: {:}.get_xy() was called without setting center"
                .format(type(self).__name__))
        if not hasattr(self, "_degrees_per_sec"):
            raise trajtracker.InvalidStateError(
                "trajtracker error: {:}.get_xy() was called without setting degrees_per_sec"
                .format(type(self).__name__))
        if not hasattr(self, "_radius"):
            raise trajtracker.InvalidStateError(
                "trajtracker error: {:}.get_xy() was called without setting radius"
                .format(type(self).__name__))

        curr_degrees = (self._degrees_at_t0 +
                        self._degrees_per_sec * time) % 360

        curr_degrees_rad = curr_degrees / 360 * np.pi * 2

        x = int(np.abs(np.round(self._radius * np.sin(curr_degrees_rad))))
        y = int(np.abs(np.round(self._radius * np.cos(curr_degrees_rad))))

        if curr_degrees > 180:
            x = -x
        if 90 < curr_degrees < 270:
            y = -y

        return {'x': x + self._center[0], 'y': y + self._center[1]}
Ejemplo n.º 18
0
    def show(self):
        """
        Show the dots in the virtual rectangle's corners
        """
        self._log_func_enters("show")

        if self._need_to_regenerate_dots:
            raise ttrk.InvalidStateError(
                '{:}.show() was called without calling reset() first'.format(
                    _u.get_type_name(self)))

        self._set_dot_position_for_time(0)
        self._start_zoom_time = None
        self._now_visible = True

        for dot in self._dots:
            dot.visible = True
Ejemplo n.º 19
0
    def position(self, value):
        if self._preloaded:
            raise ttrk.InvalidStateError(
                "{:}.position cannot be set after the object was preloaded".
                format(_u.get_type_name(self)))

        if value is None:
            self._position = None

        else:
            _u.validate_attr_is_collection(self, "size", value, 2, 2)
            _u.validate_attr_numeric(self, "size[0]", value[0])
            _u.validate_attr_numeric(self, "size[1]", value[1])

            self._position = (int(value[0]), int(value[1]))

        self._log_property_changed("position")
Ejemplo n.º 20
0
    def show(self, coord, line_mode):

        if self._guide_line is None:
            self._create_guide_line(
            )  # try creating again. Maybe the experiment was inactive
            if self._guide_line is None:
                raise trajtracker.InvalidStateError(
                    "The visual guide for {:} cannot be created because the experiment is inactive"
                    .format(GlobalSpeedValidator.__name__))

        _u.validate_func_arg_type(self, "show", "coord", coord, int)
        _u.validate_func_arg_type(self, "show", "line_mode", line_mode,
                                  self.LineMode)

        self._guide_line.activate(line_mode)

        pos = (coord,
               0) if self._validator.axis == ValidationAxis.x else (0, coord)
        self._guide_line.position = pos
        self._guide_line.present(clear=False, update=False)
Ejemplo n.º 21
0
    def current_value(self, value):
        _u.validate_func_arg_type(self,
                                  "set_current_value",
                                  "value",
                                  value,
                                  Number,
                                  none_allowed=True)

        if self._locked:
            raise ttrk.InvalidStateError(
                "{:}.current_value cannot be changed - the slider is locked".
                format(_u.get_type_name(self)))

        self._current_value = None if value is None else self._crop_value(
            value)

        self.gauge_stimulus.visible = self.visible and (value is not None)
        if value is not None:
            self._move_gauge_to_coord(self._value_to_coord(
                self._current_value))
Ejemplo n.º 22
0
    def show(self, coord, line_mode):

        self._log_func_enters("show", [coord, line_mode])

        if self._guide_line is None:
            self._create_guide_line(
            )  # try creating again. Maybe the experiment was inactive
            if self._guide_line is None:
                raise trajtracker.InvalidStateError(
                    "The visual guide for {:} cannot be created because the experiment is inactive"
                    .format(_u.get_type_name(self)))

        _u.validate_func_arg_type(self, "show", "coord", coord, int)
        _u.validate_func_arg_type(self, "show", "line_mode", line_mode,
                                  self.LineMode)

        self._guide_line.activate(line_mode)

        pos = (coord,
               0) if self._validator.axis == ValidationAxis.x else (0, coord)
        self._guide_line.position = pos
Ejemplo n.º 23
0
 def _validate_unlocked(self):
     if self._preloaded:
         raise trajtracker.InvalidStateError(
             'An attempt was made to change the visual properties of a NumberLine after it was already plotted'
         )
Ejemplo n.º 24
0
    def check_xyt(self, x_coord, y_coord, time):
        """
        Validate movement.

        :param x_coord:
        :type x_coord: int

        :param y_coord:
        :type y_coord: int

        :param time: Time from start of trial
        :returns: None if all OK; ValidationFailed object if error
        """

        self._check_xyt_validate_and_log(x_coord, y_coord, time)
        self._assert_initialized(self._origin_coord, "origin_coord")
        self._assert_initialized(self._end_coord, "end_coord")
        self._assert_initialized(self._max_trial_duration,
                                 "max_trial_duration")

        if not self._enabled:
            return None

        #-- If this is the first call in a trial: do nothing
        if self._time0 is None:
            self.reset(time)
            return None

        if time < self._time0:
            raise trajtracker.InvalidStateError(
                "{0}.check_xyt() was called with time={1}, but the trial started at time={2}"
                .format(self.__class__, time, self._time0))

        time -= self._time0

        #-- Get the expected and actual coordinates
        coord = x_coord if self._axis == ValidationAxis.x else y_coord
        expected_coord = int(self.get_expected_coord_at_time(time))
        d_coord = coord - expected_coord

        #-- No validation during grace period
        if time <= self._grace_period:
            if self._show_guide:
                self._guide.show(expected_coord,
                                 GlobalSpeedGuide.LineMode.Grace)
            return None

        #-- Actual coordinate must be ahead of the expected minimum
        if d_coord != 0 and np.sign(d_coord) != np.sign(self._end_coord -
                                                        self._origin_coord):
            return self._create_validation_error(
                self.err_too_slow, "You moved too slowly", {
                    self.arg_expected_coord: expected_coord,
                    self.arg_actual_coord: coord
                })

        if self._show_guide:
            # Get the coordinate that the mouse/finger should reach shortly
            coord_expected_soon = self.get_expected_coord_at_time(
                time + self._guide_warning_time_delta)

            # check if mouse/finger already reached this coordinate
            reached_expected_soon = d_coord == 0 or np.sign(
                coord - coord_expected_soon) == np.sign(self._end_coord -
                                                        self._origin_coord)

            # set guide color accordingly
            self._guide.show(
                expected_coord, GlobalSpeedGuide.LineMode.OK
                if reached_expected_soon else GlobalSpeedGuide.LineMode.Error)

        return None
Ejemplo n.º 25
0
 def _assert_initialized(self, value, attr_name):
     if value is None:
         raise trajtracker.InvalidStateError(
             "{:}.check_xyt() was called before {:} was initalized".format(
                 type(self).__name__, attr_name))
Ejemplo n.º 26
0
    def wait_until_startpoint_touched(self,
                                      exp,
                                      on_loop_callback=None,
                                      on_loop_present=None,
                                      event_manager=None,
                                      trial_start_time=None,
                                      session_start_time=None,
                                      max_wait_time=None):
        """
        Wait until the starting point is touched.
        
        The *on_loop_xxx* and *event_manager* parameters define what to do on each iteration of the loop that  
        waits for the area to be touched. 
        If neither on_loop_callback nor on_loop_present are provided, the function will wait for 15 ms 
        on each loop iteration.
        
        If several on_loop parameters are provided, they will be invoked in this order:
        *callback - event manager.on_frame() - present()*.
        
        :param exp: The Expyriment experiment object
        :param on_loop_callback: A function (without arguments) to call on each loop iteration.
                                If the function returns any value other than *None*, the waiting will
                                be terminated and that value will be returned.
        :param on_loop_present: A visual object that will be present()ed on each loop iteration.
        :param event_manager: The event manager's on_frame() will be called on each loop iteration.
                              If you provide an event manager, you also have to provide trial_start_time and
                              session_start_time (whose values were obtained by :func:`trajtracker.utils.get_time`
        :param max_wait_time: Maximal time (in seconds) to wait
        :return: The value returned by the on_loop_callback function (in case it returned anything other than None).
                 Otherwise the function returns None. Use :attr:`~trajtracker.movement.StartPoint.state` to
                 learn about the StartPoint's exit status.
        """

        self._log_func_enters(
            "wait_until_startpoint_touched",
            ["exp", on_loop_callback, on_loop_present, event_manager])

        _u.validate_func_arg_type(self,
                                  "wait_until_startpoint_touched",
                                  "max_wait_time",
                                  max_wait_time,
                                  numbers.Number,
                                  none_allowed=True)
        _u.validate_func_arg_not_negative(self,
                                          "wait_until_startpoint_touched",
                                          "max_wait_time", max_wait_time)
        if event_manager is not None:
            _u.validate_func_arg_type(self,
                                      "wait_until_startpoint_touched",
                                      "trial_start_time",
                                      trial_start_time,
                                      numbers.Number,
                                      none_allowed=True)
            _u.validate_func_arg_type(self, "wait_until_startpoint_touched",
                                      "session_start_time", session_start_time,
                                      numbers.Number)

        if self._state != StartPoint.State.reset:
            raise ttrk.InvalidStateError(
                "{:}.wait_until_startpoint_touched() was called without calling reset() first"
                .format(_u.get_type_name(self)))

        time_started_waiting = u.get_time()

        # The "StartPoint" object is expected to run through these states, in this order:
        # State.reset - after the trial initialized
        # State.mouse_up - after the mouse/finger was unclicked/lifted
        # State.init - when the screen was touched/clicked (this is when this function returns)

        while True:

            if not ttrk.env.mouse.check_button_pressed(
                    0) and self._state == StartPoint.State.reset:
                # Mouse/finger is UP
                self._state = StartPoint.State.mouse_up
                self._log_write_if(ttrk.log_debug,
                                   "Mouse unclicked. Setting state=mouse_up",
                                   True)

            elif ttrk.env.mouse.check_button_pressed(
                    0) and self._state == StartPoint.State.mouse_up:
                # Mouse/finger touched the screen
                finger_pos = ttrk.env.mouse.position
                self.check_xy(finger_pos[0], finger_pos[1])

            if max_wait_time is not None and u.get_time(
            ) - time_started_waiting >= max_wait_time:
                self._log_func_returns("wait_until_startpoint_touched", False)
                self._state = StartPoint.State.timeout
                return None

            if self._state == StartPoint.State.init:
                break  # Screen touched - we're done here

            # Invoke custom operations on each loop iteration

            if on_loop_callback is not None:
                retval = on_loop_callback()
                if retval is not None:
                    return retval

            if event_manager is not None:
                curr_time = u.get_time()
                event_manager.on_frame(
                    None if trial_start_time is None else curr_time -
                    trial_start_time, curr_time - session_start_time)

            if on_loop_present is not None:
                on_loop_present.present()

            if on_loop_present is None and on_loop_callback is None:
                exp.clock.wait(15)

            xpy.io.Keyboard.process_control_keys()

        self._log_func_returns("wait_until_startpoint_touched", True)
        return None
Ejemplo n.º 27
0
    def get_traj_point(self, time):
        """
        Generate the trajectory - get one time point data

        :param time: in seconds
        :return: (x, y, visible)
        """

        self.validate()

        _u.validate_func_arg_type(self, "get_traj_point", "time", time, numbers.Number)
        _u.validate_func_arg_not_negative(self, "get_traj_point", "time", time)

        if self._active_traj_id is None:
            if len(self._trajectories):
                self.active_traj_id = self._trajectories.keys()[0]
            else:
                raise trajtracker.InvalidStateError("{:}.get_traj_point() cannot be called before active_traj_id was set".format(type(self).__name__))

        traj_inf = self._trajectories[self._active_traj_id]

        if time < traj_inf['times'][0]:
            raise ValueError("trajtracker error in {:}.get_traj_point(time={:}): the active trajectory ({:}) starts from time={:}".format(
                type(self).__name__, time, self._active_traj_id, traj_inf['times'][0]))

        #-- Time can't exceed the trajectory duration
        if time > traj_inf['duration']:
            time = time % traj_inf['duration'] if self._cyclic else traj_inf['duration']

        traj_times = traj_inf['times']
        traj_xy = traj_inf['coords']
        traj_visible = traj_inf['visible']


        ind_before_time = np.where(traj_times <= time)[0][-1]
        time_before = traj_times[ind_before_time]

        coord_before = traj_xy[ind_before_time]
        visible_before = traj_visible[ind_before_time]

        if time_before == time:
            ind_after_time = ind_before_time
            time_after = time_before
        else:
            ind_after_time = min(ind_before_time+1, len(traj_times)-1)
            time_after = traj_times[ind_after_time]

        if self._interpolate and time_before != time_after:

            #-- Coordinates: linear interpolation between the two relevant time points
            coord_after = traj_xy[ind_after_time]
            weight_of_after_ind = (time - time_before) / (time_after - time_before)
            weight_of_before_ind = 1 - weight_of_after_ind
            x = int( np.round(coord_before[0] * weight_of_before_ind + coord_after[0] * weight_of_after_ind) )
            y = int( np.round(coord_before[1] * weight_of_before_ind + coord_after[1] * weight_of_after_ind) )

            #-- Visibility: use the value from the closest available time point
            visible_after = traj_visible[ind_after_time]
            visible = visible_before if weight_of_before_ind > weight_of_after_ind else visible_after

            return x, y, visible

        else:
            #-- Return the value of the last time point before "time"
            return coord_before + (visible_before, )
Ejemplo n.º 28
0
    def update_xyt(self, position, time_in_trial, time_in_session=None):
        """
        Validate movement.

        :type position: tuple (x,y)
        :param time_in_trial: Time from start of trial
        :param time_in_session: ignored
        :returns: None if all OK; ExperimentError object if error
        """

        _u.update_xyt_validate_and_log(self, position, time_in_trial)
        self._assert_initialized(self._origin_coord, "origin_coord")
        self._assert_initialized(self._end_coord, "end_coord")
        self._assert_initialized(self._max_movement_time, "max_movement_time")

        if not self._enabled:
            return None

        #-- If this is the first call in a trial: do nothing
        if self._time0 is None:
            return

        if time_in_trial < self._time0:
            raise trajtracker.InvalidStateError(
                "{0}.update_xyt() was called with time={1}, but the movement started at time={2}"
                .format(self.__class__, time_in_trial, self._time0))

        time_in_trial -= self._time0

        #-- Get the expected and actual coordinates
        coord = position[0] if self._axis == ValidationAxis.x else position[1]
        expected_coord = int(self.get_expected_coord_at_time(time_in_trial))
        d_coord = coord - expected_coord

        #-- No validation during grace period
        if time_in_trial <= self._grace_period:
            if self._show_guide:
                self._guide.show(expected_coord,
                                 GlobalSpeedGuide.LineMode.Grace)
            if self._should_set_guide_visible:
                self._guide.stimulus.visible = True
                self._should_set_guide_visible = False
            return None

        #-- Actual coordinate must be ahead of the expected minimum
        if d_coord != 0 and np.sign(d_coord) != np.sign(self._end_coord -
                                                        self._origin_coord):
            return trajtracker.validators.create_experiment_error(
                self, self.err_too_slow, "You moved too slowly", {
                    self.arg_expected_coord: expected_coord,
                    self.arg_actual_coord: coord
                })

        if self._show_guide:
            # Get the coordinate that the mouse/finger should reach shortly
            coord_expected_soon = self.get_expected_coord_at_time(
                time_in_trial + self._guide_warning_time_delta)

            # check if mouse/finger already reached this coordinate
            reached_expected_soon = d_coord == 0 or np.sign(
                coord - coord_expected_soon) == np.sign(self._end_coord -
                                                        self._origin_coord)

            # set guide color accordingly
            self._guide.show(
                expected_coord, GlobalSpeedGuide.LineMode.OK
                if reached_expected_soon else GlobalSpeedGuide.LineMode.Error)

            if self._should_set_guide_visible:
                self._guide.stimulus.visible = True
                self._should_set_guide_visible = False

        return None
Ejemplo n.º 29
0
 def _assert_initialized(self, value, attr_name):
     if value is None:
         raise trajtracker.InvalidStateError(
             "{:}.update_xyt() was called before {:} was initalized".format(
                 _u.get_type_name(self), attr_name))