From 2b7adc7db9c30bcbc42d2033904189ea0f6e777d Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 13 May 2024 01:49:15 -0500 Subject: [PATCH 1/8] add inscopix imaging extractor and test --- src/neuroconv/datainterfaces/__init__.py | 2 ++ .../datainterfaces/ophys/inscopix/__init__.py | 0 .../inscopix/inscopiximaginginterface.py | 21 +++++++++++++++++++ .../datainterfaces/ophys/requirements.txt | 2 +- .../imagingextractordatachunkiterator.py | 2 ++ tests/test_on_data/test_imaging_interfaces.py | 7 +++++++ 6 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/neuroconv/datainterfaces/ophys/inscopix/__init__.py create mode 100644 src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py diff --git a/src/neuroconv/datainterfaces/__init__.py b/src/neuroconv/datainterfaces/__init__.py index fa27e7763..83e0a2c6a 100644 --- a/src/neuroconv/datainterfaces/__init__.py +++ b/src/neuroconv/datainterfaces/__init__.py @@ -76,6 +76,7 @@ from .ophys.cnmfe.cnmfedatainterface import CnmfeSegmentationInterface from .ophys.extract.extractdatainterface import ExtractSegmentationInterface from .ophys.hdf5.hdf5datainterface import Hdf5ImagingInterface +from .ophys.inscopix.inscopiximaginginterface import InscopixImagingInterface from .ophys.micromanagertiff.micromanagertiffdatainterface import ( MicroManagerTiffImagingInterface, ) @@ -146,6 +147,7 @@ BrukerTiffSinglePlaneImagingInterface, MicroManagerTiffImagingInterface, MiniscopeImagingInterface, + InscopixImagingInterface, # Behavior VideoInterface, AudioInterface, diff --git a/src/neuroconv/datainterfaces/ophys/inscopix/__init__.py b/src/neuroconv/datainterfaces/ophys/inscopix/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py new file mode 100644 index 000000000..81d3edb51 --- /dev/null +++ b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py @@ -0,0 +1,21 @@ +from ..baseimagingextractorinterface import BaseImagingExtractorInterface +from ....utils import FilePathType + + +class InscopixImagingInterface(BaseImagingExtractorInterface): + """Interface for Inscopix imaging data.""" + + display_name = "HDF5 Imaging" + associated_suffixes = (".isxd",) + info = "Interface for HDF5 imaging data." + + def __init__(self, file_path: FilePathType, verbose: bool = True): + """ + + Parameters + ---------- + file_path : FilePathType + Path to .h5 or .hdf5 file. + verbose : bool, default: True + """ + super().__init__(file_path=file_path, verbose=verbose) diff --git a/src/neuroconv/datainterfaces/ophys/requirements.txt b/src/neuroconv/datainterfaces/ophys/requirements.txt index 1aac92108..026a517a7 100644 --- a/src/neuroconv/datainterfaces/ophys/requirements.txt +++ b/src/neuroconv/datainterfaces/ophys/requirements.txt @@ -1 +1 @@ -roiextractors>=0.5.7 +roiextractors>=0.6.0 diff --git a/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py b/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py index dee5c6de0..518b892ad 100644 --- a/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py +++ b/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py @@ -91,6 +91,8 @@ def _get_default_chunk_shape(self, chunk_mb: float) -> tuple: width = self._maxshape[1] height = self._maxshape[2] + print(f"{self._dtype=}") + frame_size_bytes = width * height * self._dtype.itemsize chunk_size_bytes = chunk_mb * 1e6 num_frames_per_chunk = int(chunk_size_bytes / frame_size_bytes) diff --git a/tests/test_on_data/test_imaging_interfaces.py b/tests/test_on_data/test_imaging_interfaces.py index 088d42719..f6d03dd98 100644 --- a/tests/test_on_data/test_imaging_interfaces.py +++ b/tests/test_on_data/test_imaging_interfaces.py @@ -20,6 +20,7 @@ ScanImageImagingInterface, ScanImageMultiFileImagingInterface, TiffImagingInterface, + InscopixImagingInterface, ) from neuroconv.datainterfaces.ophys.scanimage.scanimageimaginginterfaces import ( ScanImageMultiPlaneImagingInterface, @@ -805,3 +806,9 @@ def check_incorrect_folder_structure_raises(self): exc_type=AssertionError, exc_msg="The main folder should contain at least one subfolder named 'Miniscope'." ): self.data_interface_cls(folder_path=folder_path) + + +class TestInscopixImagingInterface(ImagingExtractorInterfaceTestMixin, TestCase): + data_interface_cls = InscopixImagingInterface + interface_kwargs = dict(file_path=str(OPHYS_DATA_PATH / "imaging_datasets" / "inscopix" / "movie_longer_than_3_min.isxd")) + save_directory = OUTPUT_PATH From 23bbcee212c052bf42c753d31121edaddca54407 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 06:50:03 +0000 Subject: [PATCH 2/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_on_data/test_imaging_interfaces.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_on_data/test_imaging_interfaces.py b/tests/test_on_data/test_imaging_interfaces.py index f6d03dd98..aa83e3425 100644 --- a/tests/test_on_data/test_imaging_interfaces.py +++ b/tests/test_on_data/test_imaging_interfaces.py @@ -14,13 +14,13 @@ BrukerTiffMultiPlaneImagingInterface, BrukerTiffSinglePlaneImagingInterface, Hdf5ImagingInterface, + InscopixImagingInterface, MicroManagerTiffImagingInterface, MiniscopeImagingInterface, SbxImagingInterface, ScanImageImagingInterface, ScanImageMultiFileImagingInterface, TiffImagingInterface, - InscopixImagingInterface, ) from neuroconv.datainterfaces.ophys.scanimage.scanimageimaginginterfaces import ( ScanImageMultiPlaneImagingInterface, @@ -810,5 +810,7 @@ def check_incorrect_folder_structure_raises(self): class TestInscopixImagingInterface(ImagingExtractorInterfaceTestMixin, TestCase): data_interface_cls = InscopixImagingInterface - interface_kwargs = dict(file_path=str(OPHYS_DATA_PATH / "imaging_datasets" / "inscopix" / "movie_longer_than_3_min.isxd")) + interface_kwargs = dict( + file_path=str(OPHYS_DATA_PATH / "imaging_datasets" / "inscopix" / "movie_longer_than_3_min.isxd") + ) save_directory = OUTPUT_PATH From 0f204c4b61525dad70985645af4da85571ea20b6 Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 13 May 2024 02:50:26 -0400 Subject: [PATCH 3/8] Update src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py --- .../tools/roiextractors/imagingextractordatachunkiterator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py b/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py index 518b892ad..dee5c6de0 100644 --- a/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py +++ b/src/neuroconv/tools/roiextractors/imagingextractordatachunkiterator.py @@ -91,8 +91,6 @@ def _get_default_chunk_shape(self, chunk_mb: float) -> tuple: width = self._maxshape[1] height = self._maxshape[2] - print(f"{self._dtype=}") - frame_size_bytes = width * height * self._dtype.itemsize chunk_size_bytes = chunk_mb * 1e6 num_frames_per_chunk = int(chunk_size_bytes / frame_size_bytes) From 4513809939c634ade4f351e724b9bb42e0337d3e Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 13 May 2024 10:23:09 -0400 Subject: [PATCH 4/8] Update src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> --- .../datainterfaces/ophys/inscopix/inscopiximaginginterface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py index 81d3edb51..40932703e 100644 --- a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py +++ b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py @@ -5,9 +5,9 @@ class InscopixImagingInterface(BaseImagingExtractorInterface): """Interface for Inscopix imaging data.""" - display_name = "HDF5 Imaging" + display_name = "Inscopix Imaging" associated_suffixes = (".isxd",) - info = "Interface for HDF5 imaging data." + info = "Interface for Inscopix imaging data." def __init__(self, file_path: FilePathType, verbose: bool = True): """ From 3bd0c43acd636fdab53b06eb4c5e83f31732a788 Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 13 May 2024 13:28:21 -0500 Subject: [PATCH 5/8] add docs for inscopix --- docs/api/interfaces.ophys.rst | 4 +++ .../conversion_example_gallery.rst | 1 + .../imaging/inscopix.rst | 29 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 docs/conversion_examples_gallery/imaging/inscopix.rst diff --git a/docs/api/interfaces.ophys.rst b/docs/api/interfaces.ophys.rst index ee33a9668..30386cd19 100644 --- a/docs/api/interfaces.ophys.rst +++ b/docs/api/interfaces.ophys.rst @@ -13,6 +13,10 @@ HDF5 Imaging ------------ .. automodule:: neuroconv.datainterfaces.ophys.hdf5.hdf5datainterface +Inscopix Imaging +---------------- +.. automodule:: neuroconv.datainterfaces.ophys.inscopix.inscopiximaginginterface + MicroManager Tiff Imaging ------------------------- .. automodule:: neuroconv.datainterfaces.ophys.micromanagertiff.micromanagertiffdatainterface diff --git a/docs/conversion_examples_gallery/conversion_example_gallery.rst b/docs/conversion_examples_gallery/conversion_example_gallery.rst index 877a07ac2..ba6915816 100644 --- a/docs/conversion_examples_gallery/conversion_example_gallery.rst +++ b/docs/conversion_examples_gallery/conversion_example_gallery.rst @@ -66,6 +66,7 @@ Imaging Bruker HDF5 + Inscopix Micro-Manager Miniscope Scanbox diff --git a/docs/conversion_examples_gallery/imaging/inscopix.rst b/docs/conversion_examples_gallery/imaging/inscopix.rst new file mode 100644 index 000000000..112840023 --- /dev/null +++ b/docs/conversion_examples_gallery/imaging/inscopix.rst @@ -0,0 +1,29 @@ +Inscopix data conversion +------------------------ + +Install NeuroConv with the additional dependencies necessary for reading Inscopix imaging data form .isxd files. + +.. code-block:: bash + + pip install neuroconv[inscopix] + +Convert Inscopix .isxd imaging data to NWB using :py:class:`~neuroconv.datainterfaces.ophys.inscopix.inscopiximaginginterface.InscopixImagingInterface`. + +.. code-block:: python + + >>> from datetime import datetime + >>> from dateutil import tz + >>> from pathlib import Path + >>> from neuroconv.datainterfaces import InscopixImagingInterface + >>> + >>> file_path = OPHYS_DATA_PATH / "imaging_datasets" / "inscopix" / "movie_longer_than_3_min.isxd" + >>> interface = InscopixImagingInterface(file_path=file_path, verbose=False) + >>> + >>> metadata = interface.get_metadata() + >>> # For data provenance we add the time zone information to the conversion + >>> session_start_time = datetime(2020, 1, 1, 12, 30, 0, tzinfo=tz.gettz("US/Pacific")) + >>> metadata["NWBFile"].update(session_start_time=session_start_time) + >>> + >>> # Choose a path for saving the nwb file and run the conversion + >>> nwbfile_path = f"{path_to_save_nwbfile}" + >>> interface.run_conversion(nwbfile_path=nwbfile_path, metadata=metadata) From 6317efe2561c5ef8a420137ca0d3b25420623176 Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 13 May 2024 14:00:23 -0500 Subject: [PATCH 6/8] extract metadata from inscopix --- .../imaging/inscopix.rst | 2 +- .../inscopix/inscopiximaginginterface.py | 28 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/conversion_examples_gallery/imaging/inscopix.rst b/docs/conversion_examples_gallery/imaging/inscopix.rst index 112840023..5608174b7 100644 --- a/docs/conversion_examples_gallery/imaging/inscopix.rst +++ b/docs/conversion_examples_gallery/imaging/inscopix.rst @@ -21,7 +21,7 @@ Convert Inscopix .isxd imaging data to NWB using :py:class:`~neuroconv.datainter >>> >>> metadata = interface.get_metadata() >>> # For data provenance we add the time zone information to the conversion - >>> session_start_time = datetime(2020, 1, 1, 12, 30, 0, tzinfo=tz.gettz("US/Pacific")) + >>> session_start_time = metadata["NWBFile"]["session_start_time"] >>> metadata["NWBFile"].update(session_start_time=session_start_time) >>> >>> # Choose a path for saving the nwb file and run the conversion diff --git a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py index 40932703e..5e40a60ab 100644 --- a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py +++ b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py @@ -1,5 +1,8 @@ +from datetime import datetime +from imaplib import Literal + from ..baseimagingextractorinterface import BaseImagingExtractorInterface -from ....utils import FilePathType +from ....utils import FilePathType, DeepDict class InscopixImagingInterface(BaseImagingExtractorInterface): @@ -19,3 +22,26 @@ def __init__(self, file_path: FilePathType, verbose: bool = True): verbose : bool, default: True """ super().__init__(file_path=file_path, verbose=verbose) + + def get_metadata( + self, photon_series_type: Literal["OnePhotonSeries", "TwoPhotonSeries"] = "TwoPhotonSeries" + ) -> DeepDict: + metadata = super().get_metadata(photon_series_type=photon_series_type) + + extra_props = self.imaging_extractor.movie.footer['extraProperties'] + + if extra_props['animal']['id']: + metadata["Subject"]["subject_id"] = extra_props['animal']['id'] + if extra_props['animal']['species']: + metadata["Subject"]["species"] = extra_props['animal']['species'] + if extra_props["animal"]["sex"]: + metadata["Subject"]["sex"] = extra_props["animal"]["sex"].upper() + if extra_props["animal"]["dob"]: + metadata["Subject"]["date_of_birth"] = extra_props["animal"]["dob"] + if extra_props["animal"]["weight"]: + metadata["Subject"]["weight"] = str(extra_props["animal"]["weight"]) + + if extra_props["date"]: + metadata["NWBFile"]["session_start_time"] = datetime.strptime(extra_props["date"], '%Y-%m-%dT%H:%M:%S.%fZ') + + return metadata \ No newline at end of file From 54b38eb7cf5d3aa6437e32020f9d7c5cda62114e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 19:00:38 +0000 Subject: [PATCH 7/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../ophys/inscopix/inscopiximaginginterface.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py index 5e40a60ab..a2681c788 100644 --- a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py +++ b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py @@ -2,7 +2,7 @@ from imaplib import Literal from ..baseimagingextractorinterface import BaseImagingExtractorInterface -from ....utils import FilePathType, DeepDict +from ....utils import DeepDict, FilePathType class InscopixImagingInterface(BaseImagingExtractorInterface): @@ -28,12 +28,12 @@ def get_metadata( ) -> DeepDict: metadata = super().get_metadata(photon_series_type=photon_series_type) - extra_props = self.imaging_extractor.movie.footer['extraProperties'] + extra_props = self.imaging_extractor.movie.footer["extraProperties"] - if extra_props['animal']['id']: - metadata["Subject"]["subject_id"] = extra_props['animal']['id'] - if extra_props['animal']['species']: - metadata["Subject"]["species"] = extra_props['animal']['species'] + if extra_props["animal"]["id"]: + metadata["Subject"]["subject_id"] = extra_props["animal"]["id"] + if extra_props["animal"]["species"]: + metadata["Subject"]["species"] = extra_props["animal"]["species"] if extra_props["animal"]["sex"]: metadata["Subject"]["sex"] = extra_props["animal"]["sex"].upper() if extra_props["animal"]["dob"]: @@ -42,6 +42,6 @@ def get_metadata( metadata["Subject"]["weight"] = str(extra_props["animal"]["weight"]) if extra_props["date"]: - metadata["NWBFile"]["session_start_time"] = datetime.strptime(extra_props["date"], '%Y-%m-%dT%H:%M:%S.%fZ') + metadata["NWBFile"]["session_start_time"] = datetime.strptime(extra_props["date"], "%Y-%m-%dT%H:%M:%S.%fZ") - return metadata \ No newline at end of file + return metadata From 31f5ac5b45673ffd65a9c868ab167c279dfa4cd2 Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 13 May 2024 15:27:28 -0400 Subject: [PATCH 8/8] Update src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py --- .../datainterfaces/ophys/inscopix/inscopiximaginginterface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py index a2681c788..bfead3f11 100644 --- a/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py +++ b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py @@ -18,7 +18,7 @@ def __init__(self, file_path: FilePathType, verbose: bool = True): Parameters ---------- file_path : FilePathType - Path to .h5 or .hdf5 file. + Path to .isxd file. verbose : bool, default: True """ super().__init__(file_path=file_path, verbose=verbose)