Skip to content

Commit d15b12c

Browse files
committed
Merge branch 'release/2.39.0'
2 parents 3e80794 + e89f12d commit d15b12c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2367
-6058
lines changed

brainbox/behavior/wheel.py

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
"""
22
Set of functions to handle wheel data.
33
"""
4-
import logging
5-
import warnings
6-
import traceback
7-
84
import numpy as np
95
from numpy import pi
106
from iblutil.numerical import between_sorted
@@ -68,42 +64,6 @@ def interpolate_position(re_ts, re_pos, freq=1000, kind='linear', fill_gaps=None
6864
return yinterp, t
6965

7066

71-
def velocity(re_ts, re_pos):
72-
"""
73-
(DEPRECATED) Compute wheel velocity from non-uniformly sampled wheel data. Returns the velocity
74-
at the same samples locations as the position through interpolation.
75-
76-
Parameters
77-
----------
78-
re_ts : array_like
79-
Array of timestamps
80-
re_pos: array_like
81-
Array of unwrapped wheel positions
82-
83-
Returns
84-
-------
85-
np.ndarray
86-
numpy array of velocities
87-
"""
88-
for line in traceback.format_stack():
89-
print(line.strip())
90-
91-
msg = 'brainbox.behavior.wheel.velocity will soon be removed. Use velocity_filtered instead.'
92-
warnings.warn(msg, FutureWarning)
93-
logging.getLogger(__name__).warning(msg)
94-
95-
dp = np.diff(re_pos)
96-
dt = np.diff(re_ts)
97-
# Compute raw velocity
98-
vel = dp / dt
99-
# Compute velocity time scale
100-
tv = re_ts[:-1] + dt / 2
101-
# interpolate over original time scale
102-
if tv.size > 1:
103-
ifcn = interpolate.interp1d(tv, vel, fill_value="extrapolate")
104-
return ifcn(re_ts)
105-
106-
10767
def velocity_filtered(pos, fs, corner_frequency=20, order=8):
10868
"""
10969
Compute wheel velocity from uniformly sampled wheel data.
@@ -130,83 +90,6 @@ def velocity_filtered(pos, fs, corner_frequency=20, order=8):
13090
return vel, acc
13191

13292

133-
def velocity_smoothed(pos, freq, smooth_size=0.03):
134-
"""
135-
(DEPRECATED) Compute wheel velocity from uniformly sampled wheel data.
136-
137-
Parameters
138-
----------
139-
pos : array_like
140-
Array of wheel positions
141-
smooth_size : float
142-
Size of Gaussian smoothing window in seconds
143-
freq : float
144-
Sampling frequency of the data
145-
146-
Returns
147-
-------
148-
vel : np.ndarray
149-
Array of velocity values
150-
acc : np.ndarray
151-
Array of acceleration values
152-
"""
153-
for line in traceback.format_stack():
154-
print(line.strip())
155-
156-
msg = 'brainbox.behavior.wheel.velocity_smoothed will be removed. Use velocity_filtered instead.'
157-
warnings.warn(msg, FutureWarning)
158-
logging.getLogger(__name__).warning(msg)
159-
160-
# Define our smoothing window with an area of 1 so the units won't be changed
161-
std_samps = np.round(smooth_size * freq) # Standard deviation relative to sampling frequency
162-
N = std_samps * 6 # Number of points in the Gaussian covering +/-3 standard deviations
163-
gauss_std = (N - 1) / 6
164-
win = scipy.signal.windows.gaussian(N, gauss_std)
165-
win = win / win.sum() # Normalize amplitude
166-
167-
# Convolve and multiply by sampling frequency to restore original units
168-
vel = np.insert(scipy.signal.convolve(np.diff(pos), win, mode='same'), 0, 0) * freq
169-
acc = np.insert(scipy.signal.convolve(np.diff(vel), win, mode='same'), 0, 0) * freq
170-
171-
return vel, acc
172-
173-
174-
def last_movement_onset(t, vel, event_time):
175-
"""
176-
(DEPRECATED) Find the time at which movement started, given an event timestamp that occurred during the
177-
movement.
178-
179-
Movement start is defined as the first sample after the velocity has been zero for at least 50ms.
180-
Wheel inputs should be evenly sampled.
181-
182-
:param t: numpy array of wheel timestamps in seconds
183-
:param vel: numpy array of wheel velocities
184-
:param event_time: timestamp anywhere during movement of interest, e.g. peak velocity
185-
:return: timestamp of movement onset
186-
"""
187-
for line in traceback.format_stack():
188-
print(line.strip())
189-
190-
msg = 'brainbox.behavior.wheel.last_movement_onset has been deprecated. Use get_movement_onset instead.'
191-
warnings.warn(msg, FutureWarning)
192-
logging.getLogger(__name__).warning(msg)
193-
194-
# Look back from timestamp
195-
threshold = 50e-3
196-
mask = t < event_time
197-
times = t[mask]
198-
vel = vel[mask]
199-
t = None # Initialize
200-
for i, t in enumerate(times[::-1]):
201-
i = times.size - i
202-
idx = np.min(np.where((t - times) < threshold))
203-
if np.max(np.abs(vel[idx:i])) < 0.5:
204-
break
205-
206-
# Return timestamp
207-
return t
208-
209-
21093
def get_movement_onset(intervals, event_times):
21194
"""
21295
Find the time at which movement started, given an event timestamp that occurred during the

brainbox/io/one.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import spikeglx
2121

2222
import ibldsp.voltage
23+
from ibldsp.waveform_extraction import WaveformsLoader
2324
from iblutil.util import Bunch
2425
from iblatlas.atlas import AllenAtlas, BrainRegions
2526
from iblatlas import atlas
@@ -975,6 +976,21 @@ def raw_electrophysiology(self, stream=True, band='ap', **kwargs):
975976
if cbin_file is not None:
976977
return spikeglx.Reader(cbin_file)
977978

979+
def download_raw_waveforms(self, **kwargs):
980+
"""
981+
Downloads raw waveforms extracted from sorting to local disk.
982+
"""
983+
_logger.debug(f"loading waveforms from {self.collection}")
984+
return self.one.load_object(
985+
self.eid, "waveforms",
986+
attribute=["traces", "templates", "table", "channels"],
987+
collection=self._get_spike_sorting_collection("pykilosort"), download_only=True, **kwargs
988+
)
989+
990+
def raw_waveforms(self, **kwargs):
991+
wf_paths = self.download_raw_waveforms(**kwargs)
992+
return WaveformsLoader(wf_paths[0].parent, wfs_dtype=np.float16)
993+
978994
def load_channels(self, **kwargs):
979995
"""
980996
Loads channels
@@ -1318,6 +1334,7 @@ class SessionLoader:
13181334
one: One = None
13191335
session_path: Path = ''
13201336
eid: str = ''
1337+
revision: str = ''
13211338
data_info: pd.DataFrame = field(default_factory=pd.DataFrame, repr=False)
13221339
trials: pd.DataFrame = field(default_factory=pd.DataFrame, repr=False)
13231340
wheel: pd.DataFrame = field(default_factory=pd.DataFrame, repr=False)
@@ -1445,7 +1462,7 @@ def load_trials(self, collection=None):
14451462
# itiDuration frequently has a mismatched dimension, and we don't need it, exclude using regex
14461463
self.one.wildcards = False
14471464
self.trials = self.one.load_object(
1448-
self.eid, 'trials', collection=collection, attribute=r'(?!itiDuration).*').to_df()
1465+
self.eid, 'trials', collection=collection, attribute=r'(?!itiDuration).*', revision=self.revision or None).to_df()
14491466
self.one.wildcards = True
14501467
self.data_info.loc[self.data_info['name'] == 'trials', 'is_loaded'] = True
14511468

@@ -1468,7 +1485,7 @@ def load_wheel(self, fs=1000, corner_frequency=20, order=8, collection=None):
14681485
"""
14691486
if not collection:
14701487
collection = self._find_behaviour_collection('wheel')
1471-
wheel_raw = self.one.load_object(self.eid, 'wheel', collection=collection)
1488+
wheel_raw = self.one.load_object(self.eid, 'wheel', collection=collection, revision=self.revision or None)
14721489
if wheel_raw['position'].shape[0] != wheel_raw['timestamps'].shape[0]:
14731490
raise ValueError("Length mismatch between 'wheel.position' and 'wheel.timestamps")
14741491
# resample the wheel position and compute velocity, acceleration
@@ -1498,7 +1515,7 @@ def load_pose(self, likelihood_thr=0.9, views=['left', 'right', 'body']):
14981515
# empty the dictionary so that if one loads only one view, after having loaded several, the others don't linger
14991516
self.pose = {}
15001517
for view in views:
1501-
pose_raw = self.one.load_object(self.eid, f'{view}Camera', attribute=['dlc', 'times'])
1518+
pose_raw = self.one.load_object(self.eid, f'{view}Camera', attribute=['dlc', 'times'], revision=self.revision or None)
15021519
# Double check if video timestamps are correct length or can be fixed
15031520
times_fixed, dlc = self._check_video_timestamps(view, pose_raw['times'], pose_raw['dlc'])
15041521
self.pose[f'{view}Camera'] = likelihood_threshold(dlc, likelihood_thr)
@@ -1525,7 +1542,8 @@ def load_motion_energy(self, views=['left', 'right', 'body']):
15251542
# empty the dictionary so that if one loads only one view, after having loaded several, the others don't linger
15261543
self.motion_energy = {}
15271544
for view in views:
1528-
me_raw = self.one.load_object(self.eid, f'{view}Camera', attribute=['ROIMotionEnergy', 'times'])
1545+
me_raw = self.one.load_object(
1546+
self.eid, f'{view}Camera', attribute=['ROIMotionEnergy', 'times'], revision=self.revision or None)
15291547
# Double check if video timestamps are correct length or can be fixed
15301548
times_fixed, motion_energy = self._check_video_timestamps(
15311549
view, me_raw['times'], me_raw['ROIMotionEnergy'])
@@ -1550,7 +1568,7 @@ def load_pupil(self, snr_thresh=5.):
15501568
will be considered unusable and will be discarded.
15511569
"""
15521570
# Try to load from features
1553-
feat_raw = self.one.load_object(self.eid, 'leftCamera', attribute=['times', 'features'])
1571+
feat_raw = self.one.load_object(self.eid, 'leftCamera', attribute=['times', 'features'], revision=self.revision or None)
15541572
if 'features' in feat_raw.keys():
15551573
times_fixed, feats = self._check_video_timestamps('left', feat_raw['times'], feat_raw['features'])
15561574
self.pupil = feats.copy()

brainbox/tests/test_behavior.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,6 @@ def test_get_movement_onset(self):
124124
with self.assertRaises(ValueError):
125125
wheel.get_movement_onset(intervals, np.random.permutation(self.trials['feedback_times']))
126126

127-
def test_velocity_deprecation(self):
128-
"""Ensure brainbox.behavior.wheel.velocity is removed."""
129-
from datetime import datetime
130-
self.assertTrue(datetime.today() < datetime(2024, 8, 1),
131-
'remove brainbox.behavior.wheel.velocity, velocity_smoothed and last_movement_onset')
132-
133127

134128
class TestTraining(unittest.TestCase):
135129
def setUp(self):

examples/data_release/data_release_behavior.ipynb

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@
1111
"source": [
1212
"# Data Release - Behavior\n",
1313
"\n",
14-
"The International Brain Laboratory is a team of systems and computational neuroscientists, working collaboratively to understand the computations that support decision-making in the brain. To achieve this aim, we have developed a standardized decision-making task in mice in order that probes decision-making. The task requires mice to perform decisions by combining incoming visual evidence with internal beliefs about the dynamic structure of the environment. Please read our accompanying [paper (The International Brain Laboratory et al. 2020)](https://elifesciences.org/articles/63711) for details on the decision-making task and the experiment.\n"
14+
"The International Brain Laboratory is a team of systems and computational neuroscientists, working collaboratively to understand the computations that support decision-making in the brain. To achieve this aim, we have developed a standardized decision-making task in mice in order that probes decision-making. The task requires mice to perform decisions by combining incoming visual evidence with internal beliefs about the dynamic structure of the environment. Please read our accompanying [paper (The International Brain Laboratory et al. 2020)]( https://doi.org/10.7554/eLife.63711) for details on the decision-making task and the experiment.\n"
1515
]
1616
},
1717
{
1818
"cell_type": "markdown",
1919
"id": "dd157e91",
20-
"metadata": {
21-
"collapsed": false
22-
},
20+
"metadata": {},
2321
"source": [
2422
"## Overview of the Data\n",
25-
"We have released behavioral data throughout learning from our standardized training pipeline, implemented across 9 labs in 7 institutions. Users can download behavioral data from mice throughout their training, and analyse the transition from novice to expert behavior unfold. The behavioral data is associated with 198 mice up until 2020-03-23, as used in [The International Brain Laboratory et al. 2020](https://elifesciences.org/articles/63711). This dataset contains notably information on the sensory stimuli presented to the mouse, as well as mouse decisions and response times.\n",
23+
"We have released behavioral data throughout learning from our standardized training pipeline, implemented across 9 labs in 7 institutions. Users can download behavioral data from mice throughout their training, and analyse the transition from novice to expert behavior unfold. The behavioral data is associated with 198 mice up until 2020-03-23, as used in [The International Brain Laboratory et al. 2020](https://doi.org/10.7554/eLife.63711). This dataset contains notably information on the sensory stimuli presented to the mouse, as well as mouse decisions and response times.\n",
2624
"\n",
2725
"\n",
2826
"## Data structure and download\n",
@@ -33,21 +31,24 @@
3331
"* [These instructions](https://int-brain-lab.github.io/iblenv/notebooks_external/data_structure.html) to download an example dataset for one session, and get familiarised with the data structure\n",
3432
"* [These instructions](https://int-brain-lab.github.io/iblenv/notebooks_external/data_download.html) to learn how to use the ONE-api to search and download the released datasets\n",
3533
"* [These instructions](https://int-brain-lab.github.io/iblenv/loading_examples.html) to get familiarised with specific data loading functions\n",
36-
"* [These instructions](https://int-brain-lab.github.io/iblenv/dj_docs/dj_public.html) for instructions on how to access this dataset via Datajoint. (warning: this method may be retired in 2023)\n",
3734
"\n",
3835
"\n",
3936
"Note:\n",
4037
"\n",
41-
"* The tag associated to this release is `2021_Q1_IBL_et_al_Behaviour`"
38+
"* The tag associated to this release is `2021_Q1_IBL_et_al_Behaviour`\n",
39+
"\n",
40+
"\n",
41+
"## How to cite this dataset\n",
42+
"If you are using this dataset for your research please cite the [Behavior Paper](https://doi.org/10.7554/eLife.63711) and see the **How to cite** section in the associated entry in the [AWS open data registry](https://registry.opendata.aws/ibl-behaviour/)."
4243
]
4344
}
4445
],
4546
"metadata": {
4647
"celltoolbar": "Edit Metadata",
4748
"kernelspec": {
48-
"display_name": "Python [conda env:iblenv] *",
49+
"display_name": "Python 3 (ipykernel)",
4950
"language": "python",
50-
"name": "conda-env-iblenv-py"
51+
"name": "python3"
5152
},
5253
"language_info": {
5354
"codemirror_mode": {
@@ -59,7 +60,7 @@
5960
"name": "python",
6061
"nbconvert_exporter": "python",
6162
"pygments_lexer": "ipython3",
62-
"version": "3.11.6"
63+
"version": "3.9.16"
6364
}
6465
},
6566
"nbformat": 4,

examples/data_release/data_release_brainwidemap.ipynb

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@
1111
"source": [
1212
"# Data Release - Brain Wide Map\n",
1313
"\n",
14-
"IBL aims to understand the neural basis of decision-making in the mouse by gathering a whole-brain activity map composed of electrophysiological recordings pooled from multiple laboratories. We have systematically recorded from nearly all major brain areas with Neuropixels probes, using a grid system for unbiased sampling and replicating each recording site in at least two laboratories. These data have been used to construct a brain-wide map of activity at single-spike cellular resolution during a [decision-making task]((https://elifesciences.org/articles/63711)). Please read the associated article [(IBL et al. 2023)](https://www.biorxiv.org/content/10.1101/2023.07.04.547681v2). In addition to the map, this data set contains other information gathered during the task: sensory stimuli presented to the mouse; mouse decisions and response times; and mouse pose information from video recordings and DeepLabCut analysis. Please read our accompanying [technical paper](https://doi.org/10.6084/m9.figshare.21400815) for details on the experiment and data processing pipelines. To explore the data, visit [our vizualisation website](https://viz.internationalbrainlab.org/)."
14+
"IBL aims to understand the neural basis of decision-making in the mouse by gathering a whole-brain activity map composed of electrophysiological recordings pooled from multiple laboratories. We have systematically recorded from nearly all major brain areas with Neuropixels probes, using a grid system for unbiased sampling and replicating each recording site in at least two laboratories. These data have been used to construct a brain-wide map of activity at single-spike cellular resolution during a [decision-making task]((https://elifesciences.org/articles/63711)). Please read the associated article [(IBL et al. 2023)](https://doi.org/10.1101/2023.07.04.547681). In addition to the map, this data set contains other information gathered during the task: sensory stimuli presented to the mouse; mouse decisions and response times; and mouse pose information from video recordings and DeepLabCut analysis. Please read our accompanying [technical paper](https://doi.org/10.6084/m9.figshare.21400815) for details on the experiment and data processing pipelines. To explore the data, visit [our vizualisation website](https://viz.internationalbrainlab.org/)."
1515
]
1616
},
1717
{
1818
"cell_type": "markdown",
1919
"id": "e9be5894",
20-
"metadata": {
21-
"collapsed": false
22-
},
20+
"metadata": {},
2321
"source": [
2422
"## Overview of the Data\n",
25-
"We have released data from 459 Neuropixel recording sessions, which encompass 699 probe insertions, obtained in 139 subjects performing the IBL task across 12 different laboratories. As output of spike-sorting, there are 376730 units; of which 45085 are considered to be of good quality. In total, 138 brain regions were recorded in sufficient numbers for inclusion in IBL’s analyses [(IBL et al. 2023)](https://www.biorxiv.org/content/10.1101/2023.07.04.547681v2).\n",
23+
"We have released data from 459 Neuropixel recording sessions, which encompass 699 probe insertions, obtained in 139 subjects performing the IBL task across 12 different laboratories. As output of spike-sorting, there are 376730 units; of which 45085 are considered to be of good quality. In total, 138 brain regions were recorded in sufficient numbers for inclusion in IBL’s analyses [(IBL et al. 2023)](https://doi.org/10.1101/2023.07.04.547681).\n",
2624
"\n",
2725
"## Data structure and download\n",
2826
"The organisation of the data follows the standard IBL data structure.\n",
@@ -38,6 +36,10 @@
3836
"* The tag associated to this release is `Brainwidemap`\n",
3937
"\n",
4038
"\n",
39+
"## How to cite this dataset\n",
40+
"If you are using this dataset for your research please cite the [Brain Wide Map Paper](https://doi.org/10.1101/2023.07.04.547681) and see the **How to cite** section in the associated entry in the [AWS open data registry](https://registry.opendata.aws/ibl-brain-wide-map/).\n",
41+
"\n",
42+
"\n",
4143
"## Updates on the data\n",
4244
"Note: The section [Overview of the Data](#overview-of-the-data) contains the latest numbers released.\n",
4345
"\n",
@@ -54,9 +56,9 @@
5456
"metadata": {
5557
"celltoolbar": "Edit Metadata",
5658
"kernelspec": {
57-
"display_name": "Python [conda env:iblenv] *",
59+
"display_name": "Python 3 (ipykernel)",
5860
"language": "python",
59-
"name": "conda-env-iblenv-py"
61+
"name": "python3"
6062
},
6163
"language_info": {
6264
"codemirror_mode": {
@@ -68,7 +70,7 @@
6870
"name": "python",
6971
"nbconvert_exporter": "python",
7072
"pygments_lexer": "ipython3",
71-
"version": "3.11.6"
73+
"version": "3.9.16"
7274
}
7375
},
7476
"nbformat": 4,

0 commit comments

Comments
 (0)