Skip to content

Commit e31bafb

Browse files
committed
Merge branch 'release/2.25.0'
2 parents 184a540 + a5facc9 commit e31bafb

File tree

103 files changed

+9911
-4234
lines changed

Some content is hidden

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

103 files changed

+9911
-4234
lines changed

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ include ibllib/atlas/cosmos.npy
55
include ibllib/atlas/swanson.npy
66
include ibllib/atlas/mappings.pqt
77
include ibllib/io/extractors/extractor_types.json
8+
include ibllib/io/extractors/task_extractor_map.json
89
include brainbox/tests/wheel_test.p
910
recursive-include brainbox/tests/fixtures *
1011
recursive-include ibllib/qc/reference *
1112
graft ibllib/tests/extractors/data
1213
graft ibllib/io/extractors/ephys_sessions
14+
graft ibllib/io/extractors/mesoscope
1315
graft ibllib/tests/fixtures
1416
recursive-include oneibl/tests/fixtures *

brainbox/behavior/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Behaviour analysis functions for the IBL task."""

brainbox/behavior/dlc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from scipy.stats import zscore
1313

1414
from neurodsp.smooth import smooth_interpolate_savgol
15-
from brainbox.processing import bincount2D
15+
from iblutil.numerical import bincount2D
1616
import brainbox.behavior.wheel as bbox_wheel
1717

1818
logger = logging.getLogger('ibllib')

brainbox/behavior/pyschofit.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
The psychofit toolbox contains tools to fit two-alternative psychometric
2+
(DEPRECATED) The psychofit toolbox contains tools to fit two-alternative psychometric
33
data. The fitting is done using maximal likelihood estimation: one
44
assumes that the responses of the subject are given by a binomial
55
distribution whose mean is given by the psychometric function.
@@ -16,14 +16,28 @@
1616
For more info, see:
1717
- Examples: Examples of use of psychofit toolbox
1818
Matteo Carandini, 2000-2015
19+
20+
NB: USE THE PSYCHOFIT PIP PACKAGE INSTEAD.
1921
"""
2022

2123
import functools
24+
import warnings
25+
import traceback
26+
import logging
27+
2228
import numpy as np
2329
import scipy.optimize
2430
from scipy.special import erf
2531

2632

33+
for line in traceback.format_stack():
34+
print(line.strip())
35+
36+
msg = 'brainbox.behavior.pyschofit has been deprecated. Install psychofit via pip. See stack above'
37+
warnings.warn(msg, DeprecationWarning)
38+
logging.getLogger(__name__).warning(msg)
39+
40+
2741
def mle_fit_psycho(data, P_model='weibull', parstart=None, parmin=None, parmax=None, nfits=5):
2842
"""
2943
Maximumum likelihood fit of psychometric function.

brainbox/behavior/training.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from one.api import ONE
1414
from one.alf.exceptions import ALFObjectNotFound
1515

16-
import brainbox.behavior.pyschofit as psy
16+
import psychofit as psy
1717

1818
_logger = logging.getLogger('ibllib')
1919

@@ -123,9 +123,9 @@ def get_subject_training_status(subj, date=None, details=True, one=None):
123123

124124
def get_sessions(subj, date=None, one=None):
125125
"""
126-
Download and load in training data for a specfied subject. If a date is given it will load data
127-
from the three (or as many are available) previous sessions up to the specified date, if not it
128-
will load data from the last three training sessions that have data available
126+
Download and load in training data for a specified subject. If a date is given it will load
127+
data from the three (or as many as are available) previous sessions up to the specified date.
128+
If not it will load data from the last three training sessions that have data available.
129129
130130
:param subj: subject nickname (must match the name registered on Alyx)
131131
:type subj: string
@@ -227,7 +227,7 @@ def get_training_status(trials, task_protocol, ephys_sess_dates, n_delay):
227227
"""
228228
Compute training status of a subject from three consecutive training datasets
229229
230-
:param trials: dict containing trials objects from three consective training sessions
230+
:param trials: dict containing trials objects from three consecutive training sessions
231231
:type trials: Bunch
232232
:param task_protocol: task protocol used for the three training session, can be 'training',
233233
'biased' or 'ephys'
@@ -385,7 +385,7 @@ def compute_training_info(trials, trials_all):
385385
"""
386386
Compute all relevant performance metrics for when subject is on trainingChoiceWorld
387387
388-
:param trials: dict containing trials objects from three consective training sessions,
388+
:param trials: dict containing trials objects from three consecutive training sessions,
389389
keys are session dates
390390
:type trials: Bunch
391391
:param trials_all: trials object with data concatenated over three training sessions
@@ -410,7 +410,7 @@ def compute_bias_info(trials, trials_all):
410410
"""
411411
Compute all relevant performance metrics for when subject is on biasedChoiceWorld
412412
413-
:param trials: dict containing trials objects from three consective training sessions,
413+
:param trials: dict containing trials objects from three consecutive training sessions,
414414
keys are session dates
415415
:type trials: Bunch
416416
:param trials_all: trials object with data concatenated over three training sessions
@@ -667,7 +667,7 @@ def criterion_delay(n_trials, perf_easy):
667667

668668
def plot_psychometric(trials, ax=None, title=None, plot_ci=False, ci_aplha=0.32, **kwargs):
669669
"""
670-
Function to plot pyschometric curve plots a la datajoint webpage
670+
Function to plot psychometric curve plots a la datajoint webpage
671671
:param trials:
672672
:return:
673673
"""
@@ -730,7 +730,7 @@ def plot_psychometric(trials, ax=None, title=None, plot_ci=False, ci_aplha=0.32,
730730

731731
def plot_reaction_time(trials, ax=None, title=None, plot_ci=False, ci_alpha=0.32, **kwargs):
732732
"""
733-
Function to plot reaction time against contrast a la datajoint webpage (inversed for some reason??)
733+
Function to plot reaction time against contrast a la datajoint webpage (inverted for some reason??)
734734
:param trials:
735735
:return:
736736
"""

brainbox/behavior/wheel.py

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
"""
2-
Set of functions to handle wheel data
2+
Set of functions to handle wheel data.
33
"""
4+
import logging
5+
import warnings
6+
import traceback
7+
48
import numpy as np
59
from numpy import pi
10+
from iblutil.numerical import between_sorted
611
import scipy.interpolate as interpolate
712
import scipy.signal
813
from scipy.linalg import hankel
@@ -13,11 +18,11 @@
1318
__all__ = ['cm_to_deg',
1419
'cm_to_rad',
1520
'interpolate_position',
16-
'last_movement_onset',
21+
'get_movement_onset',
1722
'movements',
1823
'samples_to_cm',
1924
'traces_by_trial',
20-
'velocity_smoothed']
25+
'velocity_filtered']
2126

2227
# Define some constants
2328
ENC_RES = 1024 * 4 # Rotary encoder resolution, assumes X4 encoding
@@ -49,6 +54,8 @@ def interpolate_position(re_ts, re_pos, freq=1000, kind='linear', fill_gaps=None
4954
Timestamps of interpolated positions
5055
"""
5156
t = np.arange(re_ts[0], re_ts[-1], 1 / freq) # Evenly resample at frequency
57+
if t[-1] > re_ts[-1]:
58+
t = t[:-1] # Occasionally due to precision errors the last sample may be outside of range.
5259
yinterp = interpolate.interp1d(re_ts, re_pos, kind=kind)(t)
5360

