From 9d3bd0aa08f727b44c296d365e5520d7c7193d9c Mon Sep 17 00:00:00 2001 From: weiglszonja Date: Mon, 19 Jun 2023 12:15:36 +0200 Subject: [PATCH 1/8] support extracting data from OnePhotonSeries --- .../extractors/nwbextractors/nwbextractors.py | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index 20fb3be6..e3b4fafe 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -1,12 +1,12 @@ from pathlib import Path -from typing import Union, Optional, Iterable +from typing import Union, Optional, Iterable, Literal import numpy as np from lazy_ops import DatasetView try: from pynwb import NWBHDF5IO - from pynwb.ophys import TwoPhotonSeries + from pynwb.ophys import TwoPhotonSeries, OnePhotonSeries HAVE_NWB = True except ImportError: @@ -49,14 +49,14 @@ class NwbImagingExtractor(ImagingExtractor): mode = "file" installation_mesg = "To use the Nwb Extractor run:\n\n pip install pynwb\n\n" # error message when not installed - def __init__(self, file_path: PathType, optical_series_name: Optional[str] = "TwoPhotonSeries"): + def __init__(self, file_path: PathType, optical_series_name: Literal["TwoPhotonSeries", "OnePhotonSeries"] = "TwoPhotonSeries"): """ Parameters ---------- file_path: str The location of the folder containing dataset.nwb file - optical_series_name: str (optional) - optical series to extract data from + optical_series_name: {'TwoPhotonSeries', 'OnePhotonSeries'}, optional + The optical series to extract data from. """ ImagingExtractor.__init__(self) self._path = file_path @@ -73,33 +73,37 @@ def __init__(self, file_path: PathType, optical_series_name: Optional[str] = "Tw raise ValueError("No acquisitions found in the .nwb file.") self._optical_series_name = a_names[0] - self.two_photon_series = self.nwbfile.acquisition[self._optical_series_name] + self.photon_series = self.nwbfile.acquisition[self._optical_series_name] + photon_series = dict( + OnePhotonSeries=OnePhotonSeries, + TwoPhotonSeries=TwoPhotonSeries, + )[self._optical_series_name] assert isinstance( - self.two_photon_series, TwoPhotonSeries - ), "The optical series must be of type pynwb.TwoPhotonSeries" + self.photon_series, photon_series + ), f"The optical series must be of type {photon_series.__name__}" # TODO if external file --> return another proper extractor (e.g. TiffImagingExtractor) - assert self.two_photon_series.external_file is None, "Only 'raw' format is currently supported" + assert self.photon_series.external_file is None, "Only 'raw' format is currently supported" # Load the two video structures that TwoPhotonSeries supports. self._data_has_channels_axis = True - if len(self.two_photon_series.data.shape) == 3: + if len(self.photon_series.data.shape) == 3: self._num_channels = 1 - self._num_frames, self._columns, self._num_rows = self.two_photon_series.data.shape + self._num_frames, self._columns, self._num_rows = self.photon_series.data.shape else: raise_multi_channel_or_depth_not_implemented(extractor_name=self.extractor_name) # Set channel names (This should disambiguate which optical channel) - self._channel_names = [i.name for i in self.two_photon_series.imaging_plane.optical_channel] + self._channel_names = [i.name for i in self.photon_series.imaging_plane.optical_channel] # Set sampling frequency - if hasattr(self.two_photon_series, "timestamps") and self.two_photon_series.timestamps: - self._sampling_frequency = 1.0 / np.median(np.diff(self.two_photon_series.timestamps)) - self._imaging_start_time = self.two_photon_series.timestamps[0] - self.set_times(np.array(self.two_photon_series.timestamps)) + if hasattr(self.photon_series, "timestamps") and self.photon_series.timestamps: + self._sampling_frequency = 1.0 / np.median(np.diff(self.photon_series.timestamps)) + self._imaging_start_time = self.photon_series.timestamps[0] + self.set_times(np.array(self.photon_series.timestamps)) else: - self._sampling_frequency = self.two_photon_series.rate - self._imaging_start_time = self.two_photon_series.fields.get("starting_time", 0.0) + self._sampling_frequency = self.photon_series.rate + self._imaging_start_time = self.photon_series.fields.get("starting_time", 0.0) # Fill epochs dictionary self._epochs = {} @@ -158,7 +162,7 @@ def get_frames(self, frame_idxs: ArrayType, channel: Optional[int] = 0): slice_start = 0 slice_stop = self.get_num_frames() - data = self.two_photon_series.data + data = self.photon_series.data frames = data[slice_start:slice_stop, ...].transpose([0, 2, 1]) if isinstance(frame_idxs, int): @@ -169,7 +173,7 @@ def get_video(self, start_frame=None, end_frame=None, channel: Optional[int] = 0 start_frame = start_frame if start_frame is not None else 0 end_frame = end_frame if end_frame is not None else self.get_num_frames() - video = self.two_photon_series.data + video = self.photon_series.data video = video[start_frame:end_frame].transpose([0, 2, 1]) return video From 5e39c890794933fc389e76b4ed40986672a5026b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 10:17:04 +0000 Subject: [PATCH 2/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/roiextractors/extractors/nwbextractors/nwbextractors.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index e3b4fafe..e0edc921 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -49,7 +49,11 @@ class NwbImagingExtractor(ImagingExtractor): mode = "file" installation_mesg = "To use the Nwb Extractor run:\n\n pip install pynwb\n\n" # error message when not installed - def __init__(self, file_path: PathType, optical_series_name: Literal["TwoPhotonSeries", "OnePhotonSeries"] = "TwoPhotonSeries"): + def __init__( + self, + file_path: PathType, + optical_series_name: Literal["TwoPhotonSeries", "OnePhotonSeries"] = "TwoPhotonSeries", + ): """ Parameters ---------- From f6305ff840d89436b890909280ba750fad32d4fa Mon Sep 17 00:00:00 2001 From: weiglszonja Date: Mon, 19 Jun 2023 18:00:43 +0200 Subject: [PATCH 3/8] refactor --- .../extractors/nwbextractors/nwbextractors.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index e0edc921..24afdcd4 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -78,13 +78,10 @@ def __init__( self._optical_series_name = a_names[0] self.photon_series = self.nwbfile.acquisition[self._optical_series_name] - photon_series = dict( - OnePhotonSeries=OnePhotonSeries, - TwoPhotonSeries=TwoPhotonSeries, - )[self._optical_series_name] - assert isinstance( - self.photon_series, photon_series - ), f"The optical series must be of type {photon_series.__name__}" + valid_photon_series_types = [OnePhotonSeries, TwoPhotonSeries] + assert any( + [isinstance(self.photon_series, photon_series_type) for photon_series_type in valid_photon_series_types] + ), f"The optical series must be of type pynwb.ophys.OnePhotonSeries or pynwb.ophys.TwoPhotonSeries." # TODO if external file --> return another proper extractor (e.g. TiffImagingExtractor) assert self.photon_series.external_file is None, "Only 'raw' format is currently supported" From 613917675ee433d402b63d0f28e70015f92ec1ef Mon Sep 17 00:00:00 2001 From: Szonja Weigl Date: Mon, 19 Jun 2023 18:06:02 +0200 Subject: [PATCH 4/8] Apply suggestions from code review --- src/roiextractors/extractors/nwbextractors/nwbextractors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index 24afdcd4..11f51e60 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -52,15 +52,15 @@ class NwbImagingExtractor(ImagingExtractor): def __init__( self, file_path: PathType, - optical_series_name: Literal["TwoPhotonSeries", "OnePhotonSeries"] = "TwoPhotonSeries", + optical_series_name: Optional[str] = "TwoPhotonSeries" ): """ Parameters ---------- file_path: str The location of the folder containing dataset.nwb file - optical_series_name: {'TwoPhotonSeries', 'OnePhotonSeries'}, optional - The optical series to extract data from. + optical_series_name: str (optional) + The name of the optical series to extract data from. """ ImagingExtractor.__init__(self) self._path = file_path From 7e7f082895e1d07fbd3d51c47a06b776ea8a623d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 16:06:16 +0000 Subject: [PATCH 5/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/roiextractors/extractors/nwbextractors/nwbextractors.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index 11f51e60..e2e83367 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -49,11 +49,7 @@ class NwbImagingExtractor(ImagingExtractor): mode = "file" installation_mesg = "To use the Nwb Extractor run:\n\n pip install pynwb\n\n" # error message when not installed - def __init__( - self, - file_path: PathType, - optical_series_name: Optional[str] = "TwoPhotonSeries" - ): + def __init__(self, file_path: PathType, optical_series_name: Optional[str] = "TwoPhotonSeries"): """ Parameters ---------- From 130a471b3255f7a7ff051d23b84d59d0831e0ab0 Mon Sep 17 00:00:00 2001 From: weiglszonja Date: Mon, 19 Jun 2023 18:07:29 +0200 Subject: [PATCH 6/8] refactor --- src/roiextractors/extractors/nwbextractors/nwbextractors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index e2e83367..694ee757 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -77,7 +77,7 @@ def __init__(self, file_path: PathType, optical_series_name: Optional[str] = "Tw valid_photon_series_types = [OnePhotonSeries, TwoPhotonSeries] assert any( [isinstance(self.photon_series, photon_series_type) for photon_series_type in valid_photon_series_types] - ), f"The optical series must be of type pynwb.ophys.OnePhotonSeries or pynwb.ophys.TwoPhotonSeries." + ), "The optical series must be of type pynwb.ophys.OnePhotonSeries or pynwb.ophys.TwoPhotonSeries." # TODO if external file --> return another proper extractor (e.g. TiffImagingExtractor) assert self.photon_series.external_file is None, "Only 'raw' format is currently supported" From 9a8ebe2a0b99bf54e7a7a3e9d7ef4d8c4a33b7fe Mon Sep 17 00:00:00 2001 From: weiglszonja Date: Mon, 19 Jun 2023 18:08:27 +0200 Subject: [PATCH 7/8] refactor --- src/roiextractors/extractors/nwbextractors/nwbextractors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index 694ee757..b5c4f98f 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Union, Optional, Iterable, Literal +from typing import Union, Optional, Iterable import numpy as np from lazy_ops import DatasetView From 438d0224b50ee825f24e8c72c294e7b273e36834 Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Wed, 21 Jun 2023 10:36:03 -0400 Subject: [PATCH 8/8] Update src/roiextractors/extractors/nwbextractors/nwbextractors.py --- src/roiextractors/extractors/nwbextractors/nwbextractors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roiextractors/extractors/nwbextractors/nwbextractors.py b/src/roiextractors/extractors/nwbextractors/nwbextractors.py index b5c4f98f..00c0d5f1 100644 --- a/src/roiextractors/extractors/nwbextractors/nwbextractors.py +++ b/src/roiextractors/extractors/nwbextractors/nwbextractors.py @@ -55,7 +55,7 @@ def __init__(self, file_path: PathType, optical_series_name: Optional[str] = "Tw ---------- file_path: str The location of the folder containing dataset.nwb file - optical_series_name: str (optional) + optical_series_name: string, optional The name of the optical series to extract data from. """ ImagingExtractor.__init__(self)