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..5608174b7 --- /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 = 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 + >>> nwbfile_path = f"{path_to_save_nwbfile}" + >>> interface.run_conversion(nwbfile_path=nwbfile_path, metadata=metadata) 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..bfead3f11 --- /dev/null +++ b/src/neuroconv/datainterfaces/ophys/inscopix/inscopiximaginginterface.py @@ -0,0 +1,47 @@ +from datetime import datetime +from imaplib import Literal + +from ..baseimagingextractorinterface import BaseImagingExtractorInterface +from ....utils import DeepDict, FilePathType + + +class InscopixImagingInterface(BaseImagingExtractorInterface): + """Interface for Inscopix imaging data.""" + + display_name = "Inscopix Imaging" + associated_suffixes = (".isxd",) + info = "Interface for Inscopix imaging data." + + def __init__(self, file_path: FilePathType, verbose: bool = True): + """ + + Parameters + ---------- + file_path : FilePathType + Path to .isxd file. + 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 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/tests/test_on_data/test_imaging_interfaces.py b/tests/test_on_data/test_imaging_interfaces.py index 088d42719..aa83e3425 100644 --- a/tests/test_on_data/test_imaging_interfaces.py +++ b/tests/test_on_data/test_imaging_interfaces.py @@ -14,6 +14,7 @@ BrukerTiffMultiPlaneImagingInterface, BrukerTiffSinglePlaneImagingInterface, Hdf5ImagingInterface, + InscopixImagingInterface, MicroManagerTiffImagingInterface, MiniscopeImagingInterface, SbxImagingInterface, @@ -805,3 +806,11 @@ 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