5461
if fill_gaps:
@@ -63,7 +70,7 @@ def interpolate_position(re_ts, re_pos, freq=1000, kind='linear', fill_gaps=None
6370

6471
def velocity(re_ts, re_pos):
6572
"""
66-
Compute wheel velocity from non-uniformly sampled wheel data. Returns the velocity
73+
(DEPRECATED) Compute wheel velocity from non-uniformly sampled wheel data. Returns the velocity
6774
at the same samples locations as the position through interpolation.
6875
6976
Parameters
@@ -78,6 +85,13 @@ def velocity(re_ts, re_pos):
7885
np.ndarray
7986
numpy array of velocities
8087
"""
88+
for line in traceback.format_stack():
89+
print(line.strip())
90+
91+
msg = 'brainbox.behavior.wheel.velocity has been deprecated. Use velocity_filtered instead.'
92+
warnings.warn(msg, DeprecationWarning)
93+
logging.getLogger(__name__).warning(msg)
94+
8195
dp = np.diff(re_pos)
8296
dt = np.diff(re_ts)
8397
# Compute raw velocity
@@ -92,12 +106,23 @@ def velocity(re_ts, re_pos):
92106

93107
def velocity_filtered(pos, fs, corner_frequency=20, order=8):
94108
"""
95-
Compute wheel velocity from uniformly sampled wheel data
109+
Compute wheel velocity from uniformly sampled wheel data.
110+
111+
pos: array_like
112+
Vector of uniformly sampled wheel positions.
113+
fs : float
114+
Frequency in Hz of the sampling frequency.
115+
corner_frequency : float
116+
Corner frequency of low-pass filter.
117+
order : int
118+
Order of Butterworth filter.
96119
97-
:param pos: vector of uniformly sampled wheel positions
98-
:param fs: scalar, sampling frequency
99-
:param corner_frequency: scalar, corner frequency of low-pass filter
100-
:param order: scalar, order of Butterworth filter
120+
Returns
121+
-------
122+
vel : np.ndarray
123+
Array of velocity values.
124+
acc : np.ndarray
125+
Array of acceleration values.
101126
"""
102127
sos = scipy.signal.butter(**{'N': order, 'Wn': corner_frequency / fs * 2, 'btype': 'lowpass'}, output='sos')
103128
vel = np.insert(np.diff(scipy.signal.sosfiltfilt(sos, pos)), 0, 0) * fs
@@ -107,7 +132,7 @@ def velocity_filtered(pos, fs, corner_frequency=20, order=8):
107132

108133
def velocity_smoothed(pos, freq, smooth_size=0.03):
109134
"""
110-
Compute wheel velocity from uniformly sampled wheel data
135+
(DEPRECATED) Compute wheel velocity from uniformly sampled wheel data.
111136
112137
Parameters
113138
----------
@@ -125,6 +150,13 @@ def velocity_smoothed(pos, freq, smooth_size=0.03):
125150
acc : np.ndarray
126151
Array of acceleration values
127152
"""
153+
for line in traceback.format_stack():
154+
print(line.strip())
155+
156+
msg = 'brainbox.behavior.wheel.velocity_smoothed has been deprecated. Use velocity_filtered instead.'
157+
warnings.warn(msg, DeprecationWarning)
158+
logging.getLogger(__name__).warning(msg)
159+
128160
# Define our smoothing window with an area of 1 so the units won't be changed
129161
std_samps = np.round(smooth_size * freq) # Standard deviation relative to sampling frequency
130162
N = std_samps * 6 # Number of points in the Gaussian covering +/-3 standard deviations
@@ -141,15 +173,24 @@ def velocity_smoothed(pos, freq, smooth_size=0.03):
141173

142174
def last_movement_onset(t, vel, event_time):
143175
"""
144-
Find the time at which movement started, given an event timestamp that occurred during the
145-
movement. Movement start is defined as the first sample after the velocity has been zero
146-
for at least 50ms. Wheel inputs should be evenly sampled.
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.
147181
148182
:param t: numpy array of wheel timestamps in seconds
149183
:param vel: numpy array of wheel velocities
150184
:param event_time: timestamp anywhere during movement of interest, e.g. peak velocity
151185
:return: timestamp of movement onset
152186
"""
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, DeprecationWarning)
192+
logging.getLogger(__name__).warning(msg)
193+
153194
# Look back from timestamp
154195
threshold = 50e-3
155196
mask = t < event_time
@@ -166,6 +207,42 @@ def last_movement_onset(t, vel, event_time):
166207
return t
167208

