Skip to content

Core Stimulus module

Module for handling stimulus presentation in behavioral experiments.

This module provides a base Stimulus class that handles the presentation of various types of stimuli during behavioral experiments. It includes functionality for stimulus preparation, presentation, logging, and cleanup.

StimCondition

Bases: Manual

Datajoint table for the stimulus presentation hash.

Source code in src/ethopy/core/stimulus.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
@stimulus.schema
class StimCondition(dj.Manual):
    """Datajoint table for the stimulus presentation hash."""

    definition = """
    # This class handles the stimulus presentation use function overrides for each
    # stimulus class
    stim_hash            : char(24)   # unique stimulus condition hash
    """

    class Trial(dj.Part):
        """Datajoint table for the Stimulus onset timestamps."""

        definition = """
        # Stimulus onset timestamps
        -> experiment.Trial
        period='Trial'       : varchar(16)
        ---
        -> StimCondition
        start_time           : int   # start time from session start (ms)
        end_time=NULL        : int   # end time from session start (ms)
        """

Trial

Bases: Part

Datajoint table for the Stimulus onset timestamps.

Source code in src/ethopy/core/stimulus.py
231
232
233
234
235
236
237
238
239
240
241
242
class Trial(dj.Part):
    """Datajoint table for the Stimulus onset timestamps."""

    definition = """
    # Stimulus onset timestamps
    -> experiment.Trial
    period='Trial'       : varchar(16)
    ---
    -> StimCondition
    start_time           : int   # start time from session start (ms)
    end_time=NULL        : int   # end time from session start (ms)
    """

Stimulus

Base class for handling stimulus presentation in behavioral experiments.

This class provides the core functionality for managing stimuli in behavioral experiments, including initialization, presentation, logging, and cleanup. It can be subclassed to implement specific types of stimuli.

Attributes:

Name Type Description
cond_tables List[str]

List of condition table names.

required_fields List[str]

List of required fields for stimulus conditions.

default_key Dict[str, Any]

Default key-value pairs for stimulus conditions.

curr_cond Dict[str, Any]

Current stimulus condition parameters.

conditions List[Dict[str, Any]]

List of all stimulus conditions.

timer Timer

Timer object for tracking stimulus timing.

period str

Current experimental period ('Trial' by default).

in_operation bool

Flag indicating if stimulus is currently active.

flip_count int

Counter for screen flips.

photodiode bool

Flag for photodiode triggering.

rec_fliptimes bool

Flag for recording flip times.

fill_colors DictStruct

Structure containing color values for different states

