def __init__(self,
                 units_per_mm,
                 min_distance=0,
                 angle_units=Units.Degrees,
                 zero_angle=0,
                 min_angle_change_per_curve=0):
        """
        Constructor

        :param units_per_mm: See :attr:`~trajtracker.movement.DirectionMonitor.units_per_mm`
        :param min_distance: See :attr:`~trajtracker.movement.DirectionMonitor.min_distance`
        :param angle_units: See :attr:`~trajtracker.movement.DirectionMonitor.angle_units`
        :param min_angle_change_per_curve: See :attr:`~trajtracker.movement.DirectionMonitor.min_angle_change_per_curve`
        """
        super(DirectionMonitor, self).__init__()

        _u.validate_func_arg_type(self, "__init__", "units_per_mm",
                                  units_per_mm, numbers.Number)
        _u.validate_func_arg_positive(self, "__init__", "units_per_mm",
                                      units_per_mm)
        self._units_per_mm = units_per_mm

        self.min_distance = min_distance
        self.angle_units = angle_units
        self.zero_angle = zero_angle
        self.min_angle_change_per_curve = min_angle_change_per_curve

        self.reset()
    def get_traj_point(self, time):
        """
        Generate the trajectory - get one time point data

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

        _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)

        #-- Handle time-too-large
        total_duration = self.duration
        if self._cyclic:
            time = time % total_duration
        elif time >= total_duration:
            last_segment = self._segments[-1]
            return last_segment['generator'].get_traj_point(
                last_segment['duration'])

        #-- Find relevant segment
        generator, time = self._get_generator_for(time)

        #-- Get point from the relevant segment
        return generator.get_traj_point(time)
Example #3
0
    def overlapping_with_position(self, pos):

        _u.validate_func_arg_is_collection(self, "overlapping_with_position",
                                           "pos", pos, 2, 2)
        _u.validate_func_arg_type(self, "overlapping_with_position", "pos[0]",
                                  pos[0], numbers.Number)
        _u.validate_func_arg_type(self, "overlapping_with_position", "pos[1]",
                                  pos[1], numbers.Number)

        x = pos[0] - self._position[0]
        y = pos[1] - self._position[1]

        height = self._size[1]
        width = self._size[0]

        if self._rotation != 0:
            #-- Instead of rotating the rectangle - rotate the point in the opposite direction

            # Get the point's position relatively to the rectangle's center as r, alpha.
            # alpha=0 means that the point is to the right of the rectangle center
            r = np.sqrt(x**2 + y**2)
            if (x == 0):
                alpha = np.pi / 2 if y > 0 else np.pi * 3 / 2
            else:
                alpha = np.arctan(y / x)

            alpha += self._rotation_radians

            x = np.cos(alpha) * r
            y = np.sin(alpha) * r

        return -(width / 2) <= x <= width / 2 and -(height /
                                                    2) <= y <= height / 2
Example #4
0
        def __init__(self, x, y, radius, from_angle, to_angle):
            """
            Constructor

            :param x: the circle's center
            :param y: the circle's center
            :param radius:
            :param from_angle: Left end of the sector (degrees)
            :param to_angle: Right end of the sector (degrees)
            """

            _u.validate_func_arg_type(self, "__init__", "x", x, int)
            _u.validate_func_arg_type(self, "__init__", "y", y, int)
            _u.validate_func_arg_type(self, "__init__", "radius", radius, int)
            _u.validate_func_arg_type(self, "__init__", "from_angle",
                                      from_angle, int)
            _u.validate_func_arg_type(self, "__init__", "to_angle", to_angle,
                                      int)
            _u.validate_func_arg_positive(self, "__init__", "radius", radius)

            self.x = x
            self.y = y
            self.radius = radius
            self.from_angle = from_angle % 360
            self.to_angle = to_angle % 360
Example #5
0
    def add(self, stimulus, stimulus_id=None, visible=True):
        """
        Add a stimulus to the container.

        :param stimulus: An Expyriment stimulus, or any other object that has a similar present() method
        :param stimulus_id: Stimulus name. Use it later to set the stimulus as visible/invisible.
                            If not provided or None, an arbitrary ID will be generated.
        :param visible: See The stimulus ID (as defined in :func:`~trajtracker.stimuli.StimulusContainer.set_visible`)
        :return:
        """

        _u.validate_func_arg_type(self, "add", "visible", visible, bool)
        if "present" not in dir(stimulus):
            raise ttrk.TypeError(
                "invalid stimulus ({:}) in {:}.add() - expecting an expyriment stimulus"
                .format(stimulus, _u.get_type_name(self)))

        stimulus.visible = visible

        if stimulus_id is None:
            n = len(self._stimuli) + 1
            while True:
                stimulus_id = "stimulus#{:}".format(n)
                if stimulus_id in self._stimuli:
                    n += 1
                else:
                    break

        order = len(self._stimuli)
        if stimulus_id not in self._stimuli:
            order += 1

        self._stimuli[stimulus_id] = dict(id=stimulus_id,
                                          stimulus=stimulus,
                                          order=order)
Example #6
0
    def add_stimulus(self, stim_id, stimulus):
        """
        Add a stimulus to the set of available stimuli.
        
        :param stim_id: A logical name of the stimulus
        :type stim_id: str
        :param stimulus: an expyriment stimulus
        """

        _u.validate_func_arg_type(self, "add_stimulus", "stim_id", stim_id,
                                  str)
        if "is_preloaded" not in dir(stimulus) or "present" not in dir(
                stimulus):
            raise ttrk.TypeError(
                "Invalid stimulus in {:}.add_stimulus() - {:}".format(
                    _u.get_type_name(self), stimulus))

        if stim_id in self._available_stimuli and self._should_log(
                ttrk.log_warn):
            self._log_write(
                'WARNING: Stimulus "{:}" already exists in the {:}, definition will be overriden'
                .format(stim_id, _u.get_type_name(self)))

        if not stimulus.is_preloaded:
            stimulus.preload()

        self._available_stimuli[stim_id] = stimulus
        self._container.add(stimulus, stim_id, visible=False)
Example #7
0
    def __add__(self, rhs):
        """Define a new event, in a time offset relatively to an existing event"""

        _u.validate_func_arg_type(self, "+", "right operand", rhs, numbers.Number)
        if rhs < 0:
            raise trajtracker.ValueError("Invalid offset ({:}) for event {:}. Only events with positive offset are acceptable".format(
                rhs, self._event_id))

        new_event = Event(self._event_id)
        new_event._offset = self._offset + rhs
        return new_event
Example #8
0
    def show_cursor(self, show):
        """
        Show/hide the mouse pointer

        :param: show
        :type show: bool 
        """
        _u.validate_func_arg_type(self, "show_cursor", "show", show, bool)
        if show:
            self._xpy_mouse.show_cursor()
        else:
            self._xpy_mouse.hide_cursor()
Example #9
0
 def register_onset_offset_callback_func(self, func):
     """
     Register a function that should be called when a stimulus is shown/hidden
      
     :param func: The function, which gets 4 parameters:
         
         1. The MultiStimulus/MultiTextBox object
         2. The stimulus/text number (0=first)
         3. Whether the stimulus is presented (True) or hidden (False)
         4. The time when the corresponding present() function returned 
     """
     _u.validate_func_arg_type(self, "add_onset_offset_callback_func", "func", func, ttrk.TYPE_CALLABLE)
     self._onset_offset_callbacks.append(func)
    def add_segment(self, traj_generator, duration):

        _u.validate_func_arg_type(self, "add_segment", "duration", duration,
                                  numbers.Number)
        _u.validate_func_arg_positive(self, "add_segment", "duration",
                                      duration)

        if "get_traj_point" not in dir(traj_generator):
            raise trajtracker.TypeError(
                "{:}.add_segment() was called with an invalid traj_generator argument ({:})"
                .format(_u.get_type_name(self), traj_generator))

        self._segments.append(dict(generator=traj_generator,
                                   duration=duration))
Example #11
0
    def extend(self, extend_by):
        """
        Extend the rectangle by the given value
        
        :param extend_by: If a pair of values, the mean (w, h): extend the rectangle's width by w and its height by h.
                          If this is a single value, it is used for extending the width as well as the height.
        """

        if isinstance(extend_by, numbers.Number):
            extend_by = extend_by, extend_by
        else:
            _u.validate_func_arg_type(self, "extend", "extend_by", extend_by,
                                      ttrk.TYPE_SIZE)

        self.size = self._size[0] + extend_by[0], self._size[1] + extend_by[1]
    def add_segments(self, segments):

        _u.validate_func_arg_is_collection(self, "add_segments", "segments",
                                           segments)

        for i in range(len(segments)):
            segment = segments[i]
            _u.validate_func_arg_is_collection(self, "add_segments",
                                               "segments[%d]" % i, segment, 2,
                                               2)
            _u.validate_func_arg_type(self, "add_segments",
                                      "segments[%d][1]" % i, segment[1],
                                      numbers.Number)
            _u.validate_func_arg_positive(self, "add_segments",
                                          "segments[%d][1]" % i, segment[1])
            self.add_segment(segment[0], segment[1])
Example #13
0
    def unregister_recurring_callback(self, func_id):
        """
        Unregister a recurring listener function that was previously registered via 
        :func:`~trajtracker.stimuli.StimulusContainer.register_callback`
        
        :param func_id: The function ID that was provided to :func:`~trajtracker.stimuli.StimulusContainer.register_callback` 
        :return: *True* if unregistered, *False* if there is no registered recurring function with the given func_id 
        """
        _u.validate_func_arg_type(self, "unregister_recurring_callback",
                                  "func_id", func_id, str)

        if func_id in self._recurring_callbacks:
            del self._recurring_callbacks[func_id]
            return True
        else:
            return False
Example #14
0
def xy_to_pixels(value, screen_size, parameter_name):
    """
    Translate a stimulus size or position to pixels.
    
    The input is either one value (x or y) or a pair of values (x, y).
    It may denote either a stimulus size or a position.
    
    If x/y is an int value (or a pair of ints), it is left unchanged.
    If it is a float value, it is interpreted as percentage of the screen size. In this case,  
    the value should be between 0.0 and 1.0 for size, or between -0.5 and 0.5 for position (but the function will
    accept any value between -0.5 and 1.0)
    
    :param value: The value to convert - either a number or a pair of numbers  
    :param screen_size: The screen size - either a number or a pair of numbers (must match the "value" paremeter)
    :param parameter_name: If this is not None, errors will yield an exception, indicating this parameter
    :return: An int or a pair of ints (scale = pixels). If the input value is not a valid size, return None.
    """

    if isinstance(value, numbers.Number):

        #-- A single value

        if isinstance(value, int):
            return value

        elif -0.5 <= value <= 1:
            _u.validate_func_arg_type(None, "common.xy_to_pixels", "screen_size", screen_size, int)
            return int(np.round(value * screen_size))

        else:
            raise ttrk.TypeError('Invalid value of {:} ({:})'.format(parameter_name, value))

    if u.is_collection(value) and len(value) == 2 and \
            isinstance(value[0], numbers.Number) and isinstance(value[1], numbers.Number):

        #-- Pair of values
        _u.validate_func_arg_is_collection(None, "common.xy_to_pixels", "screen_size", screen_size, 2, 2)

        return xy_to_pixels(value[0], screen_size[0], "{:}[0]".format(parameter_name)), \
               xy_to_pixels(value[1], screen_size[1], "{:}[1]".format(parameter_name))

    else:
        #-- Not a valid xy
        raise ttrk.TypeError('Invalid value of {:} ({:})'.format(parameter_name, value))
Example #15
0
    def set_trajectory(self, traj_id, traj_data):
        """
        Add a single trajectory (or replace an existing one)

        :param traj_id: A logical ID for this trajectory.
        :param traj_data: The trajectory data - a list/tuple of per-timepoint data.
                Per time point, specify a list/tuple of with 3 or 4 elements: time (> 0),
                x coordinate (int), y coordinate (int), and optional "visible" (bool)
        """

        _u.validate_func_arg_anylist(self, "set_trajectory", "traj_data", traj_data, min_length=1)
        if traj_id is None:
            raise TypeError("trajtracker error: {:}.set_trajectory(traj_id=None) is invalid".format(type(self).__name__))

        coords = []
        times = []
        visible = []
        prev_time = -1

        for i in range(len(traj_data)):

            time_point = traj_data[i]

            _u.validate_func_arg_anylist(self, "set_trajectory", "traj_data[%d]" % i, time_point, min_length=3, max_length=4)
            _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][0]" % i, time_point[0], numbers.Number)
            _u.validate_func_arg_not_negative(self, "set_trajectory", "traj_data[%d][0]" % i, time_point[0])
            _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][1]" % i, time_point[1], int)
            _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][2]" % i, time_point[2], int)

            time = time_point[0]
            if time <= prev_time:
                raise ValueError(("trajtracker error: {:}.set_trajectory() called with invalid value for trajectory '{:}' " +
                                 "- timepoint {:} appeared after {:}").format(type(self).__name__, traj_id, time, prev_time))

            prev_time = time

            times.append(time)
            coords.append((time_point[1], time_point[2]))

            if len(time_point) == 4:
                _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][3]" % i, time_point[3], bool)
                visible.append(time_point[3])
            else:
                visible.append(True)

        self._trajectories[traj_id] = {
            'times': np.array(times),
            'coords': coords,
            'visible': visible,
            'duration': times[-1]
        }

        self._validation_err = None
    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)
Example #17
0
    def update(self, clicked, xy):
        """
        Update the slider according to mouse movement
        
        **Note**: Unlike other stimulus objects in TrajTracker, here you should call the update() function also
        when the mouse is unclicked.
        
        :param clicked: Whether the mouse is presently clicked or not 
        :param xy: The coordinate to which the gauge is being dragged (x, y). This parameter is ignored in some 
                   situations, e.g., when clicked=False, when slider is locked, etc.
        """
        _u.validate_func_arg_type(self, "update", "clicked", clicked,
                                  (bool, int))
        clicked = bool(clicked)
        _u.validate_func_arg_type(self, "update", "xy", xy, ttrk.TYPE_COORD)

        if self.locked:
            return

        clicked = clicked and self._is_valid_mouse_pos(xy)

        if clicked:

            if not self._now_dragging:
                #-- Started clicking
                self._n_moves += 1
                self._gauge_stimulus.visible = self.visible
                self._log_write_if(ttrk.log_trace, "Start moving slider")
                self._now_dragging = True

            coord = xy[self._orientation_ind]
            self._current_value = self._coord_to_value(coord)
            self._move_gauge_to_coord(coord)

        elif self._now_dragging:  # and not clicked
            #-- Finger/mouse was just lifted

            self._now_dragging = False

            if self._max_moves is not None and self._n_moves >= self._max_moves:
                # Lifted too many times: lock the slider
                self.locked = True
    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)
Example #19
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))
Example #20
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
Example #21
0
    def __init__(self, event_id, extends=None):
        """
        Constructor - invoked when you create a new object by writing Event()

        :param event_id: A string that uniquely identifies the event
        :type event_id: str
        :param extends: If this event extends another one (see details in :ref:`event-hierarchy`)
        :type extends: Event
        """
        super(Event, self).__init__()

        _u.validate_func_arg_type(self, "__init__", "event_id", event_id, str)
        _u.validate_func_arg_type(self, "__init__", "extends", extends, Event, True)

        self._event_id = event_id
        self._offset = 0

        self._extended = False
        self._extends = extends
        if extends is not None:
            extends._extended = True
    def update_xyt(self, x_coord, y_coord, time):
        """
        Track a point.
        If tracking is currently inactive, this function will do nothing.
        """

        if not self._tracking_active:
            return

        _u.validate_func_arg_type(self, "update_xyt", "x_coord", x_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "y_coord", y_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "time", time,
                                  numbers.Number)
        _u.validate_func_arg_not_negative(self, "update_xyt", "time", time)

        self._trajectory['x'].append(x_coord)
        self._trajectory['y'].append(y_coord)
        self._trajectory['time'].append(time)

        if self._log_level:
            expyriment._active_exp._event_file_log(
                "Trajectory,Track_xyt,{0},{1},{2}".format(
                    x_coord, y_coord, time), 2)
Example #23
0
    def get_color_at(self, x_coord, y_coord, use_mapping=None):
        """
        Return the color at a given coordinate

        :param x_coord:
        :param y_coord:
        :param use_mapping:
        :return: The color in the given place, or None if the coordinate is out of the image range
        """

        _u.validate_func_arg_type(self, "get_color_at", "x_coord", x_coord, int)
        _u.validate_func_arg_type(self, "get_color_at", "y_coord", y_coord, int)
        _u.validate_func_arg_type(self, "get_color_at", "use_mapping", use_mapping, numbers.Number, none_allowed=True)

        if use_mapping is None:
            use_mapping = self._use_mapping

        if self._color_to_code is None and use_mapping:
            raise trajtracker.ValueError("a call to %s.get_color_at(use_mapping=True) is invalid because color_codes were not specified" % self.__class__)

        if x_coord < self._top_left_x or x_coord >= self._top_left_x+self._width or \
               y_coord < self._top_left_y or y_coord >= self._top_left_y + self._height:
            return None

        x_coord -= self._top_left_x
        y_coord -= self._top_left_y
        #y_coord = len(self._image) - 1 - y_coord   # reverse up/down

        v = self._image[-(y_coord+1)][x_coord]

        return self._color_to_code[v] if use_mapping else v
Example #24
0
    def register_callback(self, callback_func, recurring=False, func_id=None):
        """
        Register a "present callback" - a function that should be called when the StimulusContainer is present()ed
        
        :param callback_func: A function or another callable object, which will be called. 
                         This function takes these arguments -
                         
                         1. The StimulusContainer object
                         2. a tuple with the IDs of the stimuli that were actually presented (i.e., stimuli 
                            that had stim.visible == True)
                         3. The time when present() returned
                            
        :param recurring: True = invoke the function on each present() call. False = Invoke the function only 
                          on the next present(), and then forget this function.
                          
        :param func_id: A logical ID for a recurring function (it can be used to unregister the function later) 
        """

        _u.validate_func_arg_type(self, "register_callback", "callback_func",
                                  callback_func, ttrk.TYPE_CALLABLE)
        _u.validate_func_arg_type(self, "register_callback", "recurring",
                                  recurring, bool)

        if recurring:
            if func_id == "":
                func_id = None
            _u.validate_func_arg_type(self, "register_callback", "func_id",
                                      func_id, str)
            self._recurring_callbacks[func_id] = callback_func

        else:
            self._non_recurring_callbacks.append(callback_func)
Example #25
0
    def update_xyt(self, x_coord, y_coord, time):
        """
        Call this method whenever the finger/mouse moves

        :param time: use the same time scale provided to reset()
        """

        _u.validate_func_arg_type(self, "update_xyt", "x_coord", x_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "y_coord", y_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "time", time,
                                  numbers.Number)
        self._validate_time(time)

        if self._time0 is None:
            self._time0 = time

        #-- Set coordinate space
        x_coord /= self._units_per_mm
        y_coord /= self._units_per_mm

        #-- Find distance to recent coordinate
        if len(self._recent_points) > 0:
            last_loc = self._recent_points[-1]
            distance = np.sqrt((x_coord - last_loc[0])**2 +
                               (y_coord - last_loc[1])**2)
        else:
            distance = 0

        self._remove_recent_points_older_than(time -
                                              self._calculation_interval)

        #-- Remember current coords & time
        self._recent_points.append((x_coord, y_coord, time, distance))
Example #26
0
    def check_xy(self, x_coord, y_coord):
        """
        Check whether the new finger coordinates imply starting a trial

        :return: State.init - if the finger/mouse touched in the start area for the first time
                 State.start - if the finger/mouse left the start area in a valid way (into the exit area)
                 State.error - if the finger/mouse left the start area in an invalid way (not to the exit area)
                 None - if the finger/mouse didn't cause any change in the "start" state
        """

        _u.validate_func_arg_type(self, "check_xy", "x_coord", x_coord, numbers.Number)
        _u.validate_func_arg_type(self, "check_xy", "y_coord", y_coord, numbers.Number)

        if self._state == self.State.reset:
            #-- Trial not initialized yet: waiting for a touch inside start_area
            if self._start_area.overlapping_with_position((x_coord, y_coord)):
                self._state = self.State.init
                return self._state
            else:
                return None

        elif self._state == self.State.init:
            #-- Trial initialized but not started: waiting for a touch outside start_area

            if self._start_area.overlapping_with_position((x_coord, y_coord)):
                # still in the start area
                return None

            elif self._exit_area.overlapping_with_position((x_coord, y_coord)):
                # Left the start area into the exit area
                self._state = self.State.start

            else:
                # Left the start area into another (invalid) area
                self._state = self.State.error

            return self._state

        return None
Example #27
0
    def load_file(self, filename):
        """
        Load data from the CSV file

        :return: a tuple with two elements: (1) list with one dict per row, transformed to the required types; 
                (2) List of field names that were found in the file.
        """

        _u.validate_func_arg_type(self, "load_file", "filename", filename, str)

        rows, fieldnames = self._read_data_from_file(filename)

        self._validate_field_names(fieldnames, filename)

        #-- Transform data
        result = []
        for row in rows:
            if not self._case_sensitive_col_names:
                row = self._transform_lowercase(row)
            row = self._transform_types(row, filename)
            result.append(row)

        return result, fieldnames
Example #28
0
    def update(self, time):
        """
        Call this function on each frame where you want the animated object to move.

        :param time: The time (typically - time from start of trial)
        """
        _u.validate_func_arg_type(self, "update", "time", time, numbers.Number)

        if self._animated_object is None or self._trajectory_generator is None:
            return

        relative_time = time - self._time0

        traj_point = self._trajectory_generator.get_traj_point(relative_time)
        x = traj_point[
            'x'] if 'x' in traj_point else self._animated_object.position[0]
        y = traj_point[
            'y'] if 'y' in traj_point else self._animated_object.position[1]
        visible = traj_point['visible'] if 'visible' in traj_point else True
        self._animated_object.position = x, y
        if visible:
            self._animated_object.present(update=self._do_update_screen,
                                          clear=self._do_clear_screen)
Example #29
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]}
Example #30
0
    def _check_xyt_validate_and_log(self, x_coord, y_coord, time, time_used=True):

        _u.validate_func_arg_type(self, "check_xyt", "x_coord", x_coord, numbers.Number, type_name="numeric")
        _u.validate_func_arg_type(self, "check_xyt", "y_coord", y_coord, numbers.Number, type_name="numeric")

        if time_used:
            _u.validate_func_arg_type(self, "check_xyt", "time", time, numbers.Number, type_name="numeric")

        if self._should_log(self.log_trace):
            msg = "{0}.check_xyt,{1},{2}".format(type(self).__name__, x_coord, y_coord)
            if time_used:
                msg += ",{0}".format(time)
            self._log_write(msg)