168209

210+
def get_movement_onset(intervals, event_times):
211+
"""
212+
Find the time at which movement started, given an event timestamp that occurred during the
213+
movement.
214+
215+
Parameters
216+
----------
217+
intervals : numpy.array
218+
The wheel movement intervals.
219+
event_times : numpy.array
220+
Sorted event timestamps anywhere during movement of interest, e.g. peak velocity, feedback
221+
time.
222+
223+
Returns
224+
-------
225+
numpy.array
226+
An array the length of event_time of intervals.
227+
228+
Examples
229+
--------
230+
Find the last movement onset before each trial response time
231+
232+
>>> trials = one.load_object(eid, 'trials')
233+
>>> wheelMoves = one.load_object(eid, 'wheelMoves')
234+
>>> onsets = last_movement_onset(wheelMoves.intervals, trials.response_times)
235+
"""
236+
if not np.all(np.diff(event_times) > 0):
237+
raise ValueError('event_times must be in ascending order.')
238+
onsets = np.full(event_times.size, np.nan)
239+
for i in np.arange(intervals.shape[0]):
240+
onset = between_sorted(event_times, intervals[i, :])
241+
if np.any(onset):
242+
onsets[onset] = intervals[i, 0]
243+
return onsets
244+
245+
169246
def movements(t, pos, freq=1000, pos_thresh=8, t_thresh=.2, min_gap=.1, pos_thresh_onset=1.5,
170247
min_dur=.05, make_plots=False):
171248
"""
@@ -296,7 +373,7 @@ def movements(t, pos, freq=1000, pos_thresh=8, t_thresh=.2, min_gap=.1, pos_thre
296373
if make_plots:
297374
fig, axes = plt.subplots(nrows=2, sharex='all')
298375
indices = np.sort(np.hstack((onset_samps, offset_samps))) # Points to split trace
299-
vel, acc = velocity_smoothed(pos, freq, 0.015)
376+
vel, acc = velocity_filtered(pos, freq)
300377

301378
# Plot the wheel position and velocity
302379
for ax, y in zip(axes, (pos, vel)):
@@ -440,6 +517,6 @@ def to_mask(a, b):
440517
return [(cuts[n][0, :], cuts[n][1, :]) for n in range(len(cuts))] if separate else cuts
441518

442519

443-
if __name__ == "__main__":
520+
if __name__ == '__main__':
444521
import doctest
445522
doctest.testmod()

brainbox/ephys_plots.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import matplotlib.pyplot as plt
44
from brainbox.plot_base import (ImagePlot, ScatterPlot, ProbePlot, LinePlot, plot_line,
55
plot_image, plot_probe, plot_scatter, arrange_channels2banks)
6-
from brainbox.processing import bincount2D, compute_cluster_average
6+
from brainbox.processing import compute_cluster_average
7+
from iblutil.numerical import bincount2D
78
from ibllib.atlas.regions import BrainRegions
89

910

0 commit comments

Comments
 (0)