Source code in src/ethopy/core/stimulus.py
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
class Stimulus:
    """Base class for handling stimulus presentation in behavioral experiments.

    This class provides the core functionality for managing stimuli in behavioral
    experiments, including initialization, presentation, logging, and cleanup. It can be
    subclassed to implement specific types of stimuli.

    Attributes:
        cond_tables (List[str]): List of condition table names.
        required_fields (List[str]): List of required fields for stimulus conditions.
        default_key (Dict[str, Any]): Default key-value pairs for stimulus conditions.
        curr_cond (Dict[str, Any]): Current stimulus condition parameters.
        conditions (List[Dict[str, Any]]): List of all stimulus conditions.
        timer (Timer): Timer object for tracking stimulus timing.
        period (str): Current experimental period ('Trial' by default).
        in_operation (bool): Flag indicating if stimulus is currently active.
        flip_count (int): Counter for screen flips.
        photodiode (bool): Flag for photodiode triggering.
        rec_fliptimes (bool): Flag for recording flip times.
        fill_colors (DictStruct): Structure containing color values for different states

    """

    def __init__(self) -> None:
        """Initialize stimulus attributes."""
        self.cond_tables: List[str] = []
        self.required_fields: List[str] = []
        self.default_key: Dict[str, Any] = {}
        self.curr_cond: Dict[str, Any] = {}
        self.timer: Timer = Timer()
        self.period: str = "Trial"
        self.in_operation: bool = False
        self.flip_count: int = 0
        self.photodiode: bool = False
        self.rec_fliptimes: bool = False
        self.fill_colors: FillColors = FillColors()
        self.logger = None
        self.exp = None
        self.monitor = None
        self.Presenter = None
        self.start_time: Optional[float] = None

    def init(self, exp) -> None:
        """Initialize stimulus with experiment object and setup screen properties.

        Args:
            exp (Experiment): Experiment object containing logger and interface
                components.

        """
        self.logger = exp.logger
        self.exp = exp
        screen_properties = self.logger.get(
            schema="interface",
            table="SetupConfiguration.Screen",
            key=f"setup_conf_idx={self.exp.setup_conf_idx}",
            as_dict=True,
        )
        self.monitor = DictStruct(screen_properties[0])
        if self.logger.is_pi:
            cmd = (
                "echo %d > /sys/class/backlight/rpi_backlight/brightness"
                % self.monitor.intensity
            )
            os.system(cmd)
            exp.interface.setup_touch_exit()

    def setup(self) -> None:
        """Set up stimulus presentation environment.

        Initializes the Presenter object with monitor settings and background color.
        Should be called before starting the experiment.
        """
        self.Presenter = Presenter(
            self.logger,
            self.monitor,
            background_color=self.fill_colors.background,
            photodiode=self.photodiode,
            rec_fliptimes=self.rec_fliptimes,
        )

    def prepare(self, curr_cond=False, stim_period="") -> None:
        """Prepare stuff for presentation before trial starts."""
        self.curr_cond = curr_cond if stim_period == "" else curr_cond[stim_period]
        self.period = stim_period

    def start(self) -> None:
        """Start stimulus."""
        self.in_operation = True
        self.log_start()
        self.timer.start()

    def present(self) -> None:
        """Present stimulus.

        This is a placeholder method that should be overridden by subclasses
        to implement specific stimulus presentation logic.
        """

    def fill(self, color=False) -> None:
        """Stimulus hidding method."""
        if not color:
            color = self.fill_colors.background
        if self.fill_colors.background:
            self.Presenter.fill(color)

    def stop(self) -> None:
        """Stop stimulus."""
        self.fill()
        self.log_stop()
        self.in_operation = False

    def exit(self) -> None:
        """Exit stimulus stuff."""
        self.Presenter.quit()

    def ready_stim(self) -> None:
        """Stim Cue for ready."""
        if self.fill_colors.ready:
            self.fill(self.fill_colors.ready)

    def reward_stim(self) -> None:
        """Stim Cue for reward."""
        if self.fill_colors.reward:
            self.fill(self.fill_colors.reward)

    def punish_stim(self) -> None:
        """Stim Cue for punishment."""
        if self.fill_colors.punish:
            self.fill(self.fill_colors.punish)

    def start_stim(self) -> None:
        """Stim Cue for start."""
        if self.fill_colors.start:
            self.fill(self.fill_colors.start)

    def log_start(self) -> None:
        """Start timer for the log of stimlus condition."""
        self.start_time = self.logger.logger_timer.elapsed_time()
        self.exp.interface.sync_out(True)

    def log_stop(self) -> None:
        """Log stimulus condition start & stop time."""
        stop_time = self.logger.logger_timer.elapsed_time()
        self.exp.interface.sync_out(False)
        self.logger.log(
            "StimCondition.Trial",
            dict(
                period=self.period,
                stim_hash=self.curr_cond["stim_hash"],
                start_time=self.start_time,
                end_time=stop_time,
            ),
            schema="stimulus",
        )

    def make_conditions(
        self, conditions: List[Dict[str, Any]] = None
    ) -> List[Dict[str, Any]]:
        """Generate and store stimulus conditions.

        Args:
            conditions: List of condition dictionaries to process.

        Returns:
            List of processed condition dictionaries with hashes.

        Raises:
            AssertionError: If required fields are missing from any condition.

        """
        # check for any missing field from the required fields and add the default keys
        for cond in conditions:
            missing_fields = [
                field for field in self.required_fields if field not in cond
            ]
            assert not missing_fields, (
                f"Missing Stimulus required fields: {missing_fields}"
            )
            cond.update({**self.default_key, **cond})
        # log stim conditions
        conditions = self.exp.log_conditions(
            conditions,
            schema="stimulus",
            hash_field="stim_hash",
            condition_tables=["StimCondition"] + self.cond_tables,
        )
        return conditions

    def name(self) -> str:
        """Get the name of the stimulus class.

        Returns:
            (str):Name of the current stimulus class.

        """
        return type(self).__name__

