Пример #1
0
    def _set_property(self, prop_name, value, prop_type, allow_single_value=True, allow_none=True):

        multiple_values = False

        #convert CSV input string to expyriment colour object
        if prop_type == 'RGB' and type(value[0])== str:
            temp = ()
            for i in value:
                temp = temp + (int(i),)
           
            newValue = Colour(temp)
            value = newValue

        if value is None and not allow_none:
                raise ttrk.TypeError("{:}.{:} cannot be set to None".format(_u.get_type_name(self), prop_name))

        if value is not None:

            multiple_values = self._is_multiple_values(value, prop_type)
            if multiple_values and (prop_type != 'RGB'):
                for v in value:
                    _u.validate_attr_type(self, prop_name, v, prop_type)
                value = list(value)
            elif allow_single_value:
                _u.validate_attr_type(self, prop_name, value, prop_type, none_allowed=True)
            else:
                raise ttrk.TypeError("{:}.{:} must be set to a list of values; a single {:} is invalid".format(
                    _u.get_type_name(self), prop_name, prop_type.__name__ if isinstance(prop_type, type) else prop_type))

        setattr(self, "_" + prop_name, value)
        setattr(self, "_" + prop_name + "_multiple", multiple_values)
Пример #2
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)
Пример #3
0
    def _validate_property(self, prop_name, n_stim=0):

        value = getattr(self, prop_name)
        if value is None:
            raise ttrk.ValueError('{:}.{:} was not set'.format(_u.get_type_name(self), prop_name))

        is_multiple_values = getattr(self, "_" + prop_name + "_multiple")
        if is_multiple_values and len(value) < n_stim:
            raise ttrk.ValueError('{:}.{:} has {:} values, but there are {:} values to present'.format(
                _u.get_type_name(self), prop_name, len(value), n_stim))
Пример #4
0
    def animated_object(self, obj):
        if "present" not in dir(obj):
            raise trajtracker.ValueError(
                "{:}.animated_object must be an object with a present() method"
                .format(_u.get_type_name(self)))
        if "position" not in dir(obj):
            raise trajtracker.ValueError(
                "{:}.animated_object must be an object with a 'position' property"
                .format(_u.get_type_name(self)))

        self._animated_object = obj
        self._log_property_changed("animated_object")
Пример #5
0
    def init_for_trial(self):
        """
        Initialize when a trial starts.

        Do not use this function if you are working with the events mechanism. 
        """

        self._log_func_enters("init_for_trial")
        if self._event_manager is not None:
            self._log_write_if(ttrk.log_warn,
                               "init_for_trial() was called although the {:} was registered to an event manager".format(
                                   _u.get_type_name(self)))

        self._configure_and_preload()

        n_stim = self.n_stim

        show_ops = list(zip(self._onset_time[:n_stim], [True] * n_stim, range(n_stim)))

        duration = self._duration if self._duration_multiple else ([self._duration] * n_stim)
        offset_times = [self._onset_time[i] + duration[i] for i in range(n_stim)]
        hide_ops = list(zip(offset_times, [False] * n_stim, range(n_stim)))
        if self._last_stimulus_remains:
            hide_ops = hide_ops[:-1]  # don't hide the last one

        self._show_hide_operations = sorted(show_ops + hide_ops, key=itemgetter(0))
        self._start_showing_time = None
Пример #6
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")
Пример #7
0
    def _set_dot_position_for_time(self, time):

        if time < 0 or time > 10000:
            raise ttrk.ValueError(
                '{:}._set_dot_position_for_time(): invalid "time" argument ({:})'
                .format(_u.get_type_name(self), time))

        remaining_time_ratio = 1 - (min(time, self._zoom_duration) /
                                    self._zoom_duration)

        dx = int(np.round(self._box_size[0] / 2 * remaining_time_ratio))
        dy = int(np.round(self._box_size[1] / 2 * remaining_time_ratio))

        self._dots[0].position = self.position[0] - dx, self.position[
            1] - dy  # top-left
        self._dots[1].position = self.position[0] + dx, self.position[
            1] - dy  # top-right
        self._dots[2].position = self.position[0] - dx, self.position[
            1] + dy  # bottom-left
        self._dots[3].position = self.position[0] + dx, self.position[
            1] + dy  # bottom-right

        if self._should_log(ttrk.log_trace):
            self._log_write(
                "Set dots location, remaining time = {:.0f}%".format(
                    remaining_time_ratio * 100), True)
