From 4f1bb4861da271429b91404ddb09eb3a51ec73f2 Mon Sep 17 00:00:00 2001 From: luiz Date: Mon, 7 Apr 2025 16:04:40 +0200 Subject: [PATCH 1/9] nev alone --- src/spikeinterface/extractors/neoextractors/blackrock.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spikeinterface/extractors/neoextractors/blackrock.py b/src/spikeinterface/extractors/neoextractors/blackrock.py index 8557c811b5..b7f52f7e50 100644 --- a/src/spikeinterface/extractors/neoextractors/blackrock.py +++ b/src/spikeinterface/extractors/neoextractors/blackrock.py @@ -95,8 +95,10 @@ def __init__( sampling_frequency: Optional[float] = None, stream_id: Optional[str] = None, stream_name: Optional[str] = None, + nsx_to_load: Optional[list[int]] = None, ): neo_kwargs = self.map_to_neo_kwargs(file_path) + neo_kwargs["nsx_to_load"] = nsx_to_load NeoBaseSortingExtractor.__init__( self, sampling_frequency=sampling_frequency, From 7bddaa5272d4aa3309544da7ace17a0681b6dc2d Mon Sep 17 00:00:00 2001 From: luiz Date: Tue, 8 Apr 2025 13:39:05 +0200 Subject: [PATCH 2/9] get sampling rate from spike channels --- .../extractors/neoextractors/blackrock.py | 3 +- .../neoextractors/neobaseextractor.py | 32 ++++++++++++------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/blackrock.py b/src/spikeinterface/extractors/neoextractors/blackrock.py index b7f52f7e50..3706b9e795 100644 --- a/src/spikeinterface/extractors/neoextractors/blackrock.py +++ b/src/spikeinterface/extractors/neoextractors/blackrock.py @@ -95,10 +95,9 @@ def __init__( sampling_frequency: Optional[float] = None, stream_id: Optional[str] = None, stream_name: Optional[str] = None, - nsx_to_load: Optional[list[int]] = None, ): neo_kwargs = self.map_to_neo_kwargs(file_path) - neo_kwargs["nsx_to_load"] = nsx_to_load + neo_kwargs["nsx_to_load"] = [] # Tell neo to not load the nsx files NeoBaseSortingExtractor.__init__( self, sampling_frequency=sampling_frequency, diff --git a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py index a9ba4bf5d6..b4fa6e9cbb 100644 --- a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py +++ b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py @@ -95,18 +95,26 @@ def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: If there are no signal streams available from which to extract the sampling frequencies. """ neo_header = self.neo_reader.header - signal_channels = neo_header["signal_channels"] - assert signal_channels.size > 0, "No signal streams to infer the sampling frequency. Set it manually" - - # Get unique pairs of channel_stream_id and channel_sampling_frequencies - channel_sampling_frequencies = signal_channels["sampling_rate"] - channel_stream_id = signal_channels["stream_id"] - unique_pairs = np.unique(np.vstack((channel_stream_id, channel_sampling_frequencies)).T, axis=0) - - # Form a dictionary of stream_id to sampling_frequency - stream_to_sampling_frequencies = {} - for stream_id, sampling_frequency in unique_pairs: - stream_to_sampling_frequencies[stream_id] = float(sampling_frequency) + if "spike_channels" in neo_header: + channels = neo_header["spike_channels"] + channel_sampling_frequencies = channels["wf_sampling_rate"] + stream_to_sampling_frequencies = { + 0: float(np.unique(channel_sampling_frequencies)[0]) + } + elif "signal_channels" in neo_header: + channels = neo_header["signal_channels"] + assert channels.size > 0, "No spike or signal streams to infer the sampling frequency. Set it manually" + # Get unique pairs of channel_stream_id and channel_sampling_frequencies + channel_sampling_frequencies = channels["sampling_rate"] + channel_stream_id = channels["stream_id"] + unique_pairs = np.unique(np.vstack((channel_stream_id, channel_sampling_frequencies)).T, axis=0) + + # Form a dictionary of stream_id to sampling_frequency + stream_to_sampling_frequencies = {} + for stream_id, sampling_frequency in unique_pairs: + stream_to_sampling_frequencies[stream_id] = float(sampling_frequency) + else: + raise AssertionError("No spike or signal streams to infer the sampling frequency. Set it manually") return stream_to_sampling_frequencies From e854f8e0d5ff62d51f6f93c8e4382c9d6ca48001 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:40:16 +0000 Subject: [PATCH 3/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../extractors/neoextractors/neobaseextractor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py index b4fa6e9cbb..ed9c6bacf8 100644 --- a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py +++ b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py @@ -98,9 +98,7 @@ def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: if "spike_channels" in neo_header: channels = neo_header["spike_channels"] channel_sampling_frequencies = channels["wf_sampling_rate"] - stream_to_sampling_frequencies = { - 0: float(np.unique(channel_sampling_frequencies)[0]) - } + stream_to_sampling_frequencies = {0: float(np.unique(channel_sampling_frequencies)[0])} elif "signal_channels" in neo_header: channels = neo_header["signal_channels"] assert channels.size > 0, "No spike or signal streams to infer the sampling frequency. Set it manually" From d7b6fb8d1bf6f55573ab9c9c40107f48b2b241c8 Mon Sep 17 00:00:00 2001 From: luiz Date: Tue, 8 Apr 2025 16:05:24 +0200 Subject: [PATCH 4/9] try to fix error, give preference to estimate rate from signal channels --- .../neoextractors/neobaseextractor.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py index b4fa6e9cbb..c5c8030ecc 100644 --- a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py +++ b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py @@ -95,15 +95,8 @@ def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: If there are no signal streams available from which to extract the sampling frequencies. """ neo_header = self.neo_reader.header - if "spike_channels" in neo_header: - channels = neo_header["spike_channels"] - channel_sampling_frequencies = channels["wf_sampling_rate"] - stream_to_sampling_frequencies = { - 0: float(np.unique(channel_sampling_frequencies)[0]) - } - elif "signal_channels" in neo_header: + if "signal_channels" in neo_header and neo_header["signal_channels"].size > 0: channels = neo_header["signal_channels"] - assert channels.size > 0, "No spike or signal streams to infer the sampling frequency. Set it manually" # Get unique pairs of channel_stream_id and channel_sampling_frequencies channel_sampling_frequencies = channels["sampling_rate"] channel_stream_id = channels["stream_id"] @@ -113,8 +106,14 @@ def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: stream_to_sampling_frequencies = {} for stream_id, sampling_frequency in unique_pairs: stream_to_sampling_frequencies[stream_id] = float(sampling_frequency) + elif "spike_channels" in neo_header and neo_header["spike_channels"].size > 0: + channels = neo_header["spike_channels"] + channel_sampling_frequencies = channels["wf_sampling_rate"] + stream_to_sampling_frequencies = { + 0: float(np.unique(channel_sampling_frequencies)[0]) + } else: - raise AssertionError("No spike or signal streams to infer the sampling frequency. Set it manually") + raise AssertionError("No signal or spike streams to infer the sampling frequency. Set it manually") return stream_to_sampling_frequencies From 3f7308520278b0e04918c470e13c4410599e9678 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:07:57 +0000 Subject: [PATCH 5/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../extractors/neoextractors/neobaseextractor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py index fdc344863d..5c409a257a 100644 --- a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py +++ b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py @@ -108,9 +108,7 @@ def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: elif "spike_channels" in neo_header and neo_header["spike_channels"].size > 0: channels = neo_header["spike_channels"] channel_sampling_frequencies = channels["wf_sampling_rate"] - stream_to_sampling_frequencies = { - 0: float(np.unique(channel_sampling_frequencies)[0]) - } + stream_to_sampling_frequencies = {0: float(np.unique(channel_sampling_frequencies)[0])} else: raise AssertionError("No signal or spike streams to infer the sampling frequency. Set it manually") From 26595b70804b5e18b5ce259899032a98ece181b8 Mon Sep 17 00:00:00 2001 From: luiz Date: Tue, 8 Apr 2025 17:02:35 +0200 Subject: [PATCH 6/9] overwrite method in extractor --- .../extractors/neoextractors/blackrock.py | 31 +++++++++++++++++-- .../neoextractors/neobaseextractor.py | 28 +++++++---------- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/blackrock.py b/src/spikeinterface/extractors/neoextractors/blackrock.py index 3706b9e795..b5709a0444 100644 --- a/src/spikeinterface/extractors/neoextractors/blackrock.py +++ b/src/spikeinterface/extractors/neoextractors/blackrock.py @@ -2,8 +2,8 @@ from pathlib import Path from packaging import version -from typing import Optional - +from typing import Optional, Dict +import numpy as np from spikeinterface.core.core_tools import define_function_from_class @@ -118,6 +118,33 @@ def map_to_neo_kwargs(cls, file_path): neo_kwargs = {"filename": str(file_path)} return neo_kwargs + def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: + """ + Build a mapping from stream_id to sampling frequencies. + + This function creates a dictionary mapping each stream_id to its corresponding sampling + frequency, as extracted from the signal channels in the Neo header. + + Returns + ------- + dict of {str: float} + Dictionary mapping stream_ids to their corresponding sampling frequencies. + + Raises + ------ + AssertionError + If there are no signal streams available from which to extract the sampling frequencies. + """ + neo_header = self.neo_reader.header + if "spike_channels" in neo_header and neo_header["spike_channels"].size > 0: + channels = neo_header["spike_channels"] + channel_sampling_frequencies = channels["wf_sampling_rate"] + stream_to_sampling_frequencies = {0: float(np.unique(channel_sampling_frequencies)[0])} + else: + raise AssertionError("No signal or spike streams to infer the sampling frequency. Set it manually") + + return stream_to_sampling_frequencies + read_blackrock = define_function_from_class(source_class=BlackrockRecordingExtractor, name="read_blackrock") read_blackrock_sorting = define_function_from_class( diff --git a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py index 5c409a257a..a9ba4bf5d6 100644 --- a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py +++ b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py @@ -95,22 +95,18 @@ def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: If there are no signal streams available from which to extract the sampling frequencies. """ neo_header = self.neo_reader.header - if "signal_channels" in neo_header and neo_header["signal_channels"].size > 0: - channels = neo_header["signal_channels"] - # Get unique pairs of channel_stream_id and channel_sampling_frequencies - channel_sampling_frequencies = channels["sampling_rate"] - channel_stream_id = channels["stream_id"] - unique_pairs = np.unique(np.vstack((channel_stream_id, channel_sampling_frequencies)).T, axis=0) - # Form a dictionary of stream_id to sampling_frequency - stream_to_sampling_frequencies = {} - for stream_id, sampling_frequency in unique_pairs: - stream_to_sampling_frequencies[stream_id] = float(sampling_frequency) - elif "spike_channels" in neo_header and neo_header["spike_channels"].size > 0: - channels = neo_header["spike_channels"] - channel_sampling_frequencies = channels["wf_sampling_rate"] - stream_to_sampling_frequencies = {0: float(np.unique(channel_sampling_frequencies)[0])} - else: - raise AssertionError("No signal or spike streams to infer the sampling frequency. Set it manually") + signal_channels = neo_header["signal_channels"] + assert signal_channels.size > 0, "No signal streams to infer the sampling frequency. Set it manually" + + # Get unique pairs of channel_stream_id and channel_sampling_frequencies + channel_sampling_frequencies = signal_channels["sampling_rate"] + channel_stream_id = signal_channels["stream_id"] + unique_pairs = np.unique(np.vstack((channel_stream_id, channel_sampling_frequencies)).T, axis=0) + + # Form a dictionary of stream_id to sampling_frequency + stream_to_sampling_frequencies = {} + for stream_id, sampling_frequency in unique_pairs: + stream_to_sampling_frequencies[stream_id] = float(sampling_frequency) return stream_to_sampling_frequencies From b312c105b85b36fa37e971c08b6ed7e87871daa1 Mon Sep 17 00:00:00 2001 From: luiz Date: Mon, 14 Apr 2025 10:31:31 +0200 Subject: [PATCH 7/9] remove method, add nsx_to_load kwarg --- .../extractors/neoextractors/blackrock.py | 34 +++---------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/blackrock.py b/src/spikeinterface/extractors/neoextractors/blackrock.py index b5709a0444..f46eca7790 100644 --- a/src/spikeinterface/extractors/neoextractors/blackrock.py +++ b/src/spikeinterface/extractors/neoextractors/blackrock.py @@ -92,17 +92,18 @@ class BlackrockSortingExtractor(NeoBaseSortingExtractor): def __init__( self, file_path, - sampling_frequency: Optional[float] = None, stream_id: Optional[str] = None, stream_name: Optional[str] = None, + sampling_frequency: Optional[float] = None, + nsx_to_load: Optional[int | list | str] = None, ): neo_kwargs = self.map_to_neo_kwargs(file_path) - neo_kwargs["nsx_to_load"] = [] # Tell neo to not load the nsx files NeoBaseSortingExtractor.__init__( self, - sampling_frequency=sampling_frequency, stream_id=stream_id, stream_name=stream_name, + sampling_frequency=sampling_frequency, + nsx_to_load=nsx_to_load, **neo_kwargs, ) @@ -118,33 +119,6 @@ def map_to_neo_kwargs(cls, file_path): neo_kwargs = {"filename": str(file_path)} return neo_kwargs - def build_stream_id_to_sampling_frequency_dict(self) -> Dict[str, float]: - """ - Build a mapping from stream_id to sampling frequencies. - - This function creates a dictionary mapping each stream_id to its corresponding sampling - frequency, as extracted from the signal channels in the Neo header. - - Returns - ------- - dict of {str: float} - Dictionary mapping stream_ids to their corresponding sampling frequencies. - - Raises - ------ - AssertionError - If there are no signal streams available from which to extract the sampling frequencies. - """ - neo_header = self.neo_reader.header - if "spike_channels" in neo_header and neo_header["spike_channels"].size > 0: - channels = neo_header["spike_channels"] - channel_sampling_frequencies = channels["wf_sampling_rate"] - stream_to_sampling_frequencies = {0: float(np.unique(channel_sampling_frequencies)[0])} - else: - raise AssertionError("No signal or spike streams to infer the sampling frequency. Set it manually") - - return stream_to_sampling_frequencies - read_blackrock = define_function_from_class(source_class=BlackrockRecordingExtractor, name="read_blackrock") read_blackrock_sorting = define_function_from_class( From a457b1e09a1e3b7f4b8c74c84edb3d7d2be39989 Mon Sep 17 00:00:00 2001 From: luiz Date: Mon, 14 Apr 2025 14:57:13 +0200 Subject: [PATCH 8/9] docstring --- .../extractors/neoextractors/blackrock.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/blackrock.py b/src/spikeinterface/extractors/neoextractors/blackrock.py index f46eca7790..78547a34a7 100644 --- a/src/spikeinterface/extractors/neoextractors/blackrock.py +++ b/src/spikeinterface/extractors/neoextractors/blackrock.py @@ -76,14 +76,17 @@ class BlackrockSortingExtractor(NeoBaseSortingExtractor): ---------- file_path : str The file path to load the recordings from - sampling_frequency : float, default: None - The sampling frequency for the sorting extractor. When the signal data is available (.ncs) those files will be - used to extract the frequency automatically. Otherwise, the sampling frequency needs to be specified for - this extractor to be initialized stream_id : str, default: None Used to extract information about the sampling frequency and t_start from the analog signal if provided. stream_name : str, default: None Used to extract information about the sampling frequency and t_start from the analog signal if provided. + sampling_frequency : float, default: None + The sampling frequency for the sorting extractor. When the signal data is available (.ncs) those files will be + used to extract the frequency automatically. Otherwise, the sampling frequency needs to be specified for + this extractor to be initialized. + nsx_to_load : int | list | str, default: None + IDs of nsX file from which to load data, e.g., if set to 5 only data from the ns5 file are loaded. + If 'all', then all nsX will be loaded. If None, all nsX files will be loaded. If empty list, no nsX files will be loaded. """ NeoRawIOClass = "BlackrockRawIO" From d8ea01b4c802aee3d228f2a213ccedd58b45cc80 Mon Sep 17 00:00:00 2001 From: Heberto Mayorquin Date: Fri, 18 Apr 2025 09:50:07 -0300 Subject: [PATCH 9/9] Apply suggestions from code review --- src/spikeinterface/extractors/neoextractors/blackrock.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/blackrock.py b/src/spikeinterface/extractors/neoextractors/blackrock.py index 78547a34a7..d21422654b 100644 --- a/src/spikeinterface/extractors/neoextractors/blackrock.py +++ b/src/spikeinterface/extractors/neoextractors/blackrock.py @@ -2,8 +2,7 @@ from pathlib import Path from packaging import version -from typing import Optional, Dict -import numpy as np +from typing import Optional from spikeinterface.core.core_tools import define_function_from_class