From e5c3892a8f8c0abb9b07338c5ef0980b2602504b Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Mon, 15 Jul 2024 15:27:17 -0400 Subject: [PATCH 1/4] [Enhancement I] Add multichannel volume (#13) * add multichannel volume * swap to datainterface * fix import * fix test name * fix intercompatability * fix light sources * fix * ryans suggestion * adjust to use full list * adjust constructor test * reorder kwargs in mock * adjust kwargs order in mock * Implement lists of object references with tests * Adjust constructor test to match * fix outer spec to match altered one * Apply suggestions from code review Co-authored-by: Ryan Ly * fix outer spec to match altered one (#20) Co-authored-by: CodyCBakerPhD --------- Co-authored-by: CodyCBakerPhD Co-authored-by: Ryan Ly --- spec/ndx-microscopy.extensions.yaml | 80 +++++++++++++++++++- src/pynwb/ndx_microscopy/__init__.py | 2 + src/pynwb/ndx_microscopy/testing/__init__.py | 2 + src/pynwb/ndx_microscopy/testing/_mock.py | 34 ++++++++- src/pynwb/tests/test_constructors.py | 27 +++++++ src/pynwb/tests/test_roundtrip.py | 80 +++++++++++++++++++- 6 files changed, 219 insertions(+), 6 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 3e53d9c..f908396 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -247,7 +247,7 @@ groups: - frames - height - width - - depth + - depths shape: - null - null @@ -258,3 +258,81 @@ groups: doc: Link to VolumetricImagingSpace object containing metadata about the region of physical space this imaging data was recorded from. target_type: VolumetricImagingSpace + + - neurodata_type_def: MultiChannelMicroscopyVolume + neurodata_type_inc: NWBDataInterface + doc: Static (not time-varying) volumetric imaging data acquired from multiple optical channels. + attributes: + - name: description + dtype: text + doc: Description of the MultiChannelVolume. + required: false + - name: unit + dtype: text + doc: Base unit of measurement for working with the data. Actual stored values are + not necessarily stored in these units. To access the data in these units, + multiply 'data' by 'conversion' and add 'offset'. + - name: conversion + dtype: float32 + default_value: 1.0 + doc: Scalar to multiply each element in data to convert it to the specified 'unit'. + If the data are stored in acquisition system units or other units + that require a conversion to be interpretable, multiply the data by 'conversion' + to convert the data to the specified 'unit'. e.g. if the data acquisition system + stores values in this object as signed 16-bit integers (int16 range + -32,768 to 32,767) that correspond to a 5V range (-2.5V to 2.5V), and the data + acquisition system gain is 8000X, then the 'conversion' multiplier to get from + raw data acquisition values to recorded volts is 2.5/32768/8000 = 9.5367e-9. + required: false + - name: offset + dtype: float32 + default_value: 0.0 + doc: Scalar to add to the data after scaling by 'conversion' to finalize its coercion + to the specified 'unit'. Two common examples of this include (a) data stored in an + unsigned type that requires a shift after scaling to re-center the data, + and (b) specialized recording devices that naturally cause a scalar offset with + respect to the true units. + required: false + datasets: + - name: data + doc: Recorded imaging data, shaped by (frame height, frame width, number of depth planes, number of optical + channels). + dtype: numeric + dims: + - height + - width + - depths + - optical_channels + shape: + - null + - null + - null + - null + - name: light_sources + doc: An ordered list of references to MicroscopyLightSource objects containing metadata about the excitation methods. + neurodata_type_inc: VectorData + dtype: + reftype: object + target_type: MicroscopyLightSource + dims: + - light_sources + shape: + - null + - name: optical_channels + doc: An ordered list of references to MicroscopyOpticalChannel objects containing metadata about the indicator and filters used to collect this data. This maps to the last dimension of `data`, i.e., the i-th MicroscopyOpticalChannel contains metadata about the indicator and filters used to collect the volume at `data[:,:,:,i]`. + neurodata_type_inc: VectorData + dtype: + reftype: object + target_type: MicroscopyOpticalChannel + dims: + - optical_channels + shape: + - null + links: + - name: microscope + doc: Link to a Microscope object containing metadata about the device used to acquire this imaging data. + target_type: Microscope + - name: imaging_space + doc: Link to VolumetricImagingSpace object containing metadata about the region of physical space this imaging data + was recorded from. + target_type: VolumetricImagingSpace diff --git a/src/pynwb/ndx_microscopy/__init__.py b/src/pynwb/ndx_microscopy/__init__.py index 98ecc79..722b281 100644 --- a/src/pynwb/ndx_microscopy/__init__.py +++ b/src/pynwb/ndx_microscopy/__init__.py @@ -30,6 +30,7 @@ PlanarMicroscopySeries = get_class("PlanarMicroscopySeries", extension_name) VariableDepthMicroscopySeries = get_class("VariableDepthMicroscopySeries", extension_name) VolumetricMicroscopySeries = get_class("VolumetricMicroscopySeries", extension_name) +MultiChannelMicroscopyVolume = get_class("MultiChannelMicroscopyVolume", extension_name) __all__ = [ "Microscope", @@ -42,4 +43,5 @@ "PlanarMicroscopySeries", "VariableDepthMicroscopySeries", "VolumetricMicroscopySeries", + "MultiChannelMicroscopyVolume", ] diff --git a/src/pynwb/ndx_microscopy/testing/__init__.py b/src/pynwb/ndx_microscopy/testing/__init__.py index 213dea7..b305dac 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -2,6 +2,7 @@ mock_Microscope, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, + mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, @@ -18,4 +19,5 @@ "mock_PlanarMicroscopySeries", "mock_VariableDepthMicroscopySeries", "mock_VolumetricMicroscopySeries", + "mock_MultiChannelMicroscopyVolume", ] diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 4fff56f..7024cdb 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -1,7 +1,8 @@ import warnings -from typing import Optional, Tuple +from typing import List, Optional, Tuple import numpy as np +import pynwb.base from pynwb.testing.mock.utils import name_generator import ndx_microscopy @@ -286,3 +287,34 @@ def mock_VolumetricMicroscopySeries( timestamps=series_timestamps, ) return volumetric_microscopy_series + + +def mock_MultiChannelMicroscopyVolume( + *, + microscope: ndx_microscopy.Microscope, + imaging_space: ndx_microscopy.VolumetricImagingSpace, + light_sources: pynwb.base.VectorData, + optical_channels: pynwb.base.VectorData, + name: Optional[str] = None, + description: str = "This is a mock instance of a MultiChannelMicroscopyVolume type to be used for rapid testing.", + data: Optional[np.ndarray] = None, + unit: str = "n.a.", + conversion: float = 1.0, + offset: float = 0.0, +) -> ndx_microscopy.MultiChannelMicroscopyVolume: + series_name = name or name_generator("MultiChannelMicroscopyVolume") + imaging_data = data if data is not None else np.ones(shape=(10, 20, 7, 3)) + + volumetric_microscopy_series = ndx_microscopy.MultiChannelMicroscopyVolume( + name=series_name, + description=description, + microscope=microscope, + imaging_space=imaging_space, + light_sources=light_sources, + optical_channels=optical_channels, + data=imaging_data, + unit=unit, + conversion=conversion, + offset=offset, + ) + return volumetric_microscopy_series diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 10a6cf8..7585c1d 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -2,10 +2,12 @@ import pytest +import pynwb from ndx_microscopy.testing import ( mock_Microscope, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, + mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, @@ -71,5 +73,30 @@ def test_constructor_volumetric_microscopy_series(): ) +def test_constructor_multi_channel_microscopy_volume(): + microscope = mock_Microscope() + imaging_space = mock_VolumetricImagingSpace(microscope=microscope) + light_sources = [mock_MicroscopyLightSource()] + optical_channels = [mock_MicroscopyOpticalChannel()] + + light_sources_used_by_volume = pynwb.base.VectorData( + name="light_sources", description="Light sources used by this MultiChannelVolume.", data=light_sources + ) + optical_channels_used_by_volume = pynwb.base.VectorData( + name="optical_channels", + description=( + "Optical channels ordered to correspond to the third axis (e.g., [0, 0, :, 0]) " + "of the data for this MultiChannelVolume." + ), + data=optical_channels, + ) + mock_MultiChannelMicroscopyVolume( + microscope=microscope, + imaging_space=imaging_space, + light_sources=light_sources_used_by_volume, + optical_channels=optical_channels_used_by_volume, + ) + + if __name__ == "__main__": pytest.main() # Required since not a typical package structure diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 899c15c..530a703 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -8,6 +8,7 @@ mock_Microscope, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, + mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, @@ -20,7 +21,7 @@ class TestPlanarMicroscopySeriesSimpleRoundtrip(pynwb_TestCase): """Simple roundtrip test for PlanarMicroscopySeries.""" def setUp(self): - self.nwbfile_path = "test.nwb" + self.nwbfile_path = "test_planar_microscopy_series_roundtrip.nwb" def tearDown(self): pynwb.testing.remove_test_file(self.nwbfile_path) @@ -68,7 +69,7 @@ class TestVolumetricMicroscopySeriesSimpleRoundtrip(pynwb_TestCase): """Simple roundtrip test for VolumetricMicroscopySeries.""" def setUp(self): - self.nwbfile_path = "test.nwb" + self.nwbfile_path = "test_volumetric_microscopy_series_roundtrip.nwb" def tearDown(self): pynwb.testing.remove_test_file(self.nwbfile_path) @@ -118,7 +119,7 @@ class TestVariableDepthMicroscopySeriesSimpleRoundtrip(pynwb_TestCase): """Simple roundtrip test for VariableDepthMicroscopySeries.""" def setUp(self): - self.nwbfile_path = "test.nwb" + self.nwbfile_path = "test_variable_depth_microscopy_series_roundtrip.nwb" def tearDown(self): pynwb.testing.remove_test_file(self.nwbfile_path) @@ -133,7 +134,7 @@ def test_roundtrip(self): nwbfile.add_device(devices=light_source) imaging_space = mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) - nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_spacec() + nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() optical_channel = mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") nwbfile.add_lab_meta_data(lab_meta_data=optical_channel) @@ -162,3 +163,74 @@ def test_roundtrip(self): self.assertContainerEqual( variable_depth_microscopy_series, read_nwbfile.acquisition["VariableDepthMicroscopySeries"] ) + + +class TestMultiChannelMicroscopyVolumeSimpleRoundtrip(pynwb_TestCase): + """Simple roundtrip test for MultiChannelMicroscopyVolume.""" + + def setUp(self): + self.nwbfile_path = "test_multi_channel_microscopy_volume_roundtrip.nwb" + + def tearDown(self): + pynwb.testing.remove_test_file(self.nwbfile_path) + + def test_roundtrip(self): + nwbfile = mock_NWBFile() + + microscope = mock_Microscope(name="Microscope") + nwbfile.add_device(devices=microscope) + + imaging_space = mock_VolumetricImagingSpace(name="VolumetricImagingSpace", microscope=microscope) + nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() + + light_sources = list() + light_source_0 = mock_MicroscopyLightSource(name="LightSource") + nwbfile.add_device(devices=light_source_0) + light_sources.append(light_source_0) + + optical_channels = list() + optical_channel_0 = mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") + nwbfile.add_lab_meta_data(lab_meta_data=optical_channel_0) + optical_channels.append(optical_channel_0) + + # TODO: It might be more convenient in Python to have a custom constructor that takes in a list of + # light sources and optical channels and does the VectorData wrapping internally + light_sources_used_by_volume = pynwb.base.VectorData( + name="light_sources", description="Light sources used by this MultiChannelVolume.", data=light_sources + ) + optical_channels_used_by_volume = pynwb.base.VectorData( + name="optical_channels", + description=( + "Optical channels ordered to correspond to the third axis (e.g., [0, 0, :, 0]) " + "of the data for this MultiChannelVolume." + ), + data=optical_channels, + ) + multi_channel_microscopy_volume = mock_MultiChannelMicroscopyVolume( + name="MultiChannelMicroscopyVolume", + microscope=microscope, + imaging_space=imaging_space, + light_sources=light_sources_used_by_volume, + optical_channels=optical_channels_used_by_volume, + ) + nwbfile.add_acquisition(nwbdata=multi_channel_microscopy_volume) + + with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="w") as io: + io.write(nwbfile) + + with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="r", load_namespaces=True) as io: + read_nwbfile = io.read() + + self.assertContainerEqual(microscope, read_nwbfile.devices["Microscope"]) + self.assertContainerEqual(light_source_0, read_nwbfile.devices["LightSource"]) + + self.assertContainerEqual(imaging_space, read_nwbfile.lab_meta_data["VolumetricImagingSpace"]) + self.assertContainerEqual(optical_channel_0, read_nwbfile.lab_meta_data["MicroscopyOpticalChannel"]) + + self.assertContainerEqual( + multi_channel_microscopy_volume, read_nwbfile.acquisition["MultiChannelMicroscopyVolume"] + ) + + +if __name__ == "__main__": + pytest.main() # Required since not a typical package structure From bb380a48a58734e45dd96e24269e8f0d5e8f2197 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 19:03:52 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pynwb/tests/test_constructors.py | 2 +- src/pynwb/tests/test_roundtrip.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 2c8fc3a..7903230 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -4,13 +4,13 @@ import pynwb from ndx_microscopy.testing import ( + mock_LightSource, mock_Microscope, mock_MicroscopyImageSegmentation, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, mock_MicroscopyPlaneSegmentation, mock_MultiChannelMicroscopyVolume, - mock_LightSource, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index eb33e02..255df6c 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -1,10 +1,10 @@ """Test roundtrip (write and read back) of the Python API for the ndx-microscopy extension.""" -import pynwb import pytest from pynwb.testing import TestCase as pynwb_TestCase from pynwb.testing.mock.file import mock_NWBFile +import pynwb from ndx_microscopy.testing import ( mock_Microscope, mock_MicroscopyLightSource, From 94ee2286723c422aa2b97da07b452757250045f2 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:22:53 -0400 Subject: [PATCH 3/4] alessandras comments and tests --- spec/ndx-microscopy.extensions.yaml | 13 +++---- src/pynwb/ndx_microscopy/__init__.py | 4 +- src/pynwb/ndx_microscopy/testing/_mock.py | 13 ++++--- src/pynwb/tests/test_constructors.py | 8 ++-- src/pynwb/tests/test_roundtrip.py | 45 ++++++++++++++++++++++- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 0382803..2fc474b 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -170,9 +170,9 @@ groups: # These are needed to allow linkage of processed data to the new objects, until this is merged to core # Technically the RoiResponseSeries shouldn't need to be modified since it just takes a DynamicTableRegion and # does not care about the target - - neurodata_type_def: MicroscopyImageSegmentation + - neurodata_type_def: MicroscopySegmentations neurodata_type_inc: NWBDataInterface - default_name: MicroscopyImageSegmentation + default_name: MicroscopySegmentations doc: Stores pixels in an image that represent different regions of interest (ROIs) or masks. All segmentation for a given imaging plane is stored together, with storage for multiple imaging planes (masks) supported. Each ROI is stored in its @@ -253,12 +253,11 @@ groups: masks are concatenated and parsing of this dataset is maintained by the PlaneSegmentation' quantity: '?' groups: - - name: reference_images - doc: Image stacks that the segmentation masks apply to. + - name: summary_images + doc: Summary images that are related to the plane segmentation, e.g., mean, correlation, maximum projection. groups: - - neurodata_type_inc: ImageSeries - doc: One or more image stacks that the masks apply to (can be one-element - stack). + - neurodata_type_inc: Images + doc: An container for the estimated summary images. quantity: '*' links: - name: imaging_space diff --git a/src/pynwb/ndx_microscopy/__init__.py b/src/pynwb/ndx_microscopy/__init__.py index abc6b72..8dfeac9 100644 --- a/src/pynwb/ndx_microscopy/__init__.py +++ b/src/pynwb/ndx_microscopy/__init__.py @@ -26,7 +26,7 @@ ImagingSpace = get_class("ImagingSpace", extension_name) PlanarImagingSpace = get_class("PlanarImagingSpace", extension_name) VolumetricImagingSpace = get_class("VolumetricImagingSpace", extension_name) -MicroscopyImageSegmentation = get_class("MicroscopyImageSegmentation", extension_name) +MicroscopySegmentations = get_class("MicroscopySegmentations", extension_name) MicroscopyPlaneSegmentation = get_class("MicroscopyPlaneSegmentation", extension_name) MicroscopySeries = get_class("MicroscopySeries", extension_name) PlanarMicroscopySeries = get_class("PlanarMicroscopySeries", extension_name) @@ -42,7 +42,7 @@ "ImagingSpace", "PlanarImagingSpace", "VolumetricImagingSpace", - "MicroscopyImageSegmentation", + "MicroscopySegmentations", "MicroscopyPlaneSegmentation", "MicroscopySeries", "PlanarMicroscopySeries", diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 8f16678..5ab81cc 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -116,21 +116,22 @@ def mock_VolumetricImagingSpace( return volumetric_imaging_space -def mock_MicroscopyImageSegmentation( - name: Optional[str] = None, microscopy_plane_segmentations: Optional[Iterable[PlaneSegmentation]] = None +def mock_MicroscopySegmentations( + name: Optional[str] = None, + microscopy_plane_segmentations: Optional[Iterable[ndx_microscopy.PlaneSegmentation]] = None, ) -> ndx_microscopy.MicroscopyImageSegmentation: - name = name or name_generator("MicroscopyImageSegmentation") + name = name or name_generator("MicroscopySegmentations") microscopy_plane_segmentations = microscopy_plane_segmentations or [mock_MicroscopyPlaneSegmentation()] - image_segmentation = ndx_microscopy.ImageSegmentation( + segmentations = ndx_microscopy.MicroscopySegmentations( name=name, microscopy_plane_segmentations=microscopy_plane_segmentations ) - return image_segmentation + return segmentations def mock_MicroscopyPlaneSegmentation( - imaging_space: ImagingSpace, + imaging_space: ndx_microscopy.ImagingSpace, name: Optional[str] = None, description: str = "This is a mock instance of a MicroscopyPlaneSegmentation type to be used for rapid testing.", number_of_rois: int = 5, diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 2c8fc3a..5f00b9b 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -5,7 +5,7 @@ import pynwb from ndx_microscopy.testing import ( mock_Microscope, - mock_MicroscopyImageSegmentation, + mock_MicroscopySegmentations, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, mock_MicroscopyPlaneSegmentation, @@ -44,8 +44,8 @@ def test_constructor_volumetric_image_space(): mock_VolumetricImagingSpace(microscope=microscope) -def test_constructor_microscopy_image_segmentation(): - mock_MicroscopyImageSegmentation() +def test_constructor_microscopy_segmentations(): + mock_MicroscopySegmentations() def test_constructor_microscopy_plane_segmentation(): @@ -67,7 +67,7 @@ def test_constructor_microscopy_image_segmentation_with_plane_segmentation(): ) microscopy_plane_segmentations = [plane_segmentation_1, plane_segmentation_2] - mock_MicroscopyImageSegmentation(microscopy_plane_segmentations=microscopy_plane_segmentations) + mock_MicroscopySegmentations(microscopy_plane_segmentations=microscopy_plane_segmentations) def test_constructor_planar_microscopy_series(): diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index eb33e02..c5c715d 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -15,6 +15,8 @@ mock_VariableDepthMicroscopySeries, mock_VolumetricImagingSpace, mock_VolumetricMicroscopySeries, + mock_MicroscopySegmentations, + mock_MicroscopyPlaneSegmentation, ) @@ -233,7 +235,48 @@ def test_roundtrip(self): ) -# TODO: add roundtrip for planesegmentation, imagesegmentation, etc. +class TestMicroscopySegmentationsSimpleRoundtrip(pynwb_TestCase): + """Simple roundtrip test for MicroscopySegmentations.""" + + def setUp(self): + self.nwbfile_path = "test_microscopy_segmentations_roundtrip.nwb" + + def tearDown(self): + pynwb.testing.remove_test_file(self.nwbfile_path) + + def test_roundtrip(self): + nwbfile = mock_NWBFile() + + microscope = mock_Microscope() + nwbfile.add_device(devices=microscope) + + imaging_space = mock_PlanarImagingSpace(microscope=microscope) + nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() + + plane_segmentation_1 = mock_MicroscopyPlaneSegmentation( + imaging_space=imaging_space, name="MicroscopyPlaneSegmentation1" + ) + plane_segmentation_2 = mock_MicroscopyPlaneSegmentation( + imaging_space=imaging_space, name="MicroscopyPlaneSegmentation2" + ) + microscopy_plane_segmentations = [plane_segmentation_1, plane_segmentation_2] + + segmentations = mock_MicroscopySegmentations(microscopy_plane_segmentations=microscopy_plane_segmentations) + processing_module = nwbfile.create_processing_module(name="ophys") + processing_module.add(segmentations) + + with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="w") as io: + io.write(nwbfile) + + with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="r", load_namespaces=True) as io: + read_nwbfile = io.read() + + self.assertContainerEqual(microscope, read_nwbfile.devices["Microscope"]) + + self.assertContainerEqual(imaging_space, read_nwbfile.lab_meta_data["PlanarImagingSpace"]) + + self.assertContainerEqual(segmentations, read_nwbfile.processing["ophys"]["MicroscopySegmentations"]) + if __name__ == "__main__": pytest.main() # Required since not a typical package structure From e583e39bb728b1d50e1264914a34561cdd888d66 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 19:23:20 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pynwb/tests/test_constructors.py | 2 +- src/pynwb/tests/test_roundtrip.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 8b325fb..2c3d781 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -6,10 +6,10 @@ from ndx_microscopy.testing import ( mock_LightSource, mock_Microscope, - mock_MicroscopySegmentations, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, mock_MicroscopyPlaneSegmentation, + mock_MicroscopySegmentations, mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 2a97616..ff17ef3 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -9,14 +9,14 @@ mock_Microscope, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, + mock_MicroscopyPlaneSegmentation, + mock_MicroscopySegmentations, mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, mock_VolumetricImagingSpace, mock_VolumetricMicroscopySeries, - mock_MicroscopySegmentations, - mock_MicroscopyPlaneSegmentation, )