Пример #8
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)
Пример #9
0
    def init_output_file(self,
                         filename=None,
                         xy_precision=5,
                         time_precision=3):
        """
        Initialize a new CSV output file for saving the results

        :param filename: Full path
        :param xy_precision: Precision of x,y coordinates (default: 5)
        :param time_precision: Precision of time (default: 3)
        """
        if filename is not None:
            self._filename = filename

        if self._filename is None:
            raise ttrk.ValueError(
                "filename was not provided to {:}.init_output_file()".format(
                    _u.get_type_name(self)))

        self._xy_precision = xy_precision
        self._time_precision = time_precision

        fh = self._open_file(self._filename, 'w')
        fh.write('trial,time,x,y\n')
        fh.close()

        self._out_file_initialized = True

        self._log_write_if(ttrk.log_debug,
                           "Initializing output file %s" % self._filename,
                           True)
Пример #10
0
    def orientation(self, value):
        if not isinstance(value, ttrk.stimuli.Orientation):
            raise ttrk.TypeError(
                "invalid value for {:}.orientation ({:}) - expecting Orientation.Horizontal or Orientation.Vertical"
                .format(_u.get_type_name(self), value))

        self._orientation = value
        self._log_property_changed("orientation")
Пример #11
0
def create_experiment_error(self, err_code, message, err_args=None):

    self._log_write_if(
        ttrk.log_info,
        "Experiment error detected by {:}: errcode={:}, message = {:}. Error parameters: {:}"
        .format(_u.get_type_name(self), err_code, message, err_args))

    return ExperimentError(err_code, message, self, err_args)
Пример #12
0
    def trajectory_generator(self, obj):

        if "get_traj_point" not in dir(obj):
            raise trajtracker.ValueError(
                "{:}.trajectory_generator must be an object with a get_traj_point() method"
                .format(_u.get_type_name(self)))

        self._trajectory_generator = obj
Пример #13
0
    def on_registered(self, event_manager):
        self._event_manager = event_manager

        #-- Whenever the trial starts: register specifc events
        event_manager.register_operation(event=self._trial_configured_event,
                                         operation=lambda t1, t2: self._init_trial_events(),
                                         recurring=True,
                                         description="Setup {:}".format(_u.get_type_name(self)))
Пример #14
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")
Пример #15
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(
                "{:}.update_xyt() was called with time={:} after it was previously called with time={:}"
                .format(_u.get_type_name(self), time, prev_time))
Пример #16
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")
Пример #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 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)
Пример #18
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")
Пример #19
0
    def colormap(self, value):

        if value is None:
            #-- No mapping: use default colors
            self._color_to_code = None

        elif isinstance(value, str) and value.lower() == "default":
            #-- Use arbitrary coding
            self._color_to_code = {}
            n = 0
            for color in sorted(list(self._available_colors)):
                self._color_to_code[color] = n
                n += 1

        elif isinstance(value, str) and value.lower() == "rgb":
            # Translate each triplet to an RGB code
            self._color_to_code = { color: color_rgb_to_num(color) for color in self._available_colors }

        elif isinstance(value, dict):
            #-- Use this mapping; but make sure that all colors from the image were defined
            missing_colors = set()
            for color in self._available_colors:
                if color not in value:
                    missing_colors.add(color)
            if len(missing_colors) > 0:
                raise trajtracker.ValueError("Invalid value for {:}.color_codes - some colors are missing: {:}".format(
                    _u.get_type_name(self), missing_colors))

            self._color_to_code = value.copy()

        elif isinstance(value, type(lambda:1)):
            #-- A function that maps each color to a code
            self._color_to_code = { color: value(color) for color in self._available_colors }

        else:
            raise trajtracker.ValueError(
                "{:}.color_codes can only be set to None, 'default', or a dict. Invalid value: {:}".format(
                    _u.get_type_name(self), value))

        self._log_property_changed("colormap", value)
Пример #20
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")
Пример #21
0
    def _is_multiple_values(self, value, prop_type):

        if type(prop_type) == type:
            return isinstance(value, (tuple, list, np.ndarray))
        elif prop_type == ttrk.TYPE_RGB:
            return isinstance(value, (tuple, list, np.ndarray)) and \
                    (len(value) == 0 or u.is_rgb(value[0]))
        elif prop_type == ttrk.TYPE_COORD:
            return isinstance(value, (tuple, list, np.ndarray)) and \
                    (len(value) == 0 or isinstance(value[0], (tuple, list, XYPoint, np.ndarray)))
        else:
            raise Exception("Trajtracker internal error: {:}._validate_attr_type() does not support type={:}".format(
                _u.get_type_name(self), prop_type))
