Skip to content

Commit f1d3a10

Browse files
committed
Merge branch 'release/2.29.0'
2 parents 68c69df + 043441f commit f1d3a10

File tree

7 files changed

+86
-9
lines changed

7 files changed

+86
-9
lines changed

.github/workflows/ibllib_ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,28 @@ on:
1010
branches: [ master, develop ]
1111

1212
jobs:
13+
detect-outstanding-prs: # Don't run builds for push events if associated with PR
14+
runs-on: ubuntu-latest
15+
env:
16+
GH_TOKEN: ${{ github.token }}
17+
outputs:
18+
abort: ${{ steps.debounce.outputs.abort }}
19+
steps:
20+
- name: Debounce
21+
if: github.event_name == 'push'
22+
id: debounce
23+
run: |
24+
pr_branches=$(gh pr list --json headRefName --repo $GITHUB_REPOSITORY)
25+
if [[ $(echo "$pr_branches" | jq -r --arg GITHUB_REF '.[].headRefName | select(. == $GITHUB_REF)') ]]; then
26+
echo "This push is associated with a pull request. Skipping the job."
27+
echo "abort=true" >> "$GITHUB_OUTPUT"
28+
fi
29+
1330
build:
1431
name: build (${{ matrix.python-version }}, ${{ matrix.os }})
1532
runs-on: ${{ matrix.os }}
33+
needs: debounce
34+
if: needs.debounce.outputs.abort != 'true'
1635
strategy:
1736
fail-fast: false # Whether to stop execution of other instances
1837
max-parallel: 2

brainbox/io/one.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from ibllib.plots import vertical_lines
2929

3030
import brainbox.plot
31+
from brainbox.io.spikeglx import Streamer
3132
from brainbox.ephys_plots import plot_brain_regions
3233
from brainbox.metrics.single_units import quick_unit_metrics
3334
from brainbox.behavior.wheel import interpolate_position, velocity_filtered
@@ -793,6 +794,7 @@ class SpikeSortingLoader:
793794
datasets: list = None # list of all datasets belonging to the session
794795
# the following properties are the outcome of a reading function
795796
files: dict = None
797+
raw_data_files: list = None # list of raw ap and lf files corresponding to the recording
796798
collection: str = ''
797799
histology: str = '' # 'alf', 'resolved', 'aligned' or 'traced'
798800
spike_sorter: str = 'pykilosort'
@@ -829,6 +831,7 @@ def __post_init__(self):
829831
if self.atlas is None:
830832
self.atlas = AllenAtlas()
831833
self.files = {}
834+
self.raw_data_files = []
832835

833836
def _load_object(self, *args, **kwargs):
834837
"""
@@ -881,6 +884,11 @@ def load_spike_sorting_object(self, obj, *args, **kwargs):
881884
self.download_spike_sorting_object(obj, *args, **kwargs)
882885
return self._load_object(self.files[obj])
883886

887+
def get_version(self, spike_sorter='pykilosort'):
888+
collection = self._get_spike_sorting_collection(spike_sorter=spike_sorter)
889+
dset = self.one.alyx.rest('datasets', 'list', session=self.eid, collection=collection, name='spikes.times.npy')
890+
return dset[0]['version'] if len(dset) else 'unknown'
891+
884892
def download_spike_sorting_object(self, obj, spike_sorter='pykilosort', dataset_types=None, collection=None,
885893
missing='raise', **kwargs):
886894
"""
@@ -919,6 +927,46 @@ def download_spike_sorting(self, **kwargs):
919927
self.download_spike_sorting_object(obj=obj, **kwargs)
920928
self.spike_sorting_path = self.files['spikes'][0].parent
921929