__init__()

Initialize stimulus attributes.

Source code in src/ethopy/core/stimulus.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def __init__(self) -> None:
    """Initialize stimulus attributes."""
    self.cond_tables: List[str] = []
    self.required_fields: List[str] = []
    self.default_key: Dict[str, Any] = {}
    self.curr_cond: Dict[str, Any] = {}
    self.timer: Timer = Timer()
    self.period: str = "Trial"
    self.in_operation: bool = False
    self.flip_count: int = 0
    self.photodiode: bool = False
    self.rec_fliptimes: bool = False
    self.fill_colors: FillColors = FillColors()
    self.logger = None
    self.exp = None
    self.monitor = None
    self.Presenter = None
    self.start_time: Optional[float] = None

exit()

Exit stimulus stuff.

Source code in src/ethopy/core/stimulus.py
134
135
136
def exit(self) -> None:
    """Exit stimulus stuff."""
    self.Presenter.quit()

fill(color=False)

Stimulus hidding method.

Source code in src/ethopy/core/stimulus.py
121
122
123
124
125
126
def fill(self, color=False) -> None:
    """Stimulus hidding method."""
    if not color:
        color = self.fill_colors.background
    if self.fill_colors.background:
        self.Presenter.fill(color)

init(exp)

Initialize stimulus with experiment object and setup screen properties.

Parameters:

Name Type Description Default
exp Experiment

Experiment object containing logger and interface components.

required
Source code in src/ethopy/core/stimulus.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def init(self, exp) -> None:
    """Initialize stimulus with experiment object and setup screen properties.

    Args:
        exp (Experiment): Experiment object containing logger and interface
            components.

    """
    self.logger = exp.logger
    self.exp = exp
    screen_properties = self.logger.get(
        schema="interface",
        table="SetupConfiguration.Screen",
        key=f"setup_conf_idx={self.exp.setup_conf_idx}",
        as_dict=True,
    )
    self.monitor = DictStruct(screen_properties[0])
    if self.logger.is_pi:
        cmd = (
            "echo %d > /sys/class/backlight/rpi_backlight/brightness"
            % self.monitor.intensity
        )
        os.system(cmd)
        exp.interface.setup_touch_exit()

log_start()

Start timer for the log of stimlus condition.

Source code in src/ethopy/core/stimulus.py
158
159
160
161
def log_start(self) -> None:
    """Start timer for the log of stimlus condition."""
    self.start_time = self.logger.logger_timer.elapsed_time()
    self.exp.interface.sync_out(True)

log_stop()

Log stimulus condition start & stop time.

Source code in src/ethopy/core/stimulus.py
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def log_stop(self) -> None:
    """Log stimulus condition start & stop time."""
    stop_time = self.logger.logger_timer.elapsed_time()
    self.exp.interface.sync_out(False)
    self.logger.log(
        "StimCondition.Trial",
        dict(
            period=self.period,
            stim_hash=self.curr_cond["stim_hash"],
            start_time=self.start_time,
            end_time=stop_time,
        ),
        schema="stimulus",
    )

make_conditions(conditions=None)

Generate and store stimulus conditions.

Parameters:

Name Type Description Default
conditions List[Dict[str, Any]]

List of condition dictionaries to process.

None

Returns:

Type Description
List[Dict[str, Any]]

List of processed condition dictionaries with hashes.

Raises:

Type Description
AssertionError

If required fields are missing from any condition.

