aind-behavior-utils 0.3.2__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.github/workflows/tag_and_publish.yml +2 -2
  2. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/PKG-INFO +1 -1
  3. aind_behavior_utils-0.3.4/docs/CAMStim Behavior Pickle Structure.md +499 -0
  4. aind_behavior_utils-0.3.4/docs/CAMStim Passive Pickle Structure.md +549 -0
  5. aind_behavior_utils-0.3.4/docs/CAMStim Pickle Structure Comparison.md +272 -0
  6. aind_behavior_utils-0.3.4/docs/behavior_pkl_review.ipynb +476 -0
  7. aind_behavior_utils-0.3.4/docs/passive_pickle_review.ipynb +725 -0
  8. aind_behavior_utils-0.3.4/src/aind_behavior_utils/__init__.py +3 -0
  9. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils.egg-info/PKG-INFO +1 -1
  10. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils.egg-info/SOURCES.txt +5 -1
  11. aind_behavior_utils-0.3.2/.github/workflows/init.yml +0 -52
  12. aind_behavior_utils-0.3.2/src/aind_behavior_utils/__init__.py +0 -3
  13. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.flake8 +0 -0
  14. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  15. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  16. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.github/ISSUE_TEMPLATE/user-story.md +0 -0
  17. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.github/workflows/test_and_lint.yml +0 -0
  18. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/.gitignore +0 -0
  19. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/LICENSE +0 -0
  20. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/README.md +0 -0
  21. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/Makefile +0 -0
  22. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/make.bat +0 -0
  23. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/source/_static/dark-logo.svg +0 -0
  24. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/source/_static/favicon.ico +0 -0
  25. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/source/_static/light-logo.svg +0 -0
  26. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/source/conf.py +0 -0
  27. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/docs/source/index.rst +0 -0
  28. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/pyproject.toml +0 -0
  29. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/setup.cfg +0 -0
  30. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/setup.py +0 -0
  31. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/plotting/__init__.py +0 -0
  32. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/plotting/plots.py +0 -0
  33. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/stimulus/__init__.py +0 -0
  34. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/stimulus/camstim_dataset.py +0 -0
  35. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/stimulus/wheel_utils.py +0 -0
  36. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/sync/__init__.py +0 -0
  37. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/sync/legacy_line_labels.py +0 -0
  38. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils/sync/sync_dataset.py +0 -0
  39. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils.egg-info/dependency_links.txt +0 -0
  40. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils.egg-info/requires.txt +0 -0
  41. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/src/aind_behavior_utils.egg-info/top_level.txt +0 -0
  42. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/tests/__init__.py +0 -0
  43. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/tests/test_camstim_dataset.py +0 -0
  44. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/tests/test_legacy_line_labels.py +0 -0
  45. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/tests/test_plotting.py +0 -0
  46. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/tests/test_sync_dataset.py +0 -0
  47. {aind_behavior_utils-0.3.2 → aind_behavior_utils-0.3.4}/tests/test_sync_line_utils.py +0 -0
@@ -62,9 +62,9 @@ jobs:
62
62
  add: '["README.md"]'
63
63
  tag:
64
64
  needs: update_badges
65
- uses: AllenNeuralDynamics/aind-github-actions/.github/workflows/tag.yml@main
65
+ uses: AllenNeuralDynamics/.github/.github/workflows/release-bump-version.yml@main
66
66
  secrets:
67
- SERVICE_TOKEN: ${{ secrets.SERVICE_TOKEN }}
67
+ repo-token: ${{ secrets.SERVICE_TOKEN }}
68
68
  publish:
69
69
  needs: tag
70
70
  if: true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aind-behavior-utils
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Generated from aind-library-template
5
5
  Author: Allen Institute for Neural Dynamics
6
6
  License: MIT