930+
def download_raw_electrophysiology(self, band='ap'):
931+
"""
932+
Downloads raw electrophysiology data files on local disk.
933+
:param band: "ap" (default) or "lf" for LFP band
934+
:return: list of raw data files full paths (ch, meta and cbin files)
935+
"""
936+
raw_data_files = []
937+
for suffix in [f'*.{band}.ch', f'*.{band}.meta', f'*.{band}.cbin']:
938+
try:
939+
# FIXME: this will fail if multiple LFP segments are found
940+
raw_data_files.append(self.one.load_dataset(
941+
self.eid,
942+
download_only=True,
943+
collection=f'raw_ephys_data/{self.pname}',
944+
dataset=suffix,
945+
check_hash=False,
946+
))
947+
except ALFObjectNotFound:
948+
_logger.debug(f"{self.session_path} can't locate raw data collection raw_ephys_data/{self.pname}, file {suffix}")
949+
self.raw_data_files = list(set(self.raw_data_files + raw_data_files))
950+
return raw_data_files
951+
952+
def raw_electrophysiology(self, stream=True, band='ap', **kwargs):
953+
"""
954+
Returns a reader for the raw electrophysiology data
955+
By default it is a streamer object, but if stream is False, it will return a spikeglx.Reader after having
956+
downloaded the raw data file if necessary
957+
:param stream:
958+
:param band:
959+
:param kwargs:
960+
:return:
961+
"""
962+
if stream:
963+
return Streamer(pid=self.pid, one=self.one, typ=band, **kwargs)
964+
else:
965+
raw_data_files = self.download_raw_electrophysiology(band=band)
966+
cbin_file = next(filter(lambda f: f.name.endswith(f'.{band}.cbin'), raw_data_files), None)
967+
if cbin_file is not None:
968+
return spikeglx.Reader(cbin_file)
969+
922970
def load_channels(self, **kwargs):
923971
"""
924972
Loads channels
@@ -1282,7 +1330,8 @@ def load_trials(self):
12821330
"""
12831331
# itiDuration frequently has a mismatched dimension, and we don't need it, exclude using regex
12841332
self.one.wildcards = False
1285-
self.trials = self.one.load_object(self.eid, 'trials', collection='alf', attribute=r'(?!itiDuration).*').to_df()
1333+
self.trials = self.one.load_object(
1334+
self.eid, 'trials', collection='alf', attribute=r'(?!itiDuration).*').to_df()
12861335
self.one.wildcards = True
12871336
self.data_info.loc[self.data_info['name'] == 'trials', 'is_loaded'] = True
12881337

ibllib/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import logging
33
import warnings
44

5-
__version__ = '2.28.2'
5+
__version__ = '2.29.0'
6+
67
warnings.filterwarnings('always', category=DeprecationWarning, module='ibllib')
78

89
# if this becomes a full-blown library we should let the logging configuration to the discretion of the dev

ibllib/atlas/genes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Gene expression maps."""
22

3-
from iblatlas import genes
3+
from iblatlas.genomics import genes
44
from ibllib.atlas import deprecated_decorator
55

66

ibllib/io/session_params.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,10 @@ def get_task_protocol(sess_params, task_collection=None):
318318
"""
319319
collections = get_collections({'tasks': sess_params.get('tasks')})
320320
if task_collection is None:
321-
return set(collections.keys()) # Return all protocols
321+
if len(collections) == 0:
322+
return None
323+
else:
324+
return set(collections.keys()) # Return all protocols
322325
else:
323326
return next((k for k, v in collections.items() if v == task_collection), None)
324327

release_notes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## Release Notes 2.29
2+
3+
### features
4+
- Added raw data loaders and synchronisation tools in brainbox.io.one.SpikeSortingLoader, method `ssl.raw_electrophysiology()`
5+
16
## Release Notes 2.28
27

38
### features

requirements.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ flake8>=3.7.8
55
globus-sdk
66
graphviz
77
matplotlib>=3.0.3
8-
mtscomp>=1.0.1
98
numba>=0.56
109
numpy>=1.18
1110
nptdms
1211
opencv-python-headless
1312
pandas
14-
phylib>=2.4
1513
pyarrow
1614
pynrrd>=0.4.0
1715
pytest
@@ -23,11 +21,13 @@ sparse
2321
seaborn>=0.9.0
2422
tqdm>=4.32.1
2523
# ibl libraries
24+
iblatlas>=0.4.0
2625
ibl-neuropixel>=0.8.1
2726
iblutil>=1.7.0
2827
labcams # widefield extractor
29-
ONE-api>=2.5
28+
mtscomp>=1.0.1
29+
ONE-api>=2.6
30+
phylib>=2.4
31+
psychofit
3032
slidingRP>=1.0.0 # steinmetz lab refractory period metrics
3133
wfield==0.3.7 # widefield extractor frozen for now (2023/07/15) until Joao fixes latest version
32-
psychofit
33-
iblatlas

0 commit comments

Comments
 (0)