Пример #22
0
    def present(self, clear=True, update=True):
        """
        Present all visible stimuli in the container
        Stimuli marked as invisible will not be shown

        :param clear: See in `Expyriment <http://docs.expyriment.org/expyriment.stimuli.Rectangle.html#expyriment.stimuli.Rectangle.present>`
        :param update: See in `Expyriment <http://docs.expyriment.org/expyriment.stimuli.Rectangle.html#expyriment.stimuli.Rectangle.present>`
        :return: The duration (in seconds) this function took to run
        """

        self._log_func_enters(
            "{:}({:}).present".format(_u.get_type_name(self), self._name),
            [clear, update])

        start_time = ttrk.utils.get_time()

        visible_stims = [
            stim for stim in self._stimuli.values() if stim['stimulus'].visible
        ]
        visible_stims.sort(key=itemgetter('order'))

        if self._should_log(ttrk.log_debug):
            self._log_write("going to present() these stimuli: {:}".format(
                ", ".join([str(s['id']) for s in visible_stims])),
                            prepend_self=True)

        if clear:
            _u.display_clear()
            self._log_write_if(ttrk.log_trace, "screen cleared")

        #-- Present stimuli marked as visible
        for i in range(len(visible_stims)):
            duration = visible_stims[i]['stimulus'].present(clear=False,
                                                            update=False)

            if self._should_log(ttrk.log_trace):
                self._log_write(
                    "{:}.present(): stimulus#{:}({:}).present() took {:.4f} sec"
                    .format(self._myname(), visible_stims[i]['order'],
                            visible_stims[i]['id'], c, u, duration))

        if update:
            _u.display_update()
            self._log_write_if(ttrk.log_trace, "screen updated (flip)")

        total_duration = ttrk.utils.get_time() - start_time

        self._invoke_callbacks(visible_stims)

        self._log_func_returns("present", total_duration)
        return total_duration
Пример #23
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)))
Пример #24
0
    def _init_trial_events(self):
        self._log_func_enters("_init_trial_events")

        if self._onset_event is None:
            raise ttrk.ValueError('{:}.onset_event was not set'.format(_u.get_type_name(self)))

        n_stim = self.n_stim
        self._configure_and_preload()

        duration = self._duration if self._duration_multiple else ([self._duration] * n_stim)

        op_ids = set()

        for i in range(n_stim):
            onset_event = self._onset_event + self._onset_time[i]
            op = StimulusEnableDisableOp(self, i, True)
            id1 = self._event_manager.register_operation(event=onset_event, recurring=False,
                                                         description=str(op), operation=op,
                                                         cancel_pending_operation_on=self.terminate_event)
            op_ids.add(id1)

            if i == n_stim - 1 and self._last_stimulus_remains:
                break

            offset_event = self._onset_event + self._onset_time[i] + duration[i]
            op = StimulusEnableDisableOp(self, i, False)
            id2 = self._event_manager.register_operation(event=offset_event, recurring=False,
                                                         description=str(op), operation=op,
                                                         cancel_pending_operation_on=self.terminate_event)
            op_ids.add(id2)

        self._registered_ops = op_ids

        if self._terminate_event is not None:
            self._event_manager.register_operation(event=self._terminate_event,
                                                   recurring=False,
                                                   description="Terminate " + _u.get_type_name(self),
                                                   operation=lambda t1, t2: self.terminate_display())
Пример #25
0
    def activate(self, key):
        """
        Set one of the stimuli as the active one.

        :param key: The key of the stimulus, as set in :func:`~trajtracker.stimuli.ChangingStimulus.add_stimulus`
        """
        if key is None or key in self._stimuli:
            if self._should_log(ttrk.log_trace):
                self._log_write("Activate,{:}".format(key), True)
            self._active_key = key
        else:
            raise ttrk.ValueError(
                "{:}.select(key={:}) - this stimulus was not defined".format(
                    _u.get_type_name(self), key))
    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))
Пример #27
0
    def exit_area(self, value):
        if value is None:
            self._exit_area = None
        elif isinstance(value, str):
            self._exit_area = self._create_default_exit_area(value)
            self._log_property_changed("exit_area", value=value)
        elif "overlapping_with_position" in dir(value):
            self._exit_area = value
            self._log_property_changed("exit_area", value="shape")
        else:
            raise ttrk.ValueError("invalid value for %s.exit_area" %
                                  _u.get_type_name(self))

        self._log_property_changed("exit_area")
Пример #28
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._center is None:
            raise trajtracker.InvalidStateError(
                "{:}.get_xy() was called without setting center".format(
                    _u.get_type_name(self)))
        if self._degrees_per_sec is None:
            raise trajtracker.InvalidStateError(
                "{:}.get_xy() was called without setting degrees_per_sec".
                format(_u.get_type_name(self)))
        if self._radius is None:
            raise trajtracker.InvalidStateError(
                "{:}.get_xy() was called without setting radius".format(
                    _u.get_type_name(self)))

        dps = self._degrees_per_sec * (1 if self._clockwise else -1)
        curr_degrees = (self._degrees_at_t0 + dps * 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]}
Пример #29
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")
Пример #30
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