Source code in src/ethopy/core/stimulus.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def make_conditions(
    self, conditions: List[Dict[str, Any]] = None
) -> List[Dict[str, Any]]:
    """Generate and store stimulus conditions.

    Args:
        conditions: List of condition dictionaries to process.

    Returns:
        List of processed condition dictionaries with hashes.

    Raises:
        AssertionError: If required fields are missing from any condition.

    """
    # check for any missing field from the required fields and add the default keys
    for cond in conditions:
        missing_fields = [
            field for field in self.required_fields if field not in cond
        ]
        assert not missing_fields, (
            f"Missing Stimulus required fields: {missing_fields}"
        )
        cond.update({**self.default_key, **cond})
    # log stim conditions
    conditions = self.exp.log_conditions(
        conditions,
        schema="stimulus",
        hash_field="stim_hash",
        condition_tables=["StimCondition"] + self.cond_tables,
    )
    return conditions

name()

Get the name of the stimulus class.

Returns:

Type Description
str

Name of the current stimulus class.

Source code in src/ethopy/core/stimulus.py
211
212
213
214
215
216
217
218
def name(self) -> str:
    """Get the name of the stimulus class.

    Returns:
        (str):Name of the current stimulus class.

    """
    return type(self).__name__

prepare(curr_cond=False, stim_period='')

Prepare stuff for presentation before trial starts.

Source code in src/ethopy/core/stimulus.py
103
104
105
106
def prepare(self, curr_cond=False, stim_period="") -> None:
    """Prepare stuff for presentation before trial starts."""
    self.curr_cond = curr_cond if stim_period == "" else curr_cond[stim_period]
    self.period = stim_period

present()

Present stimulus.

This is a placeholder method that should be overridden by subclasses to implement specific stimulus presentation logic.

Source code in src/ethopy/core/stimulus.py
114
115
116
117
118
119
def present(self) -> None:
    """Present stimulus.

    This is a placeholder method that should be overridden by subclasses
    to implement specific stimulus presentation logic.
    """

punish_stim()

Stim Cue for punishment.

Source code in src/ethopy/core/stimulus.py
148
149
150
151
def punish_stim(self) -> None:
    """Stim Cue for punishment."""
    if self.fill_colors.punish:
        self.fill(self.fill_colors.punish)

ready_stim()

Stim Cue for ready.

Source code in src/ethopy/core/stimulus.py
138
139
140
141
def ready_stim(self) -> None:
    """Stim Cue for ready."""
    if self.fill_colors.ready:
        self.fill(self.fill_colors.ready)

reward_stim()

Stim Cue for reward.

Source code in src/ethopy/core/stimulus.py
143
144
145
146
def reward_stim(self) -> None:
    """Stim Cue for reward."""
    if self.fill_colors.reward:
        self.fill(self.fill_colors.reward)

setup()

Set up stimulus presentation environment.

Initializes the Presenter object with monitor settings and background color. Should be called before starting the experiment.

Source code in src/ethopy/core/stimulus.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def setup(self) -> None:
    """Set up stimulus presentation environment.

    Initializes the Presenter object with monitor settings and background color.
    Should be called before starting the experiment.
    """
    self.Presenter = Presenter(
        self.logger,
        self.monitor,
        background_color=self.fill_colors.background,
        photodiode=self.photodiode,
        rec_fliptimes=self.rec_fliptimes,
    )

start()

Start stimulus.

Source code in src/ethopy/core/stimulus.py
108
109
110
111
112
def start(self) -> None:
    """Start stimulus."""
    self.in_operation = True
    self.log_start()
    self.timer.start()

start_stim()

Stim Cue for start.

Source code in src/ethopy/core/stimulus.py
153
154
155
156
def start_stim(self) -> None:
    """Stim Cue for start."""
    if self.fill_colors.start:
        self.fill(self.fill_colors.start)

stop()

Stop stimulus.

Source code in src/ethopy/core/stimulus.py
128
129
130
131
132
def stop(self) -> None:
    """Stop stimulus."""
    self.fill()
    self.log_stop()
    self.in_operation = False