@@ -0,0 +1,499 @@
1
+ # Camstim Behavior Pickle File Structure
2
+
3
+ This document describes the data structure of a Camstim behavior pickle file (`*_stim.pkl`) generated during a visual change detection task session.
4
+
5
+ ## Loading the File
6
+
7
+ ```python
8
+ import pickle
9
+
10
+ with open("1464696201_stim.pkl", "rb") as p:
11
+ data = pickle.load(p, encoding="latin1")
12
+ ```
13
+
14
+ ---
15
+
16
+ ## Top-Level Keys
17
+
18
+ | Key | Type | Description |
19
+ |-----|------|-------------|
20
+ | `comp_id` | str | Computer identifier |
21
+ | `items` | dict | Main data container — see [Items](#items) |
22
+ | `start_time` | datetime | Session start time |
23
+ | `stop_time` | datetime | Session stop time |
24
+ | `script` | str | Script text used to run the session |
25
+ | `rig_id` | str | Rig identifier |
26
+ | `threads` | list | Thread info (typically empty) |
27
+ | `session_uuid` | str | Unique session identifier |
28
+ | `platform_info` | dict | Software version info — see [Platform Info](#platform-info) |
29
+
30
+ ---
31
+
32
+ ## Platform Info
33
+
34
+ `data["platform_info"]`
35
+
36
+ | Key | Type | Description |
37
+ |-----|------|-------------|
38
+ | `camstim` | str | Camstim version |
39
+ | `opengl` | str | OpenGL version |
40
+ | `python` | str | Python version |
41
+ | `rig_id` | str | Rig identifier |
42
+ | `hardware` | tuple | Hardware info |
43
+ | `pyglet` | str | Pyglet version |
44
+ | `os` | str | Operating system |
45
+ | `psychopy` | str | PsychoPy version |
46
+ | `camstim_git_hash` | None | Git hash of camstim (if available) |
47
+
48
+ ---
49
+
50
+ ## Items
51
+
52
+ `data["items"]["behavior"]`
53
+
54
+ The top-level `items` dict contains a single key `behavior` with the following fields:
55
+
56
+ | Key | Type | Description |
57
+ |-----|------|-------------|
58
+ | `lick_sensors` | list | Lick sensor data — see [Lick Sensors](#lick-sensors) |
59
+ | `volume_dispensed` | list | String stored in a list (total volume dispensed) |
60
+ | `rewards_dispensed` | int | Total number of rewards dispensed |
61
+ | `rewards` | list | Reward event data — see [Rewards](#rewards) |
62
+ | `params` | dict | Task parameters — see [Params](#params) |
63
+ | `window` | dict | Display window configuration — see [Window](#window) |
64
+ | `trial_log` | list | Per-trial data — see [Trial Log](#trial-log) |
65
+ | `auto_update` | bool | Whether auto-update was enabled |
66
+ | `encoders` | list | Running wheel encoder data — see [Encoders](#encoders) |
67
+ | `sync_pulse` | None | Sync pulse data (typically None) |
68
+ | `stim_config` | dict | Stimulus display config — see [Stim Config](#stim-config) |
69
+ | `cl_params` | dict | Full closed-loop params as delivered — see [CL Params](#cl-params) |
70
+ | `stimuli` | dict | Stimulus presentation logs — see [Stimuli](#stimuli) |
71
+ | `omitted_flash_frame_log` | dict | Dict of `{image_name: [frame_indices]}` for omitted flashes |
72
+ | `update_count` | int | Number of update cycles |
73
+ | `behavior_text` | str | Behavior script text (often empty) |
74
+ | `intervalsms` | array | Frame interval durations in ms, shape `(n_frames,)` |
75
+ | `nidaq_tasks` | dict | NI-DAQ task configuration |
76
+
77
+ ---
78
+
79
+ ## Lick Sensors
80
+
81
+ `behavior["lick_sensors"][0]`
82
+
83
+ | Key | Type | Description |
84
+ |-----|------|-------------|
85
+ | `lick_events` | list | Initial contact lick events (tongue-first-touch) |
86
+ | `lick_data` | list | All detected lick samples |
87
+ | `line` | — | DAQ line identifier |
88
+
89
+ ---
90
+
91
+ ## Rewards
92
+
93
+ `behavior["rewards"][0]`
94
+
95
+ | Key | Type | Description |
96
+ |-----|------|-------------|
97
+ | `calibration` | — | Solenoid calibration data |
98
+ | `reward_times` | list | List of `(time_ms, frame_index)` tuples for each reward |
99
+ | `reward_count` | int | Total number of rewards delivered |
100
+ | `volume_dispensed` | float | Total volume dispensed (µL) |
101
+
102
+ ---
103
+
104
+ ## Params
105
+
106
+ `behavior["params"]`
107
+
108
+ Task parameters set at runtime.
109
+
110
+ | Key | Type | Description |
111
+ |-----|------|-------------|
112
+ | `auto_reward_delay` | int | Delay before auto-reward is delivered |
113
+ | `free_reward_trials` | int | Number of trials with free (unconditional) rewards |
114
+ | `end_after_response` | bool | Grace period after stimulus change — licks cannot trigger abort |
115
+ | `change_flashes_max` | int | Maximum flashes before a change can occur |
116
+ | `change_flashes_min` | int | Minimum flashes before a change can occur |
117
+ | `change_time_dist` | str | Distribution for change timing (e.g. `"geometric"`) |
118
+ | `change_time_scale` | float | Scale parameter for change time distribution |
119
+ | `stimulus_window` | float | Duration of the stimulus window (s) |
120
+ | `response_window` | list[float] | `[start, end]` of response window in seconds |
121
+ | `catch_frequency` | float | Frequency of catch trials (NaN if not set) |
122
+ | `min_no_lick_time` | float | Minimum no-lick time required before trial start |
123
+ | `timeout_duration` | float | Timeout duration after an aborted trial (s) |
124
+ | `volume_limit` | float | Maximum total reward volume per session (µL) |
125
+ | `max_task_duration_min` | float | Maximum session duration (minutes) |
126
+ | `reward_volume` | float | Volume per reward delivery (µL) |
127
+ | `end_after_response_sec` | float | Duration of post-response grace period (s) |
128
+ | `start_stop_padding` | float | Padding time at session start/stop (s) |
129
+ | `periodic_flash` | list[float] | `[on_duration, off_duration]` for periodic flashing (s) |
130
+ | `failure_repeats` | int | Number of times to repeat a failed trial |
131
+ | `warm_up_trials` | int | Number of auto-reward warm-up trials at session start |
132
+ | `pre_change_time` | float | Duration of the pre-change period (s) |
133
+ | `stage` | str | Stage name |
134
+ | `task_id` | str | Task identifier |
135
+ | `stimulus` | dict | Stimulus class config — see [Stimulus Config](#stimulus-config-in-params) |
136
+ | `epilogue` | dict | Epilogue movie config — see [Epilogue](#epilogue) |
137
+
138
+ ### Epilogue
139
+
140
+ `params["epilogue"]`
141
+
142
+ | Key | Path | Type | Description |
143
+ |-----|------|------|-------------|
144
+ | `name` | `epilogue["name"]` | str | Epilogue name |
145
+ | `frame_length` | `epilogue["params"]["frame_length"]` | float | Frame length (s) |
146
+ | `movie_path` | `epilogue["params"]["movie_path"]` | str | Path to epilogue movie file |
147
+ | `runs` | `epilogue["params"]["runs"]` | int | Number of times to play the movie |
148
+ | `size` | `epilogue["params"]["size"]` | list[int, int] | Movie frame size in pixels |
149
+
150
+ ### Stimulus Config in Params
151
+
152
+ `params["stimulus"]`
153
+
154
+ | Key | Path | Type | Description |
155
+ |-----|------|------|-------------|
156
+ | `image_set` | `stimulus["params"]["image_set"]` | str | Path to the image set |
157
+ | `sampling` | `stimulus["params"]["sampling"]` | str | Sampling strategy |
158
+ | `class_type` | `stimulus["class"]` | str | Python class name for the stimulus |
159
+
160
+ ---
161
+
162
+ ## Window
163
+
164
+ `behavior["window"]`
165
+
166
+ PsychoPy window configuration and state captured at session end.
167
+
168
+ | Key | Type | Description |
169
+ |-----|------|-------------|
170
+ | `scrDistCM` | int | Screen distance in cm |
171
+ | `scrWidthCM` | int | Screen width in cm |
172
+ | `scrWidthPIX` | int | Screen width in pixels |
173
+ | `mon_width_pix` | int32 | Monitor width in pixels |
174
+ | `mon_height_pix` | int32 | Monitor height in pixels |
175
+ | `mon_width_cm` | int | Monitor width in cm |
176
+ | `mon_height_cm` | float | Monitor height in cm |
177
+ | `dist_cm` | int | Viewing distance in cm |
178
+ | `aspect` | float | Aspect ratio |
179
+ | `size` | array[int, int] | Window size `[width, height]` in pixels |
180
+ | `pos` | array[int, int] | Window position on screen |
181
+ | `color` | array[float] | Background color as RGB floats `[r, g, b]` |
182
+ | `colorSpace` | str | Color space (e.g. `"rgb"`) |
183
+ | `rgb` | array[float] | RGB values |
184
+ | `flipCounter` | int | Total number of frame flips |
185
+ | `frames` | int | Total frames rendered |
186
+ | `frameIntervals` | list | Per-frame interval durations (s) |
187
+ | `monitorFramePeriod` | float | Nominal frame period (s) |
188
+ | `nDroppedFrames` | int | Number of dropped frames |
189
+ | `recordFrameIntervals` | bool | Whether frame intervals were recorded |
190
+ | `warpGridsize` | int | Warp grid size |
191
+ | `warp` | int | Warp mode |
192
+ | `warpfile` | None | Warp file path |
193
+ | `projectorType` | int | Projector type code |
194
+ | `useFBO` | bool | Whether FBO was used |
195
+ | `useNativeGamma` | bool | Whether native gamma was used |
196
+ | `gamma` | array[float] | Gamma values `[r, g, b]` |
197
+ | `origGammaRamp` | array | Original gamma ramp, shape `(3, 256)` |
198
+ | `blendMode` | str | Blend mode |
199
+ | `units` | str | Default units |
200
+ | `viewScale` | None | View scale |
201
+ | `viewPos` | None | View position |
202
+ | `viewOri` | float | View orientation |
203
+ | `flipHorizontal` | bool | Horizontal flip |
204
+ | `flipVertical` | bool | Vertical flip |
205
+ | `flipEvery3rdFrame` | bool | Whether every 3rd frame is flipped |
206
+ | `stereo` | bool | Stereo mode |
207
+ | `screen` | int | Screen index |
208
+ | `allowStencil` | bool | Whether stencil buffer is allowed |
209
+ | `allowGUI` | bool | Whether GUI is allowed |
210
+ | `winType` | str | Window type |
211
+ | `mouseVisible` | str | Mouse cursor visibility |
212
+ | `movieFrames` | list | Captured movie frames |
213
+ | `autoLog` | bool | Whether auto-logging is enabled |
214
+ | `config_path` | str | Path to monitor config file |
215
+ | `config` | dict | Monitor config — see [Window Config](#window-config) |
216
+ | `monitor` | dict | PsychoPy monitor calibration object |
217
+ | `xgrid` / `ygrid` | int | Grid dimensions |
218
+ | `nverts` | int | Number of warp vertices |
219
+
220
+ ### Window Config
221
+
222
+ `window["config"]`
223
+
224
+ | Key | Type | Description |
225
+ |-----|------|-------------|
226
+ | `showmouse` | bool | Whether mouse cursor is shown |
227
+ | `monitor_brightness` | int | Monitor brightness level |
228
+ | `fps` | float | Target frame rate |
229
+ | `monitor_contrast` | int | Monitor contrast level |
230
+
231
+ ---
232
+
233
+ ## Trial Log
234
+
235
+ `behavior["trial_log"]` — list of trial dicts, one per trial.
236
+
237
+ `trial_log[i]`
238
+
239
+ | Key | Type | Description |
240
+ |-----|------|-------------|
241
+ | `index` | int | Trial number (0-indexed) |
242
+ | `cumulative_rewards` | int | Total rewards delivered up to and including this trial |
243
+ | `cumulative_volume` | float | Total reward volume dispensed up to this trial (µL) |
244
+ | `licks` | list[tuple] | List of `(time_s, frame_index)` tuples for licks during this trial |
245
+ | `stimulus_changes` | list | Stimulus change events during this trial |
246
+ | `success` | bool | Whether the trial was a hit |
247
+ | `rewards` | list | Rewards delivered during this trial |
248
+ | `trial_params` | dict | Trial-specific parameters — see [Trial Params](#trial-params) |
249
+ | `encoder` | dict | Running wheel snapshot for this trial — see [Trial Encoder](#trial-encoder) |
250
+ | `events` | list[list] | Ordered behavioral events — see [Trial Events](#trial-events) |
251
+
252
+ ### Trial Events
253
+
254
+ `trial["events"]` — list of `[event_name, activity, time_s, frame_index]` entries.
255
+
256
+ | Event Name | Description |
257
+ |------------|-------------|
258
+ | `trial_start` | Trial begins |
259
+ | `initial_blank` | Initial blank period |
260
+ | `pre_change` | Pre-change period (gray screen with flashes) |
261
+ | `stimulus_window` | Active window where a change can be detected |
262
+ | `early_response` | Mouse licked before the response window |
263
+ | `abort` | Trial aborted (early lick or no-lick timeout) |
264
+ | `timeout` | Timeout period after an abort |
265
+ | `trial_end` | Trial ends |
266
+
267
+ ### Trial Params
268
+
269
+ `trial["trial_params"]`
270
+
271
+ | Key | Type | Description |
272
+ |-----|------|-------------|
273
+ | `catch` | bool | Whether this is a catch trial (no image change) |
274
+ | `auto_reward` | bool | Whether an automatic reward was given (warm-up trials) |
275
+ | `change_time` | int | Flash index at which the change occurred |
276
+
277
+ ### Trial Encoder
278
+
279
+ `trial["encoder"]`
280
+
281
+ | Key | Type | Description |
282
+ |-----|------|-------------|
283
+ | `count` | int | Encoder count |
284
+ | `radius_cm` | float | Wheel radius in cm |
285
+ | `degree` | — | Rotation in degrees |
286
+
287
+ ---
288
+
289
+ ## Encoders
290
+
291
+ `behavior["encoders"][0]` — full running wheel encoder log for the session.
292
+
293
+ | Key | Type | Description |
294
+ |-----|------|-------------|
295
+ | `counter_index` | int | Counter index |
296
+ | `distance` | float | Total distance traveled (cm) |
297
+ | `mdr0_register_setting` | str | MDR0 register setting |
298
+ | `base_time` | int | Base timestamp |
299
+ | `timestamp` | array[float32] | Timestamps for each encoder sample |
300
+ | `arduino_version` | str | Arduino firmware version |
301
+ | `treadmill` | bool | Whether a treadmill was used |
302
+ | `vin` | array | Input voltage signal |
303
+ | `vsig` | array | Signal voltage |
304
+ | `index_list` | array | List of encoder indices |
305
+ | `catching_encoder_failures` | int | Count of encoder failures caught |
306
+ | `degrees` | array | Rotation in degrees per sample |
307
+ | `dx` | array | Position delta per sample |
308
+ | `counts` | array | Raw encoder counts |
309
+ | `analog_encoder` | bool | Whether an analog encoder was used |
310
+ | `raw_data` | array | Raw encoder data |
311
+ | `encoder_radius` | float | Encoder wheel radius (cm) |
312
+
313
+ ---
314
+
315
+ ## Stim Config
316
+
317
+ `behavior["stim_config"]`
318
+
319
+ | Key | Type | Description |
320
+ |-----|------|-------------|
321
+ | `showmouse` | bool | Whether mouse cursor is shown |
322
+ | `monitor_brightness` | int | Monitor brightness level |
323
+ | `fps` | float | Target frame rate |
324
+ | `monitor_contrast` | int | Monitor contrast level |
325
+
326
+ ---
327
+
328
+ ## CL Params
329
+
330
+ `behavior["cl_params"]`
331
+
332
+ The full set of closed-loop task parameters as delivered to the task at runtime. These largely mirror [Params](#params) with some additions.
333
+
334
+ | Key | Type | Description |
335
+ |-----|------|-------------|
336
+ | `auto_reward_delay` | float | Delay before auto-reward |
337
+ | `free_reward_trials` | int | Free reward trial count |
338
+ | `end_after_response` | bool | End trial after response |
339
+ | `stimulus_window` | float | Stimulus window duration (s) |
340
+ | `change_flashes_max` | int | Max flashes before change |
341
+ | `change_flashes_min` | int | Min flashes before change |
342
+ | `mouse_id` | str | Mouse subject ID |
343
+ | `user_id` | str | Experimenter user ID |
344
+ | `change_time_dist` | str | Change time distribution |
345
+ | `response_window` | list[float] | `[start, end]` of response window (s) |
346
+ | `catch_frequency` | None | Catch trial frequency |
347
+ | `min_no_lick_time` | float | Min no-lick time before trial (s) |
348
+ | `volume_limit` | float | Max reward volume (µL) |
349
+ | `max_task_duration_min` | float | Max session duration (minutes) |
350
+ | `end_after_response_sec` | float | Post-response grace period (s) |
351
+ | `start_stop_padding` | float | Start/stop padding (s) |
352
+ | `periodic_flash` | list[float] | Flash on/off durations (s) |
353
+ | `timeout_duration` | float | Abort timeout duration (s) |
354
+ | `failure_repeats` | int | Failure repeat count |
355
+ | `warm_up_trials` | int | Number of warm-up (auto-reward) trials |
356
+ | `pre_change_time` | float | Pre-change period duration (s) |
357
+ | `auto_reward_vol` | float | Auto-reward volume (µL) |
358
+ | `stage` | str | Stage name |
359
+ | `task_id` | str | Task identifier |
360
+ | `epilogue` | dict | Epilogue config — same structure as [Epilogue](#epilogue) |
361
+ | `stimulus` | dict | Stimulus config — same structure as [Stimulus Config in Params](#stimulus-config-in-params) |
362
+
363
+ ---
364
+
365
+ ## Stimuli
366
+
367
+ `behavior["stimuli"]["images"]`
368
+
369
+ Logs of all stimulus presentations during the session.
370
+
371
+ | Key | Type | Description |
372
+ |-----|------|-------------|
373
+ | `image_set` | str | Path to the image set used |
374
+ | `image_path` | str | Path to image files |
375
+ | `obj_type` | str | Stimulus object type |
376
+ | `size` | tuple[int, int] | Stimulus size in pixels |
377
+ | `pos` | tuple | Stimulus position |
378
+ | `units` | str | Stimulus units |
379
+ | `sampling` | str | Image sampling strategy |
380
+ | `fps` | float | Display frame rate |
381
+ | `flash_interval_sec` | list[float] | `[on_duration, off_duration]` for each flash (s) |
382
+ | `flash_omit_probability` | float | Probability of omitting a flash |
383
+ | `flashes_omitted` | list[int] | Frame indices where flashes were omitted |
384
+ | `draw_log` | list[int] | Per-frame draw flag: `1` = image drawn, `0` = not drawn |
385
+ | `set_log` | list[tuple] | Log of every image set event — see [Set Log](#set-log) |
386
+ | `change_log` | list[tuple] | Log of every image change event — see [Change Log](#change-log) |
387
+ | `stim_groups` | list[tuple] | Stimulus group definitions |
388
+ | `image_walk` | list[array] | Ordered sequence of images shown |
389
+ | `sampling_matrix` | array | Sampling matrix, length 64 |
390
+ | `initial_group` | str | Name of the initial stimulus group |
391
+ | `correct_freq` | float | Correct response frequency |
392
+ | `stimulus` | dict | PsychoPy ImageStim object state — see [ImageStim](#imagestim) |
393
+ | `sequence` | None | Image sequence (unused) |
394
+ | `correct_table` | None | Correct response table (unused) |
395
+ | `incorrect_table` | None | Incorrect response table (unused) |
396
+ | `possibility_table` | None | Possibility table (unused) |
397
+ | `log` | list | General log (typically empty) |
398
+ | `on_draw` | dict | On-draw callbacks (typically empty) |
399
+ | `kwargs` | dict | Additional kwargs |
400
+ | `param_names` | None | Parameter names (unused) |
401
+
402
+ ### Set Log
403
+
404
+ `stimuli["images"]["set_log"]` — list of tuples recording every image presentation.
405
+
406
+ ```
407
+ ('Image', 'im000', 5.3695128, 0)
408
+ ^ ^ ^ ^
409
+ type image timestamp frame_index
410
+ name (s, display-relative)
411
+ ```
412
+
413
+ > **Timing note:** Set log timestamps are relative to when the display started, not the absolute session clock. The absolute session time of the first image is `trial_log[0]["events"][0][2]` (trial_start). The offset between display-relative and absolute time is approximately the gray-screen duration before the task begins (~300 s).
414
+
415
+ ### Change Log
416
+
417
+ `stimuli["images"]["change_log"]` — list of tuples recording every stimulus change.
418
+
419
+ ```
420
+ (('im000', 'im000'), ('im031', 'im031'), 312.1264287, 18390)
421
+ ^ ^ ^ ^
422
+ (from_group, (to_group, timestamp frame_index
423
+ from_image) to_image) (s, absolute)
424
+ ```
425
+
426
+ ### Draw Log
427
+
428
+ `stimuli["images"]["draw_log"]` — integer array with one entry per display frame.
429
+
430
+ - `1` = an image was drawn on this frame
431
+ - `0` = no image was drawn (gray screen, inter-flash interval, or omitted flash)
432
+
433
+ Used to reconstruct precise image onset/offset times from frame indices.
434
+
435
+ ---
436
+
437
+ ## ImageStim
438
+
439
+ `stimuli["images"]["stimulus"]`
440
+
441
+ PsychoPy `ImageStim` object state captured at session end.
442
+
443
+ | Key | Type | Description |
444
+ |-----|------|-------------|
445
+ | `_rotationMatrix` | array (2,2) | Rotation matrix |
446
+ | `rgbPedestal` | list[float] | RGB pedestal values |
447
+ | `color` | array (1,3) | Color |
448
+ | `colorSpace` | str | Color space |
449
+ | `pos` | array (1,2) | Position |
450
+ | `size` | array (1,2) | Size in display units |
451
+ | `_requestedSize` | array (1,2) | Originally requested size |
452
+ | `_origSize` | None | Original image size |
453
+ | `rgb` | array (1,3) | RGB values |
454
+ | `contrast` | float | Contrast |
455
+ | `opacity` | float | Opacity |
456
+ | `ori` | float | Orientation (degrees) |
457
+ | `useShaders` | bool | Whether shaders are used |
458
+ | `texRes` | int | Texture resolution |
459
+ | `interpolate` | float | Interpolation setting |
460
+ | `mask` | None | Mask |
461
+ | `maskParams` | None | Mask parameters |
462
+ | `isLumImage` | bool | Whether image is luminance-only |
463
+ | `flipHoriz` | bool | Horizontal flip |
464
+ | `flipVert` | bool | Vertical flip |
465
+ | `_verticesBase` | array (4,2) | Base vertex positions |
466
+ | `verticesPix` | array (4,2) | Vertex positions in pixels |
467
+ | `_needUpdate` | bool | Update flag |
468
+ | `_needTextureUpdate` | bool | Texture update flag |
469
+ | `_needVertexUpdate` | bool | Vertex update flag |
470
+ | `_tex1D` | bool | 1D texture flag |
471
+ | `image` | None | Loaded image (not serialized) |
472
+ | `_imName` | None | Image name (internal) |
473
+ | `_listID` | int | OpenGL display list ID |
474
+ | `_initParams` | list[str] | List of initialized parameter names |
475
+ | `units` | str | Stimulus units |
476
+ | `name` | str | Stimulus name |
477
+ | `depth` | int | Depth (draw order) |
478
+ | `status` | int | PsychoPy status flag |
479
+ | `autoLog` | bool | Auto-logging flag |
480
+
481
+ ---
482
+
483
+ ## Session Epochs
484
+
485
+ The session is divided into two epochs based on `trial_params["auto_reward"]`:
486
+
487
+ | Epoch | Description |
488
+ |-------|-------------|
489
+ | **Warm-up** | First `warm_up_trials` trials — rewards are given automatically regardless of response |
490
+ | **Change detection** | Remaining trials — mouse must respond within the response window to receive a reward |
491
+
492
+ The boundary can be found programmatically:
493
+
494
+ ```python
495
+ warmup_end_idx = next(
496
+ i for i, t in enumerate(trial_log)
497
+ if not t["trial_params"]["auto_reward"]
498
+ )
499
+ ```