Skip to content

Commit 2e1f91c

Browse files
committed
Merge branch 'release/2.10.1'
2 parents 15696d8 + 4a780e0 commit 2e1f91c

27 files changed

+2508
-273
lines changed

brainbox/behavior/dlc.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,12 @@ def plot_wheel_position(wheel_position, wheel_time, trials_df):
350350

351351
plt.axvline(x=0, linestyle='--', c='k', label='stimOn')
352352
plt.axhline(y=-0.26, linestyle='--', c='g', label='reward')
353+
plt.axhline(y=0.26, linestyle='--', c='g', label='reward')
353354
plt.ylim([-0.27, 0.27])
354355
plt.xlabel('time [sec]')
355-
plt.ylabel('wheel position [rad]')
356+
plt.ylabel('wheel position diff to first value [rad]')
356357
plt.legend(loc='center right')
357-
plt.title('Wheel position')
358+
plt.title('Wheel position trial avg\n(and individual trials)')
358359
plt.tight_layout()
359360

360361
return plt.gca()
@@ -406,7 +407,7 @@ def plot_lick_hist(lick_times, trials_df):
406407
plt.plot(times, pd.DataFrame.from_dict(dict(zip(correct.index, incorrect.values))).mean(axis=1),
407408
c='gray', label='incorrect trial')
408409
plt.axvline(x=0, label='feedback', linestyle='--', c='purple')
409-
plt.title('Lick events')
410+
plt.title('Lick events trial avg')
410411
plt.xlabel('time [sec]')
411412
plt.ylabel('lick events [a.u.]')
412413
plt.legend(loc='lower right')
@@ -479,7 +480,7 @@ def plot_motion_energy_hist(camera_dict, trials_df):
479480
plt.xlabel('time [sec]')
480481
plt.axvline(x=0, label='stimOn', linestyle='--', c='k')
481482
plt.legend(loc='lower right')
482-
plt.title('Motion Energy')
483+
plt.title('Motion Energy trial avg\n(+/- std)')
483484
if len(missing_data) > 0:
484485
ax = plt.gca()
485486
ax.text(.95, .35, f"Data incomplete for\n{' and '.join(missing_data)} camera", color='r', fontsize=10,
@@ -523,7 +524,7 @@ def plot_speed_hist(dlc_df, cam_times, trials_df, feature='paw_r', cam='left', l
523524
plt.plot(times, pd.DataFrame.from_dict(dict(zip(incorrect.index, incorrect.values))).mean(axis=1),
524525
c='gray', label='incorrect trial')
525526
plt.axvline(x=0, label='stimOn', linestyle='--', c='r')
526-
plt.title(f'{feature.split("_")[0].capitalize()} speed ({cam} cam)')
527+
plt.title(f'{feature.capitalize()} speed trial avg\n({cam.upper()} cam)')
527528
plt.xticks([-0.5, 0, 0.5, 1, 1.5])
528529
plt.xlabel('time [sec]')
529530
plt.ylabel('speed [px/sec]')
@@ -559,8 +560,8 @@ def plot_pupil_diameter_hist(pupil_diameter, cam_times, trials_df, cam='left'):
559560
plt.plot(times, pupil_mean, label=align_to.split("_")[0], color=color)
560561
plt.fill_between(times, pupil_mean + pupil_std, pupil_mean - pupil_std, color=color, alpha=0.5)
561562
plt.axvline(x=0, linestyle='--', c='k')
562-
plt.title(f'Pupil diameter ({cam} cam)')
563+
plt.title(f'Pupil diameter trial avg\n({cam.upper()} cam)')
563564
plt.xlabel('time [sec]')
564565
plt.xticks([-0.5, 0, 0.5, 1, 1.5])
565-
plt.ylabel('pupil diameter [px]')
566+
plt.ylabel('z-scored smoothed pupil diameter [px]')
566567
plt.legend(loc='lower right', title='aligned to')

brainbox/ephys_plots.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,30 @@ def histc(x, bins):
496496
return data.convert2dict(), fig, ax
497497

498498
return data
499+
500+
501+
def image_raw_data(raw, fs, chn_coords=None, cmap='bone', title=None, display=False, gain=-90, **kwargs):
502+
503+
def gain2level(gain):
504+
return 10 ** (gain / 20) * 4 * np.array([-1, 1])
505+
506+
ylabel = 'Channel index' if chn_coords is None else 'Distance from probe tip (um)'
507+
title = title or 'Raw data'
508+
509+
y = np.arange(raw.shape[1]) if chn_coords is None else chn_coords[:, 1]
510+
511+
x = np.array([0, raw.shape[0] - 1]) / fs * 1e3
512+
513+
data = ImagePlot(raw, y=y, cmap=cmap)
514+
data.set_labels(title=title, xlabel='Time (ms)',
515+
ylabel=ylabel, clabel='Power (uV)')
516+
clim = gain2level(gain)
517+
data.set_clim(clim=clim)
518+
data.set_xlim(xlim=x)
519+
data.set_ylim()
520+
521+
if display:
522+
ax, fig = plot_image(data.convert2dict(), **kwargs)
523+
return data.convert2dict(), fig, ax
524+
525+
return data

brainbox/io/one.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
import pandas as pd
99
from scipy.interpolate import interp1d
1010

11-
from one.api import ONE
11+
from one.api import ONE, One
1212
import one.alf.io as alfio
13+
from one.alf import cache
1314

1415
from iblutil.util import Bunch
15-
1616
from ibllib.io import spikeglx
1717
from ibllib.io.extractors.training_wheel import extract_wheel_moves, extract_first_movement_times
1818
from ibllib.ephys.neuropixel import SITES_COORDINATES, TIP_SIZE_UM, trace_header
@@ -872,10 +872,15 @@ def load_channels_from_insertion(ins, depths=None, one=None, ba=None):
872872
class SpikeSortingLoader:
873873
"""
874874
Object that will load spike sorting data for a given probe insertion.
875-
876-
875+
This class can be instantiated in several manners
876+
- With Alyx database probe id:
877+
SpikeSortingLoader(pid=pid, one=one)
878+
- With Alyx database eic and probe name:
879+
SpikeSortingLoader(eid=eid, pname='probe00', one=one)
880+
- From a local session and probe name:
881+
SpikeSortingLoader(session_path=session_path, pname='probe00')
877882
"""
878-
one: ONE
883+
one: ONE = None
879884
atlas: None = None
880885
pid: str = None
881886
eid: str = ''
@@ -891,14 +896,26 @@ class SpikeSortingLoader:
891896
spike_sorting_path: Path = None
892897

893898
def __post_init__(self):
899+
# pid gets precedence
894900
if self.pid is not None:
895901
self.eid, self.pname = self.one.pid2eid(self.pid)
896-
if self.atlas is None:
897-
self.atlas = AllenAtlas()
898-
self.session_path = self.one.eid2path(self.eid)
902+
self.session_path = self.one.eid2path(self.eid)
903+
# then eid / pname combination
904+
elif self.session_path is None or self.session_path == '':
905+
self.session_path = self.one.eid2path(self.eid)
906+
# fully local providing a session path
907+
else:
908+
self.one = One(cache_dir=self.session_path.parents[2], mode='local')
909+
df_sessions = cache._make_sessions_df(self.session_path)
910+
self.one._cache['sessions'] = df_sessions.set_index('id')
911+
self.one._cache['datasets'] = cache._make_datasets_df(self.session_path, hash_files=False)
912+
self.eid = str(self.session_path.relative_to(self.session_path.parents[2]))
913+
# populates default properties
899914
self.collections = self.one.list_collections(
900915
self.eid, filename='spikes*', collection=f"alf/{self.pname}*")
901916
self.datasets = self.one.list_datasets(self.eid)
917+
if self.atlas is None:
918+
self.atlas = AllenAtlas()
902919
self.files = {}
903920

904921
@staticmethod

brainbox/io/spikeglx.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,13 @@ def stream(pid, t0, nsecs=1, one=None, cache_folder=None, remove_cached=False, t
116116
:param one: An instance of ONE
117117
:param cache_folder:
118118
:param typ: 'ap' or 'lf'
119-
:return: sr, dsets, t0
119+
:return: sr, t0
120120
"""
121-
CHUNK_DURATION_SECS = 1 # the mtscomp chunk duration. Right now it's a constant
122121
if nsecs > 10:
123-
ValueError(f'Streamer works only with 10 or less seconds, set nsecs to lesss than {nsecs}')
122+
ValueError(f'Streamer works only with 10 or less seconds, set nsecs to less than {nsecs}')
124123
assert one
125124
assert typ in ['lf', 'ap']
126-
t0 = np.floor(t0 / CHUNK_DURATION_SECS) * CHUNK_DURATION_SECS
125+
127126
if cache_folder is None:
128127
samples_folder = Path(one.alyx._par.CACHE_DIR).joinpath('cache', typ)
129128

@@ -134,8 +133,13 @@ def stream(pid, t0, nsecs=1, one=None, cache_folder=None, remove_cached=False, t
134133
ch_file = one._download_datasets(ch_rec)[0]
135134
one._download_datasets(meta_rec)[0]
136135

137-
first_chunk = int(t0 / CHUNK_DURATION_SECS)
138-
last_chunk = int((t0 + nsecs) / CHUNK_DURATION_SECS) - 1
136+
import json
137+
with open(ch_file) as fid:
138+
chinfo = json.load(fid)
139+
tbounds = np.array(chinfo['chunk_bounds']) / chinfo['sample_rate']
140+
first_chunk = np.maximum(0, np.searchsorted(tbounds, t0 + 0.01) - 1)
141+
last_chunk = np.maximum(0, np.searchsorted(tbounds, t0 + + 0.01 + nsecs) - 2)
142+
t0 = tbounds[first_chunk]
139143

140144
samples_folder.mkdir(exist_ok=True, parents=True)
141145
sr = spikeglx.download_raw_partial(

brainbox/plot_base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,11 @@ def _get_scale(self, axis):
185185
:param axis: 'x' or 'y'
186186
:return:
187187
"""
188-
lim = self._set_lim(axis)
188+
if axis == 'x':
189+
lim = self.xlim
190+
else:
191+
lim = self.ylim
192+
lim = self._set_lim(axis, lim=lim)
189193
scale = (lim[1] - lim[0]) / self.data['c'].shape[axis_dict[axis]]
190194
return scale
191195

examples/atlas/Working with ibllib atlas.ipynb

Lines changed: 217 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)