From 97bfa2038119bf748c1ad100e4cd5b576ad105c0 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Mon, 24 Jun 2024 13:04:18 -0400 Subject: [PATCH 01/44] add multichannel volume --- spec/ndx-microscopy.extensions.yaml | 68 +++++++++++++++++++- src/pynwb/ndx_microscopy/__init__.py | 2 + src/pynwb/ndx_microscopy/testing/__init__.py | 2 + src/pynwb/ndx_microscopy/testing/_mock.py | 33 +++++++++- src/pynwb/tests/test_constructors.py | 15 +++++ src/pynwb/tests/test_roundtrip.py | 52 ++++++++++++++- 6 files changed, 169 insertions(+), 3 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index f76bc1d..3fd246e 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,69 @@ 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: NWBData + 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 + - channels + shape: + - null + - null + - null + - 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: light_source + doc: Link to a LightSource object containing metadata about the device used to illuminate the imaging space. + target_type: LightSource + # TODO: figure out best way to link to list of optical channels + - name: optical_channels + doc: Link to an ordered list of MicroscopyOpticalChannel objects containing metadata about the indicator and + filters used to collect this data. + target_type: MicroscopyOpticalChannel + - 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 a8cf19a..e7e3d86 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 adad764..17e66d9 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -2,6 +2,7 @@ mock_LightSource, mock_Microscope, 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 7eebeb5..7570713 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -1,5 +1,5 @@ import warnings -from typing import Optional, Tuple +from typing import List, Optional, Tuple import numpy as np from pynwb.testing.mock.utils import name_generator @@ -286,3 +286,34 @@ def mock_VolumetricMicroscopySeries( timestamps=series_timestamps, ) return volumetric_microscopy_series + + +def mock_MultiChannelMicroscopyVolume( + *, + microscope: ndx_microscopy.Microscope, + light_source: ndx_microscopy.LightSource, + imaging_space: ndx_microscopy.VolumetricImagingSpace, + optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], + 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, + light_source=light_source, + imaging_space=imaging_space, + optical_channels=optical_channels[0], # TODO: figure out how to specify list + 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 1410594..bd6ab83 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -6,6 +6,7 @@ mock_LightSource, mock_Microscope, mock_MicroscopyOpticalChannel, + mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, @@ -71,5 +72,19 @@ def test_constructor_volumetric_microscopy_series(): ) +def test_constructor_multi_channel_microscopy_volume(): + microscope = mock_Microscope() + light_source = mock_LightSource() + imaging_space = mock_VolumetricImagingSpace(microscope=microscope) + optical_channel = mock_MicroscopyOpticalChannel() + + mock_MultiChannelMicroscopyVolume( + microscope=microscope, + light_source=light_source, + imaging_space=imaging_space, + optical_channels=[optical_channel], + ) + + 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 15644b1..2d827b5 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -133,7 +133,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 +162,53 @@ 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.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) + + light_source = mock_LightSource(name="LightSource") + nwbfile.add_device(devices=light_source) + + imaging_space = mock_VolumetricImagingSpace(name="VolumetricImagingSpace", microscope=microscope) + 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) + + multi_channel_microscopy_volume = mock_MultiChannelMicroscopyVolume( + name="MultiChannelMicroscopyVolume", + microscope=microscope, + light_source=light_source, + imaging_space=imaging_space, + optical_channels=[optical_channel], + ) + 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, read_nwbfile.devices["LightSource"]) + + self.assertContainerEqual(imaging_space, read_nwbfile.lab_meta_data["PlanarImagingSpace"]) + self.assertContainerEqual(optical_channel, read_nwbfile.lab_meta_data["MicroscopyOpticalChannel"]) + + self.assertContainerEqual( + multi_channel_microscopy_volume, read_nwbfile.acquisition["MultiChannelMicroscopyVolume"] + ) From 91db41b1f61822b39b28efef4938c5232e7c4ce5 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Mon, 24 Jun 2024 15:54:29 -0400 Subject: [PATCH 02/44] swap to datainterface --- spec/ndx-microscopy.extensions.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 3fd246e..518d146 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -260,7 +260,7 @@ groups: target_type: VolumetricImagingSpace - neurodata_type_def: MultiChannelMicroscopyVolume - neurodata_type_inc: NWBData + neurodata_type_inc: NWBDataInterface doc: Static (not time-varying) volumetric imaging data acquired from multiple optical channels. attributes: - name: description From 200eb9bee63fd23f4c5999828964a596c930b23c Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Mon, 24 Jun 2024 15:57:38 -0400 Subject: [PATCH 03/44] fix import --- src/pynwb/tests/test_roundtrip.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 2d827b5..c04933f 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -8,6 +8,7 @@ mock_LightSource, mock_Microscope, mock_MicroscopyOpticalChannel, + mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, From b84aa0bfc6243ba7e1da8b905622c8a9f2e9e656 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Mon, 24 Jun 2024 16:06:06 -0400 Subject: [PATCH 04/44] fix test name --- src/pynwb/tests/test_roundtrip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index c04933f..fbad5f1 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -207,7 +207,7 @@ def test_roundtrip(self): self.assertContainerEqual(microscope, read_nwbfile.devices["Microscope"]) self.assertContainerEqual(light_source, read_nwbfile.devices["LightSource"]) - self.assertContainerEqual(imaging_space, read_nwbfile.lab_meta_data["PlanarImagingSpace"]) + self.assertContainerEqual(imaging_space, read_nwbfile.lab_meta_data["VolumetricImagingSpace"]) self.assertContainerEqual(optical_channel, read_nwbfile.lab_meta_data["MicroscopyOpticalChannel"]) self.assertContainerEqual( From c8b5dfd23c41247880a7156349d4ebd10e047c93 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 12:26:39 -0400 Subject: [PATCH 05/44] fix intercompatability --- spec/ndx-microscopy.extensions.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index da3d397..8d03861 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -313,8 +313,8 @@ groups: doc: Link to a Microscope object containing metadata about the device used to acquire this imaging data. target_type: Microscope - name: light_source - doc: Link to a LightSource object containing metadata about the device used to illuminate the imaging space. - target_type: LightSource + doc: Link to a MicroscopyLightSource object containing metadata about the device used to illuminate the imaging space. + target_type: MicroscopyLightSource # TODO: figure out best way to link to list of optical channels - name: optical_channels doc: Link to an ordered list of MicroscopyOpticalChannel objects containing metadata about the indicator and From ad6b5e74adf681bb4ac9c191629ead857d79ba62 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 12:30:14 -0400 Subject: [PATCH 06/44] fix light sources --- spec/ndx-microscopy.extensions.yaml | 5 +++-- src/pynwb/ndx_microscopy/testing/_mock.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 8d03861..c5fb049 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -312,8 +312,9 @@ groups: - name: microscope doc: Link to a Microscope object containing metadata about the device used to acquire this imaging data. target_type: Microscope - - name: light_source - doc: Link to a MicroscopyLightSource object containing metadata about the device used to illuminate the imaging space. + # TODO: figure out best way to link to list of light sources + - name: light_sources + doc: Link to an ordered list of MicroscopyLightSource objects containing metadata about the excitation method. target_type: MicroscopyLightSource # TODO: figure out best way to link to list of optical channels - name: optical_channels diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 6a32364..4a09dfb 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -291,7 +291,7 @@ def mock_VolumetricMicroscopySeries( def mock_MultiChannelMicroscopyVolume( *, microscope: ndx_microscopy.Microscope, - light_source: ndx_microscopy.LightSource, + light_sources: ndx_microscopy.MicroscopyLightSource, imaging_space: ndx_microscopy.VolumetricImagingSpace, optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], name: Optional[str] = None, @@ -308,7 +308,7 @@ def mock_MultiChannelMicroscopyVolume( name=series_name, description=description, microscope=microscope, - light_source=light_source, + light_sources=light_source[0], # TODO: figure out how to specify list imaging_space=imaging_space, optical_channels=optical_channels[0], # TODO: figure out how to specify list data=imaging_data, From 8b69db4fb9318e1d3a9c1dfa34aaf6ac40611e9e Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 13:06:41 -0400 Subject: [PATCH 07/44] fix --- src/pynwb/ndx_microscopy/testing/_mock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 4a09dfb..12cf5eb 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -291,7 +291,7 @@ def mock_VolumetricMicroscopySeries( def mock_MultiChannelMicroscopyVolume( *, microscope: ndx_microscopy.Microscope, - light_sources: ndx_microscopy.MicroscopyLightSource, + light_sources: List[ndx_microscopy.MicroscopyLightSource], imaging_space: ndx_microscopy.VolumetricImagingSpace, optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], name: Optional[str] = None, @@ -308,7 +308,7 @@ def mock_MultiChannelMicroscopyVolume( name=series_name, description=description, microscope=microscope, - light_sources=light_source[0], # TODO: figure out how to specify list + light_sources=light_sources[0], # TODO: figure out how to specify list imaging_space=imaging_space, optical_channels=optical_channels[0], # TODO: figure out how to specify list data=imaging_data, From 00d2270a0e50236f6072aadadf5e4f9a101a76d2 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 15:33:39 -0400 Subject: [PATCH 08/44] add plane segmentation stuff --- src/pynwb/ndx_microscopy/__init__.py | 4 +++ src/pynwb/ndx_microscopy/testing/__init__.py | 4 +++ src/pynwb/ndx_microscopy/testing/_mock.py | 32 +++++++++++++++++++- src/pynwb/tests/test_constructors.py | 28 +++++++++++++++++ src/pynwb/tests/test_roundtrip.py | 3 ++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/__init__.py b/src/pynwb/ndx_microscopy/__init__.py index 722b281..e27a792 100644 --- a/src/pynwb/ndx_microscopy/__init__.py +++ b/src/pynwb/ndx_microscopy/__init__.py @@ -26,6 +26,8 @@ ImagingSpace = get_class("ImagingSpace", extension_name) PlanarImagingSpace = get_class("PlanarImagingSpace", extension_name) VolumetricImagingSpace = get_class("VolumetricImagingSpace", extension_name) +MicroscopyImageSegmentation = get_class("MicroscopyImageSegmentation", extension_name) +MicroscopyPlaneSegmentation = get_class("MicroscopyPlaneSegmentation", extension_name) MicroscopySeries = get_class("MicroscopySeries", extension_name) PlanarMicroscopySeries = get_class("PlanarMicroscopySeries", extension_name) VariableDepthMicroscopySeries = get_class("VariableDepthMicroscopySeries", extension_name) @@ -39,6 +41,8 @@ "ImagingSpace", "PlanarImagingSpace", "VolumetricImagingSpace", + "MicroscopyImageSegmentation", + "MicroscopyPlaneSegmentation", "MicroscopySeries", "PlanarMicroscopySeries", "VariableDepthMicroscopySeries", diff --git a/src/pynwb/ndx_microscopy/testing/__init__.py b/src/pynwb/ndx_microscopy/testing/__init__.py index b305dac..35a2a97 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -1,7 +1,9 @@ from ._mock import ( mock_Microscope, + mock_MicroscopyImageSegmentation, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, + mock_MicroscopyPlaneSegmentation, mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, @@ -16,6 +18,8 @@ "mock_MicroscopyOpticalChannel", "mock_PlanarImagingSpace", "mock_VolumetricImagingSpace", + "mock_MicroscopyImageSegmentation", + "mock_MicroscopyPlaneSegmentation", "mock_PlanarMicroscopySeries", "mock_VariableDepthMicroscopySeries", "mock_VolumetricMicroscopySeries", diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 12cf5eb..17d66a3 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -1,5 +1,5 @@ import warnings -from typing import List, Optional, Tuple +from typing import Iterable, List, Optional, Tuple import numpy as np from pynwb.testing.mock.utils import name_generator @@ -115,6 +115,36 @@ def mock_VolumetricImagingSpace( return volumetric_imaging_space +def mock_MicroscopyImageSegmentation( + name: Optional[str] = None, plane_segmentations: Optional[Iterable[PlaneSegmentation]] = None +) -> ndx_microscopy.MicroscopyImageSegmentation: + name = name or name_generator("MicroscopyImageSegmentation") + plane_segmentations = plane_segmentations or [mock_MicroscopyPlaneSegmentation()] + + image_segmentation = ImageSegmentation(name=name, plane_segmentations=plane_segmentations) + + return image_segmentation + + +def mock_MicroscopyPlaneSegmentation( + imaging_space: 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, + image_shape: Tuple[int, int] = (10, 10), +) -> ndx_microscopy.MicroscopyPlaneSegmentation: + name = name or name_generator("MicroscopyPlaneSegmentation") + + plane_segmentation = ndx_microscopy.MicroscopyPlaneSegmentation( + name=name, description=description, imaging_space=imaging_space + ) + + for _ in range(number_of_rois): + plane_segmentation.add_roi(image_mask=np.zeros(image_shape, dtype=bool)) + + return plane_segmentation + + def mock_PlanarMicroscopySeries( *, microscope: ndx_microscopy.Microscope, diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index fd05c43..3ad18b1 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -4,8 +4,10 @@ from ndx_microscopy.testing import ( mock_Microscope, + mock_MicroscopyImageSegmentation, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, + mock_MicroscopyPlaneSegmentation, mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, @@ -39,6 +41,32 @@ def test_constructor_volumetric_image_space(): mock_VolumetricImagingSpace(microscope=microscope) +def test_constructor_microscopy_image_segmentation(): + mock_MicroscopyImageSegmentation() + + +def test_constructor_microscopy_plane_segmentation(): + microscope = mock_Microscope() + imaging_space = mock_PlanarImagingSpace(microscope=microscope) + + mock_MicroscopyPlaneSegmentation(imaging_space=imaging_space) + + +def test_constructor_microscopy_image_segmentation_with_plane_segmentation(): + microscope = mock_Microscope() + imaging_space = mock_PlanarImagingSpace(microscope=microscope) + + plane_segmentation_1 = mock_MicroscopyPlaneSegmentation( + imaging_space=imaging_space, name="MicroscopyPlaneSegmentation1" + ) + plane_segmentation_2 = mock_MicroscopyPlaneSegmentation( + imaging_space=imaging_space, name="MicroscopyPlaneSegmentation2" + ) + plane_segmentations = [plane_segmentation_1, plane_segmentation_2] + + mock_MicroscopyImageSegmentation(plane_segmentations=plane_segmentations) + + def test_constructor_planar_microscopy_series(): microscope = mock_Microscope() light_source = mock_MicroscopyLightSource() diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 58c320b..4ca2694 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -213,3 +213,6 @@ def test_roundtrip(self): self.assertContainerEqual( multi_channel_microscopy_volume, read_nwbfile.acquisition["MultiChannelMicroscopyVolume"] ) + + +# TODO: add roundtrip for planesegmentation, imagesegmentation, etc. From c6b529cd27214e010994c56bf26c9c2b22444480 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 15:42:23 -0400 Subject: [PATCH 09/44] fix autogenerated arg --- spec/ndx-microscopy.extensions.yaml | 126 ++++++++++++++++++---- src/pynwb/ndx_microscopy/testing/_mock.py | 8 +- src/pynwb/tests/test_constructors.py | 4 +- 3 files changed, 112 insertions(+), 26 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index c5fb049..1682d56 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -95,7 +95,7 @@ groups: doc: General estimate of location in the brain being subset by this space. Specify the area, layer, etc. Use standard atlas names for anatomical regions when possible. - Specify 'whole-brain' if the entire brain is strictly contained within the space. + Specify 'whole brain' if the entire brain is strictly contained within the space. required: false links: - name: microscope @@ -106,22 +106,14 @@ groups: neurodata_type_inc: ImagingSpace doc: Metadata about the 2-dimensional slice of physical space that imaging data was recorded from. datasets: - - name: grid_spacing + - name: grid_spacing_in_um dtype: float64 dims: - - x, y shape: - - 2 - doc: Amount of space between pixels in the specified unit. - Specify 'z' only when imaging volume is a regular grid; otherwise only specify 'x' and 'y'. - See origin_coordinates to determine where the grid begins. + doc: Amount of space between pixels in micrometers. quantity: '?' -# TODO: deal with grid_spacing units -# attributes: -# - name: unit -# dtype: text -# default_value: micrometers -# doc: Measurement units for grid spacing. The default value is 'micrometers'. attributes: - name: reference_frame dtype: text @@ -146,22 +138,14 @@ groups: neurodata_type_inc: ImagingSpace doc: Metadata about the 3-dimensional region of physical space that imaging data was recorded from. datasets: - - name: grid_spacing - doc: Amount of space between pixels in (x, y) or voxels in (x, y, z), in the specified unit. - Specify 'z' only when imaging volume is a regular grid; otherwise only specify 'x' and 'y'. - See origin_coordinates to determine where the grid begins. + - name: grid_spacing_in_um + doc: Amount of space between voxels in micrometers. dtype: float64 dims: - - x, y, z shape: - - 3 quantity: '?' -# TODO: deal with grid_spacing units -# attributes: -# - name: unit -# dtype: text -# default_value: micrometers -# doc: Measurement units for grid spacing. The default value is 'micrometers'. attributes: - name: reference_frame doc: Describes the reference frame of origin_coordinates and grid_spacing. @@ -182,6 +166,106 @@ groups: dtype: text required: false + + # 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_inc: NWBDataInterface + default_name: MicroscopyImageSegmentation + 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 + own subgroup, with the ROI group containing both a 2D mask and a list of pixels + that make up this mask. Segments can also be used for masking neuropil. If segmentation + is allowed to change with time, a new imaging plane (or module) is required and + ROI names should remain consistent between them. + groups: + - neurodata_type_inc: MicroscopyPlaneSegmentation + doc: Results from image segmentation of a specific imaging plane. + quantity: '+' + + + - neurodata_type_def: MicroscopyPlaneSegmentation + neurodata_type_inc: DynamicTable + doc: Results from image segmentation of a specific imaging plane. + datasets: + - name: image_mask + neurodata_type_inc: VectorData + dims: + - - num_roi + - num_x + - num_y + - - num_roi + - num_x + - num_y + - num_z + shape: + - - null + - null + - null + - - null + - null + - null + - null + doc: ROI masks for each ROI. Each image mask is the size of the original imaging + plane (or volume) and members of the ROI are finite non-zero. + quantity: '?' + - name: pixel_mask_index + neurodata_type_inc: VectorIndex + doc: Index into pixel_mask. + quantity: '?' + - name: pixel_mask + neurodata_type_inc: VectorData + dtype: + - name: x + dtype: uint32 + doc: Pixel x-coordinate. + - name: y + dtype: uint32 + doc: Pixel y-coordinate. + - name: weight + dtype: float32 + doc: Weight of the pixel. + doc: 'Pixel masks for each ROI: a list of indices and weights for the ROI. Pixel + masks are concatenated and parsing of this dataset is maintained by the PlaneSegmentation' + quantity: '?' + - name: voxel_mask_index + neurodata_type_inc: VectorIndex + doc: Index into voxel_mask. + quantity: '?' + - name: voxel_mask + neurodata_type_inc: VectorData + dtype: + - name: x + dtype: uint32 + doc: Voxel x-coordinate. + - name: y + dtype: uint32 + doc: Voxel y-coordinate. + - name: z + dtype: uint32 + doc: Voxel z-coordinate. + - name: weight + dtype: float32 + doc: Weight of the voxel. + doc: 'Voxel masks for each ROI: a list of indices and weights for the ROI. Voxel + 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. + groups: + - neurodata_type_inc: ImageSeries + doc: One or more image stacks that the masks apply to (can be one-element + stack). + quantity: '*' + links: + - name: imaging_space + target_type: ImagingSpace + doc: Link to ImagingSpace object from which this data was generated. + + - neurodata_type_def: MicroscopySeries neurodata_type_inc: TimeSeries doc: Imaging data acquired over time from an optical channel in a microscope while a light source illuminates the diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 17d66a3..605622e 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -116,12 +116,14 @@ def mock_VolumetricImagingSpace( def mock_MicroscopyImageSegmentation( - name: Optional[str] = None, plane_segmentations: Optional[Iterable[PlaneSegmentation]] = None + name: Optional[str] = None, microscopy_plane_segmentations: Optional[Iterable[PlaneSegmentation]] = None ) -> ndx_microscopy.MicroscopyImageSegmentation: name = name or name_generator("MicroscopyImageSegmentation") - plane_segmentations = plane_segmentations or [mock_MicroscopyPlaneSegmentation()] + microscopy_plane_segmentations = microscopy_plane_segmentations or [mock_MicroscopyPlaneSegmentation()] - image_segmentation = ImageSegmentation(name=name, plane_segmentations=plane_segmentations) + image_segmentation = ndx_microscopy.ImageSegmentation( + name=name, microscopy_plane_segmentations=microscopy_plane_segmentations + ) return image_segmentation diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 3ad18b1..c56f4a9 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -62,9 +62,9 @@ def test_constructor_microscopy_image_segmentation_with_plane_segmentation(): plane_segmentation_2 = mock_MicroscopyPlaneSegmentation( imaging_space=imaging_space, name="MicroscopyPlaneSegmentation2" ) - plane_segmentations = [plane_segmentation_1, plane_segmentation_2] + microscopy_plane_segmentations = [plane_segmentation_1, plane_segmentation_2] - mock_MicroscopyImageSegmentation(plane_segmentations=plane_segmentations) + mock_MicroscopyImageSegmentation(microscopy_plane_segmentations=microscopy_plane_segmentations) def test_constructor_planar_microscopy_series(): From 22836edd6b2f778d83c6ea735ead93d1dd665192 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 16:26:50 -0400 Subject: [PATCH 10/44] variable depth volume --- spec/ndx-microscopy.extensions.yaml | 79 +++++++++++++++++++- src/pynwb/ndx_microscopy/__init__.py | 2 + src/pynwb/ndx_microscopy/testing/__init__.py | 2 + src/pynwb/ndx_microscopy/testing/_mock.py | 39 +++++++++- src/pynwb/tests/test_constructors.py | 15 ++++ 5 files changed, 135 insertions(+), 2 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 1682d56..655d4fd 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -311,7 +311,7 @@ groups: datasets: - name: depth_per_frame_in_mm doc: Depth of each frame in the data array. - These values offset the 'z' value of the origin_coordinates of the linked imaging_space object. + These values offset the 'z' value of the `origin_coordinates` of the linked `imaging_space` object. dtype: numeric dims: - frames @@ -343,6 +343,7 @@ groups: 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. @@ -409,3 +410,79 @@ 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: VariableDepthMultiChannelMicroscopyVolume + neurodata_type_inc: NWBDataInterface + doc: Static (not time-varying) irregularly spaced volumetric imaging data acquired from multiple optical channels. + attributes: + - name: description + dtype: text + doc: Description of the VariableDepthMultiChannelMicroscopyVolume. + 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 + - channels + shape: + - null + - null + - null + - null + - name: depth_per_frame_in_mm + doc: Depth of each frame in the data array. + These values offset the 'z' value of the `origin_coordinates` of the linked `imaging_space` object. + dtype: numeric + dims: + - depths + 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 + # TODO: figure out best way to link to list of light sources + - name: light_sources + doc: Link to an ordered list of MicroscopyLightSource objects containing metadata about the excitation method. + target_type: MicroscopyLightSource + # TODO: figure out best way to link to list of optical channels + - name: optical_channels + doc: Link to an ordered list of MicroscopyOpticalChannel objects containing metadata about the indicator and + filters used to collect this data. + target_type: MicroscopyOpticalChannel + - 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 e27a792..abc6b72 100644 --- a/src/pynwb/ndx_microscopy/__init__.py +++ b/src/pynwb/ndx_microscopy/__init__.py @@ -33,6 +33,7 @@ VariableDepthMicroscopySeries = get_class("VariableDepthMicroscopySeries", extension_name) VolumetricMicroscopySeries = get_class("VolumetricMicroscopySeries", extension_name) MultiChannelMicroscopyVolume = get_class("MultiChannelMicroscopyVolume", extension_name) +VariableDepthMultiChannelMicroscopyVolume = get_class("VariableDepthMultiChannelMicroscopyVolume", extension_name) __all__ = [ "Microscope", @@ -48,4 +49,5 @@ "VariableDepthMicroscopySeries", "VolumetricMicroscopySeries", "MultiChannelMicroscopyVolume", + "VariableDepthMultiChannelMicroscopyVolume", ] diff --git a/src/pynwb/ndx_microscopy/testing/__init__.py b/src/pynwb/ndx_microscopy/testing/__init__.py index 35a2a97..e88baad 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -8,6 +8,7 @@ mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, + mock_VariableDepthMultiChannelMicroscopyVolume, mock_VolumetricImagingSpace, mock_VolumetricMicroscopySeries, ) @@ -24,4 +25,5 @@ "mock_VariableDepthMicroscopySeries", "mock_VolumetricMicroscopySeries", "mock_MultiChannelMicroscopyVolume", + "mock_VariableDepthMultiChannelMicroscopyVolume", ] diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 605622e..5998785 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -221,7 +221,6 @@ def mock_VariableDepthMicroscopySeries( ) -> ndx_microscopy.VariableDepthMicroscopySeries: series_name = name or name_generator("VariableDepthMicroscopySeries") series_data = data if data is not None else np.ones(shape=(15, 5, 5)) - series_depth_per_frame_in_mm = ( depth_per_frame_in_mm if depth_per_frame_in_mm is not None @@ -349,3 +348,41 @@ def mock_MultiChannelMicroscopyVolume( offset=offset, ) return volumetric_microscopy_series + + +def mock_VariableDepthMultiChannelMicroscopyVolume( + *, + microscope: ndx_microscopy.Microscope, + light_sources: List[ndx_microscopy.MicroscopyLightSource], + imaging_space: ndx_microscopy.VolumetricImagingSpace, + optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], + 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, + depth_per_frame_in_mm: Optional[np.ndarray] = None, + unit: str = "n.a.", + conversion: float = 1.0, + offset: float = 0.0, +) -> ndx_microscopy.VariableDepthMultiChannelMicroscopyVolume: + series_name = name or name_generator("MultiChannelMicroscopyVolume") + imaging_data = data if data is not None else np.ones(shape=(10, 20, 7, 3)) + volume_depth_per_frame_in_mm = ( + depth_per_frame_in_mm + if depth_per_frame_in_mm is not None + else np.linspace(start=0.0, stop=1.0, num=series_data.shape[0]) + ) + + variable_depth_multi_channel_microscopy_volume = ndx_microscopy.VariableDepthMultiChannelMicroscopyVolume( + name=series_name, + description=description, + microscope=microscope, + light_sources=light_sources[0], # TODO: figure out how to specify list + imaging_space=imaging_space, + optical_channels=optical_channels[0], # TODO: figure out how to specify list + data=imaging_data, + depth_per_frame_in_mm=volume_depth_per_frame_in_mm, + unit=unit, + conversion=conversion, + offset=offset, + ) + return variable_depth_multi_channel_microscopy_volume diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index c56f4a9..b94669e 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -12,6 +12,7 @@ mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, mock_VariableDepthMicroscopySeries, + mock_VariableDepthMultiChannelMicroscopyVolume, mock_VolumetricImagingSpace, mock_VolumetricMicroscopySeries, ) @@ -114,5 +115,19 @@ def test_constructor_multi_channel_microscopy_volume(): ) +def test_constructor_variable_depth_multi_channel_microscopy_volume(): + microscope = mock_Microscope() + light_source = mock_LightSource() + imaging_space = mock_VolumetricImagingSpace(microscope=microscope) + optical_channel = mock_MicroscopyOpticalChannel() + + mock_VariableDepthMultiChannelMicroscopyVolume( + microscope=microscope, + light_source=light_source, + imaging_space=imaging_space, + optical_channels=[optical_channel], + ) + + if __name__ == "__main__": pytest.main() # Required since not a typical package structure From 9ad9f4b5018b9d88336757e48a1d3cbf9d3e4fed Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Wed, 26 Jun 2024 16:48:47 -0400 Subject: [PATCH 11/44] swap to um --- spec/ndx-microscopy.extensions.yaml | 8 ++++---- src/pynwb/ndx_microscopy/testing/_mock.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 655d4fd..ed200e3 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -309,8 +309,8 @@ groups: doc: Volumetric imaging data acquired over an irregular number and amount of depths; for instance, when using an electrically tunable lens. datasets: - - name: depth_per_frame_in_mm - doc: Depth of each frame in the data array. + - name: depth_per_frame_in_um + doc: Depth in micrometers of each frame in the data array. These values offset the 'z' value of the `origin_coordinates` of the linked `imaging_space` object. dtype: numeric dims: @@ -461,8 +461,8 @@ groups: - null - null - null - - name: depth_per_frame_in_mm - doc: Depth of each frame in the data array. + - name: depth_per_frame_in_um + doc: Depth in micrometers of each frame in the data array. These values offset the 'z' value of the `origin_coordinates` of the linked `imaging_space` object. dtype: numeric dims: diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 5998785..cc640ef 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -366,7 +366,7 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( ) -> ndx_microscopy.VariableDepthMultiChannelMicroscopyVolume: series_name = name or name_generator("MultiChannelMicroscopyVolume") imaging_data = data if data is not None else np.ones(shape=(10, 20, 7, 3)) - volume_depth_per_frame_in_mm = ( + volume_depth_per_frame_in_um = ( depth_per_frame_in_mm if depth_per_frame_in_mm is not None else np.linspace(start=0.0, stop=1.0, num=series_data.shape[0]) @@ -380,7 +380,7 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( imaging_space=imaging_space, optical_channels=optical_channels[0], # TODO: figure out how to specify list data=imaging_data, - depth_per_frame_in_mm=volume_depth_per_frame_in_mm, + depth_per_frame_in_um=volume_depth_per_frame_in_um, unit=unit, conversion=conversion, offset=offset, From 56f70855f7504465280daeff4ac8c5bc5d54011c Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Thu, 27 Jun 2024 13:22:10 -0400 Subject: [PATCH 12/44] override for roi response to avoid construct error --- spec/ndx-microscopy.extensions.yaml | 18 ++++++++++++++++++ src/pynwb/ndx_microscopy/__init__.py | 2 ++ src/pynwb/ndx_microscopy/testing/_mock.py | 3 +++ src/pynwb/tests/test_constructors.py | 3 +++ src/pynwb/tests/test_roundtrip.py | 2 ++ 5 files changed, 28 insertions(+) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index ed200e3..0781506 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -486,3 +486,21 @@ 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: MicroscopyResponseSeries + neurodata_type_inc: TimeSeries + doc: ROI responses extracted from optical imaging. + datasets: + - name: data + dtype: numeric + dims: + - - number_of_frames + - number_of_rois + shape: + - - null + - null + doc: Signals from ROIs. + - name: rois + neurodata_type_inc: DynamicTableRegion + doc: DynamicTableRegion referencing plane segmentation containing more information about the ROIs + stored in this series. diff --git a/src/pynwb/ndx_microscopy/__init__.py b/src/pynwb/ndx_microscopy/__init__.py index abc6b72..bee92b8 100644 --- a/src/pynwb/ndx_microscopy/__init__.py +++ b/src/pynwb/ndx_microscopy/__init__.py @@ -34,6 +34,7 @@ VolumetricMicroscopySeries = get_class("VolumetricMicroscopySeries", extension_name) MultiChannelMicroscopyVolume = get_class("MultiChannelMicroscopyVolume", extension_name) VariableDepthMultiChannelMicroscopyVolume = get_class("VariableDepthMultiChannelMicroscopyVolume", extension_name) +MicroscopyResponseSeries = get_class("MicroscopyResponseSeries", extension_name) __all__ = [ "Microscope", @@ -50,4 +51,5 @@ "VolumetricMicroscopySeries", "MultiChannelMicroscopyVolume", "VariableDepthMultiChannelMicroscopyVolume", + "MicroscopyResponseSeries", ] diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index cc640ef..987f1bf 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -386,3 +386,6 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( offset=offset, ) return variable_depth_multi_channel_microscopy_volume + + +# TODO: add mock for MicroscopyResponseSeries diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index b94669e..0acd887 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -129,5 +129,8 @@ def test_constructor_variable_depth_multi_channel_microscopy_volume(): ) +# TODO: add constructor tests for MicroscopyResponseSeries + + 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 4ca2694..e50a5f1 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -216,3 +216,5 @@ def test_roundtrip(self): # TODO: add roundtrip for planesegmentation, imagesegmentation, etc. + +# TODO: add roundtrip test for MicroscopyResponseSeries From dd166ad1db5095d69e84f3cb47120bfbb745f91b Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Thu, 27 Jun 2024 13:51:18 -0400 Subject: [PATCH 13/44] add container too --- spec/ndx-microscopy.extensions.yaml | 11 ++++++++++- src/pynwb/ndx_microscopy/__init__.py | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 0781506..a3fcbf8 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -500,7 +500,16 @@ groups: - - null - null doc: Signals from ROIs. - - name: rois + - name: table_region neurodata_type_inc: DynamicTableRegion doc: DynamicTableRegion referencing plane segmentation containing more information about the ROIs stored in this series. + + - neurodata_type_def: MicroscopyResponseSeriesContainer + neurodata_type_inc: NWBDataInterface + default_name: MicroscopyResponseSeriesContainer + doc: A container of many MicroscopyResponseSeries. + groups: + - neurodata_type_inc: MicroscopyResponseSeries + doc: MicroscopyResponseSeries object(s) containing fluorescence data for a ROI. + quantity: '+' diff --git a/src/pynwb/ndx_microscopy/__init__.py b/src/pynwb/ndx_microscopy/__init__.py index bee92b8..f35baff 100644 --- a/src/pynwb/ndx_microscopy/__init__.py +++ b/src/pynwb/ndx_microscopy/__init__.py @@ -35,6 +35,7 @@ MultiChannelMicroscopyVolume = get_class("MultiChannelMicroscopyVolume", extension_name) VariableDepthMultiChannelMicroscopyVolume = get_class("VariableDepthMultiChannelMicroscopyVolume", extension_name) MicroscopyResponseSeries = get_class("MicroscopyResponseSeries", extension_name) +MicroscopyResponseSeriesContainer = get_class("MicroscopyResponseSeriesContainer", extension_name) __all__ = [ "Microscope", @@ -52,4 +53,5 @@ "MultiChannelMicroscopyVolume", "VariableDepthMultiChannelMicroscopyVolume", "MicroscopyResponseSeries", + "MicroscopyResponseSeriesContainer", ] From 04230711e5ade2effc11800a329a91de635f96a6 Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:37:48 -0400 Subject: [PATCH 14/44] ryans suggestion --- spec/ndx-microscopy.extensions.yaml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index c5fb049..7e31250 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -308,19 +308,28 @@ groups: - null - null - null + - name: light_sources + doc: Reference to an ordered list of MicroscopyLightSource objects containing metadata about the excitation method. + dtype: + reftype: object + target_type: MicroscopyLightSource + dims: + - num_light_sources + shape: + - null + - name: optical_channels + doc: Reference to an ordered list of MicroscopyOpticalChannel objects containing metadata about the indicator and filters used to collect this data. + dtype: + reftype: object + target_type: MicroscopyOpticalChannel + dims: + - num_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 - # TODO: figure out best way to link to list of light sources - - name: light_sources - doc: Link to an ordered list of MicroscopyLightSource objects containing metadata about the excitation method. - target_type: MicroscopyLightSource - # TODO: figure out best way to link to list of optical channels - - name: optical_channels - doc: Link to an ordered list of MicroscopyOpticalChannel objects containing metadata about the indicator and - filters used to collect this data. - target_type: MicroscopyOpticalChannel - name: imaging_space doc: Link to VolumetricImagingSpace object containing metadata about the region of physical space this imaging data was recorded from. From dd9ecb57d1969f6f0c8b68388a6beeb08b36d1bf Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:38:41 -0400 Subject: [PATCH 15/44] adjust to use full list --- src/pynwb/ndx_microscopy/testing/_mock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 12cf5eb..8c4931d 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -308,9 +308,9 @@ def mock_MultiChannelMicroscopyVolume( name=series_name, description=description, microscope=microscope, - light_sources=light_sources[0], # TODO: figure out how to specify list + light_sources=light_sources, imaging_space=imaging_space, - optical_channels=optical_channels[0], # TODO: figure out how to specify list + optical_channels=optical_channels, data=imaging_data, unit=unit, conversion=conversion, From dbdad41573b1530daf6814d67d65d14432bd4792 Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:39:33 -0400 Subject: [PATCH 16/44] adjust constructor test --- src/pynwb/tests/test_constructors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index fd05c43..b812aec 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -80,8 +80,8 @@ def test_constructor_multi_channel_microscopy_volume(): mock_MultiChannelMicroscopyVolume( microscope=microscope, - light_source=light_source, imaging_space=imaging_space, + light_sources=[light_source], optical_channels=[optical_channel], ) From 963e89464e9efc8eea309ae252fa11670f3bdf63 Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:40:41 -0400 Subject: [PATCH 17/44] reorder kwargs in mock --- src/pynwb/ndx_microscopy/testing/_mock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 8c4931d..ff90e8c 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -291,8 +291,8 @@ def mock_VolumetricMicroscopySeries( def mock_MultiChannelMicroscopyVolume( *, microscope: ndx_microscopy.Microscope, - light_sources: List[ndx_microscopy.MicroscopyLightSource], imaging_space: ndx_microscopy.VolumetricImagingSpace, + light_sources: List[ndx_microscopy.MicroscopyLightSource], optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], name: Optional[str] = None, description: str = "This is a mock instance of a MultiChannelMicroscopyVolume type to be used for rapid testing.", From 0962561544d0cdc12ccbbd7194f6bfbc55d29f03 Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:41:23 -0400 Subject: [PATCH 18/44] adjust kwargs order in mock --- src/pynwb/ndx_microscopy/testing/_mock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index ff90e8c..f744a2c 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -308,8 +308,8 @@ def mock_MultiChannelMicroscopyVolume( name=series_name, description=description, microscope=microscope, - light_sources=light_sources, imaging_space=imaging_space, + light_sources=light_sources, optical_channels=optical_channels, data=imaging_data, unit=unit, From 7a7ae66c81e29035adc16d00256a37f32c3d4bd4 Mon Sep 17 00:00:00 2001 From: CodyCBakerPhD Date: Thu, 11 Jul 2024 14:00:22 -0400 Subject: [PATCH 19/44] Implement lists of object references with tests --- src/pynwb/ndx_microscopy/testing/_mock.py | 5 +-- src/pynwb/tests/test_constructors.py | 2 +- src/pynwb/tests/test_roundtrip.py | 44 ++++++++++++++++------- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index f744a2c..7024cdb 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -2,6 +2,7 @@ from typing import List, Optional, Tuple import numpy as np +import pynwb.base from pynwb.testing.mock.utils import name_generator import ndx_microscopy @@ -292,8 +293,8 @@ def mock_MultiChannelMicroscopyVolume( *, microscope: ndx_microscopy.Microscope, imaging_space: ndx_microscopy.VolumetricImagingSpace, - light_sources: List[ndx_microscopy.MicroscopyLightSource], - optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], + 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, diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index b812aec..721d55b 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -74,7 +74,7 @@ def test_constructor_volumetric_microscopy_series(): def test_constructor_multi_channel_microscopy_volume(): microscope = mock_Microscope() - light_source = mock_LightSource() + light_source = mock_MicroscopyLightSource() imaging_space = mock_VolumetricImagingSpace(microscope=microscope) optical_channel = mock_MicroscopyOpticalChannel() diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 58c320b..b8415a4 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -21,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) @@ -69,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) @@ -119,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) @@ -169,7 +169,7 @@ class TestMultiChannelMicroscopyVolumeSimpleRoundtrip(pynwb_TestCase): """Simple roundtrip test for MultiChannelMicroscopyVolume.""" def setUp(self): - self.nwbfile_path = "test.nwb" + self.nwbfile_path = "test_multi_channel_microscopy_volume_roundtrip.nwb" def tearDown(self): pynwb.testing.remove_test_file(self.nwbfile_path) @@ -180,21 +180,35 @@ def test_roundtrip(self): microscope = mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - light_source = mock_LightSource(name="LightSource") - nwbfile.add_device(devices=light_source) - imaging_space = mock_VolumetricImagingSpace(name="VolumetricImagingSpace", microscope=microscope) 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) + 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, - light_source=light_source, imaging_space=imaging_space, - optical_channels=[optical_channel], + light_sources=light_sources_used_by_volume, + optical_channels=optical_channels_used_by_volume, ) nwbfile.add_acquisition(nwbdata=multi_channel_microscopy_volume) @@ -205,11 +219,15 @@ def test_roundtrip(self): read_nwbfile = io.read() self.assertContainerEqual(microscope, read_nwbfile.devices["Microscope"]) - self.assertContainerEqual(light_source, read_nwbfile.devices["LightSource"]) + self.assertContainerEqual(light_source_0, read_nwbfile.devices["LightSource"]) self.assertContainerEqual(imaging_space, read_nwbfile.lab_meta_data["VolumetricImagingSpace"]) - self.assertContainerEqual(optical_channel, read_nwbfile.lab_meta_data["MicroscopyOpticalChannel"]) + 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 4a6444ac5a30fbeb71678df4071ca75b8d0ebb37 Mon Sep 17 00:00:00 2001 From: CodyCBakerPhD Date: Thu, 11 Jul 2024 14:07:28 -0400 Subject: [PATCH 20/44] Adjust constructor test to match --- src/pynwb/tests/test_constructors.py | 20 ++++++++++++++++---- src/pynwb/tests/test_roundtrip.py | 5 ++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 721d55b..7585c1d 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -2,6 +2,7 @@ import pytest +import pynwb from ndx_microscopy.testing import ( mock_Microscope, mock_MicroscopyLightSource, @@ -74,15 +75,26 @@ def test_constructor_volumetric_microscopy_series(): def test_constructor_multi_channel_microscopy_volume(): microscope = mock_Microscope() - light_source = mock_MicroscopyLightSource() imaging_space = mock_VolumetricImagingSpace(microscope=microscope) - optical_channel = mock_MicroscopyOpticalChannel() + 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_source], - optical_channels=[optical_channel], + light_sources=light_sources_used_by_volume, + optical_channels=optical_channels_used_by_volume, ) diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index b8415a4..530a703 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -200,7 +200,10 @@ def test_roundtrip(self): ) 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.", + 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( From 4912507837e09ee74649f9c805693c40046f5c72 Mon Sep 17 00:00:00 2001 From: CodyCBakerPhD Date: Thu, 11 Jul 2024 14:13:52 -0400 Subject: [PATCH 21/44] fix outer spec to match altered one --- spec/ndx-microscopy.extensions.yaml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index 7e31250..15a6988 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -309,23 +309,17 @@ groups: - null - null - name: light_sources - doc: Reference to an ordered list of MicroscopyLightSource objects containing metadata about the excitation method. + doc: Reference to a list of MicroscopyLightSource objects containing metadata about the excitation methods. + neurodata_type_inc: VectorData dtype: reftype: object target_type: MicroscopyLightSource - dims: - - num_light_sources - shape: - - null - name: optical_channels doc: Reference to an ordered list of MicroscopyOpticalChannel objects containing metadata about the indicator and filters used to collect this data. + neurodata_type_inc: VectorData dtype: reftype: object target_type: MicroscopyOpticalChannel - dims: - - num_channels - shape: - - null links: - name: microscope doc: Link to a Microscope object containing metadata about the device used to acquire this imaging data. From 5b645dee3c6a69de967a275e00ff49e9b6231c45 Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Fri, 12 Jul 2024 11:59:37 -0400 Subject: [PATCH 22/44] Update spec/ndx-microscopy.extensions.yaml --- spec/ndx-microscopy.extensions.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index f2df838..cbc979f 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -464,7 +464,7 @@ groups: - null - null - null - - name: depth_per_frame_in_mm + - name: depth_per_frame_in_um doc: Depth of each frame in the data array. These values offset the 'z' value of the `origin_coordinates` of the linked `imaging_space` object. dtype: numeric From eb9ee22841555ec718a2e845861ba21c91d6130f Mon Sep 17 00:00:00 2001 From: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> Date: Fri, 12 Jul 2024 11:59:50 -0400 Subject: [PATCH 23/44] Update spec/ndx-microscopy.extensions.yaml --- spec/ndx-microscopy.extensions.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ndx-microscopy.extensions.yaml b/spec/ndx-microscopy.extensions.yaml index cbc979f..f2df838 100644 --- a/spec/ndx-microscopy.extensions.yaml +++ b/spec/ndx-microscopy.extensions.yaml @@ -464,7 +464,7 @@ groups: - null - null - null - - name: depth_per_frame_in_um + - name: depth_per_frame_in_mm doc: Depth of each frame in the data array. These values offset the 'z' value of the `origin_coordinates` of the linked `imaging_space` object. dtype: numeric 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 24/44] [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 25/44] 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 26/44] [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, ) From b581087d6c5f88f9c7aca68570a00145a4d47fc2 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:28:31 -0400 Subject: [PATCH 27/44] fix import --- src/pynwb/ndx_microscopy/testing/_mock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 5ab81cc..ce88466 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -118,7 +118,7 @@ def mock_VolumetricImagingSpace( def mock_MicroscopySegmentations( name: Optional[str] = None, - microscopy_plane_segmentations: Optional[Iterable[ndx_microscopy.PlaneSegmentation]] = None, + microscopy_plane_segmentations: Optional[Iterable[ndx_microscopy.MicroscopyPlaneSegmentation]] = None, ) -> ndx_microscopy.MicroscopyImageSegmentation: name = name or name_generator("MicroscopySegmentations") microscopy_plane_segmentations = microscopy_plane_segmentations or [mock_MicroscopyPlaneSegmentation()] From c4e8f3a6deee569ed2b0d94217751c865f3ed1f2 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:30:22 -0400 Subject: [PATCH 28/44] fix import --- src/pynwb/ndx_microscopy/testing/_mock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index ce88466..14c8741 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -119,7 +119,7 @@ def mock_VolumetricImagingSpace( def mock_MicroscopySegmentations( name: Optional[str] = None, microscopy_plane_segmentations: Optional[Iterable[ndx_microscopy.MicroscopyPlaneSegmentation]] = None, -) -> ndx_microscopy.MicroscopyImageSegmentation: +) -> ndx_microscopy.MicroscopySegmentations: name = name or name_generator("MicroscopySegmentations") microscopy_plane_segmentations = microscopy_plane_segmentations or [mock_MicroscopyPlaneSegmentation()] From 93a72a85259e552562d1c3c6b2688efff5f0a7f0 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:32:21 -0400 Subject: [PATCH 29/44] fix import --- src/pynwb/ndx_microscopy/testing/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/__init__.py b/src/pynwb/ndx_microscopy/testing/__init__.py index e88baad..0ebf8a5 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -1,6 +1,6 @@ from ._mock import ( mock_Microscope, - mock_MicroscopyImageSegmentation, + mock_MicroscopySegmentations, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, mock_MicroscopyPlaneSegmentation, @@ -19,7 +19,7 @@ "mock_MicroscopyOpticalChannel", "mock_PlanarImagingSpace", "mock_VolumetricImagingSpace", - "mock_MicroscopyImageSegmentation", + "mock_MicroscopySegmentations", "mock_MicroscopyPlaneSegmentation", "mock_PlanarMicroscopySeries", "mock_VariableDepthMicroscopySeries", From a300f9d7540e6dfcddd1e09a6c757339b7c66dd8 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:32:38 +0000 Subject: [PATCH 30/44] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pynwb/ndx_microscopy/testing/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/testing/__init__.py b/src/pynwb/ndx_microscopy/testing/__init__.py index 0ebf8a5..e27103f 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -1,9 +1,9 @@ from ._mock import ( mock_Microscope, - mock_MicroscopySegmentations, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, mock_MicroscopyPlaneSegmentation, + mock_MicroscopySegmentations, mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, mock_PlanarMicroscopySeries, From 335c81d428cb3a38d3bcb5685cabd288a2248cf2 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:44:49 -0400 Subject: [PATCH 31/44] debug --- src/pynwb/tests/test_constructors.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 2c3d781..b1a2ab7 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -4,7 +4,6 @@ import pynwb from ndx_microscopy.testing import ( - mock_LightSource, mock_Microscope, mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, From 70fa119404a781721f4faab4b467f3648121e6d6 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:48:52 -0400 Subject: [PATCH 32/44] debugs --- src/pynwb/ndx_microscopy/testing/_mock.py | 10 ++++++---- src/pynwb/tests/test_constructors.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 14c8741..ff8bb4d 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -78,7 +78,7 @@ def mock_PlanarImagingSpace( name: Optional[str] = None, description: str = "This is a mock instance of a PlanarImagingSpace type to be used for rapid testing.", origin_coordinates: Tuple[float, float, float] = (-1.2, -0.6, -2), - grid_spacing: Tuple[float, float, float] = (0.2, 0.2), + grid_spacing_in_mm: Tuple[float, float, float] = (0.2, 0.2), location: str = "The location targeted by the mock imaging space.", reference_frame: str = "The reference frame of the mock planar imaging space.", ) -> ndx_microscopy.PlanarImagingSpace: @@ -87,7 +87,7 @@ def mock_PlanarImagingSpace( description=description, microscope=microscope, origin_coordinates=origin_coordinates, - grid_spacing=grid_spacing, + grid_spacing_in_mm=grid_spacing_in_mm, location=location, reference_frame=reference_frame, ) @@ -100,7 +100,7 @@ def mock_VolumetricImagingSpace( name: Optional[str] = None, description: str = "This is a mock instance of a VolumetricImagingSpace type to be used for rapid testing.", origin_coordinates: Tuple[float, float, float] = (-1.2, -0.6, -2), - grid_spacing: Tuple[float, float, float] = (0.2, 0.2, 0.5), + grid_spacing_in_mm: Tuple[float, float, float] = (0.2, 0.2, 0.5), location: str = "The location targeted by the mock imaging space.", reference_frame: str = "The reference frame of the mock volumetric imaging space.", ) -> ndx_microscopy.VolumetricImagingSpace: @@ -109,7 +109,7 @@ def mock_VolumetricImagingSpace( description=description, microscope=microscope, origin_coordinates=origin_coordinates, - grid_spacing=grid_spacing, + grid_spacing_in_mm=grid_spacing_in_mm, location=location, reference_frame=reference_frame, ) @@ -117,6 +117,7 @@ def mock_VolumetricImagingSpace( def mock_MicroscopySegmentations( + *, name: Optional[str] = None, microscopy_plane_segmentations: Optional[Iterable[ndx_microscopy.MicroscopyPlaneSegmentation]] = None, ) -> ndx_microscopy.MicroscopySegmentations: @@ -131,6 +132,7 @@ def mock_MicroscopySegmentations( def mock_MicroscopyPlaneSegmentation( + *, 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.", diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index b1a2ab7..af884f5 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -129,7 +129,7 @@ def test_constructor_multi_channel_microscopy_volume(): def test_constructor_variable_depth_multi_channel_microscopy_volume(): microscope = mock_Microscope() - light_source = mock_LightSource() + light_source = mock_MicroscopyLightSource() imaging_space = mock_VolumetricImagingSpace(microscope=microscope) optical_channel = mock_MicroscopyOpticalChannel() From 5ac7eefd882319102b6bf9fa562252c141ee8cfe Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 15:59:49 -0400 Subject: [PATCH 33/44] debugs --- src/pynwb/ndx_microscopy/testing/_mock.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index ff8bb4d..98b7ad9 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -78,7 +78,7 @@ def mock_PlanarImagingSpace( name: Optional[str] = None, description: str = "This is a mock instance of a PlanarImagingSpace type to be used for rapid testing.", origin_coordinates: Tuple[float, float, float] = (-1.2, -0.6, -2), - grid_spacing_in_mm: Tuple[float, float, float] = (0.2, 0.2), + grid_spacing_in_um: Tuple[float, float, float] = (20, 20), location: str = "The location targeted by the mock imaging space.", reference_frame: str = "The reference frame of the mock planar imaging space.", ) -> ndx_microscopy.PlanarImagingSpace: @@ -87,7 +87,7 @@ def mock_PlanarImagingSpace( description=description, microscope=microscope, origin_coordinates=origin_coordinates, - grid_spacing_in_mm=grid_spacing_in_mm, + grid_spacing_in_um=grid_spacing_in_um, location=location, reference_frame=reference_frame, ) @@ -100,7 +100,7 @@ def mock_VolumetricImagingSpace( name: Optional[str] = None, description: str = "This is a mock instance of a VolumetricImagingSpace type to be used for rapid testing.", origin_coordinates: Tuple[float, float, float] = (-1.2, -0.6, -2), - grid_spacing_in_mm: Tuple[float, float, float] = (0.2, 0.2, 0.5), + grid_spacing_in_um: Tuple[float, float, float] = (20, 20, 50), location: str = "The location targeted by the mock imaging space.", reference_frame: str = "The reference frame of the mock volumetric imaging space.", ) -> ndx_microscopy.VolumetricImagingSpace: @@ -109,7 +109,7 @@ def mock_VolumetricImagingSpace( description=description, microscope=microscope, origin_coordinates=origin_coordinates, - grid_spacing_in_mm=grid_spacing_in_mm, + grid_spacing_in_um=grid_spacing_in_um, location=location, reference_frame=reference_frame, ) From 7effd8ea2927858d1c3d38d6645a48178d07160a Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 17:30:40 -0400 Subject: [PATCH 34/44] debugs --- src/pynwb/ndx_microscopy/testing/_mock.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 98b7ad9..0af0239 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -122,7 +122,12 @@ def mock_MicroscopySegmentations( microscopy_plane_segmentations: Optional[Iterable[ndx_microscopy.MicroscopyPlaneSegmentation]] = None, ) -> ndx_microscopy.MicroscopySegmentations: name = name or name_generator("MicroscopySegmentations") - microscopy_plane_segmentations = microscopy_plane_segmentations or [mock_MicroscopyPlaneSegmentation()] + + microscope = mock_Microscope() + imaging_space = mock_PlanarImagingSpace(microscope=microscope) + microscopy_plane_segmentations = microscopy_plane_segmentations or [ + mock_MicroscopyPlaneSegmentation(imaging_space=imaging_space) + ] segmentations = ndx_microscopy.MicroscopySegmentations( name=name, microscopy_plane_segmentations=microscopy_plane_segmentations @@ -142,11 +147,15 @@ def mock_MicroscopyPlaneSegmentation( name = name or name_generator("MicroscopyPlaneSegmentation") plane_segmentation = ndx_microscopy.MicroscopyPlaneSegmentation( - name=name, description=description, imaging_space=imaging_space + name=name, + description=description, + imaging_space=imaging_space, ) + image_masks = list() for _ in range(number_of_rois): - plane_segmentation.add_roi(image_mask=np.zeros(image_shape, dtype=bool)) + image_masks.append(np.zeros(image_shape, dtype=bool)) + plane_segmentation.add_column(name="image_mask", description="", data=image_masks) return plane_segmentation From 1d6fede3a6692d1c5a256bc1a6b66faec4e0818a Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 17:35:02 -0400 Subject: [PATCH 35/44] debugs --- src/pynwb/ndx_microscopy/testing/_mock.py | 1 + src/pynwb/tests/test_constructors.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 0af0239..6e34605 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -151,6 +151,7 @@ def mock_MicroscopyPlaneSegmentation( description=description, imaging_space=imaging_space, ) + plane_segmentation.add_column(name="id", description="", data=list(range(number_of_rois))) image_masks = list() for _ in range(number_of_rois): diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index af884f5..bf412f3 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -135,8 +135,8 @@ def test_constructor_variable_depth_multi_channel_microscopy_volume(): mock_VariableDepthMultiChannelMicroscopyVolume( microscope=microscope, - light_source=light_source, imaging_space=imaging_space, + light_sources=[light_source], optical_channels=[optical_channel], ) From 1d68a4a222af82e3aa7780f3999d262b0955bc06 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Wed, 17 Jul 2024 17:40:20 -0400 Subject: [PATCH 36/44] debugs --- src/pynwb/tests/test_constructors.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index bf412f3..f5c29aa 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -129,15 +129,26 @@ def test_constructor_multi_channel_microscopy_volume(): def test_constructor_variable_depth_multi_channel_microscopy_volume(): microscope = mock_Microscope() - light_source = mock_MicroscopyLightSource() imaging_space = mock_VolumetricImagingSpace(microscope=microscope) - optical_channel = mock_MicroscopyOpticalChannel() + 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_VariableDepthMultiChannelMicroscopyVolume( microscope=microscope, imaging_space=imaging_space, - light_sources=[light_source], - optical_channels=[optical_channel], + light_sources=light_sources_used_by_volume, + optical_channels=optical_channels_used_by_volume, ) From 5400462f7fac226c13239b8ef9a827fdbc477b7e Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Thu, 18 Jul 2024 13:20:44 -0400 Subject: [PATCH 37/44] debugs --- src/pynwb/ndx_microscopy/testing/_mock.py | 14 ++++++-------- src/pynwb/tests/test_roundtrip.py | 10 ++++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 6e34605..482e308 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -147,11 +147,9 @@ def mock_MicroscopyPlaneSegmentation( name = name or name_generator("MicroscopyPlaneSegmentation") plane_segmentation = ndx_microscopy.MicroscopyPlaneSegmentation( - name=name, - description=description, - imaging_space=imaging_space, + name=name, description=description, imaging_space=imaging_space, id=list(range(number_of_rois)) ) - plane_segmentation.add_column(name="id", description="", data=list(range(number_of_rois))) + # plane_segmentation.add_column(name="id", description="", data=list(range(number_of_rois))) image_masks = list() for _ in range(number_of_rois): @@ -367,9 +365,9 @@ def mock_MultiChannelMicroscopyVolume( def mock_VariableDepthMultiChannelMicroscopyVolume( *, microscope: ndx_microscopy.Microscope, - light_sources: List[ndx_microscopy.MicroscopyLightSource], imaging_space: ndx_microscopy.VolumetricImagingSpace, - optical_channels: List[ndx_microscopy.MicroscopyOpticalChannel], + 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, @@ -392,9 +390,9 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( name=series_name, description=description, microscope=microscope, - light_sources=light_sources[0], # TODO: figure out how to specify list imaging_space=imaging_space, - optical_channels=optical_channels[0], # TODO: figure out how to specify list + light_sources=light_sources, + optical_channels=optical_channels, data=imaging_data, depth_per_frame_in_mm=volume_depth_per_frame_in_mm, unit=unit, diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index ff17ef3..4d9f830 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -247,10 +247,10 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - microscope = mock_Microscope() + microscope = mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - imaging_space = mock_PlanarImagingSpace(microscope=microscope) + imaging_space = mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() plane_segmentation_1 = mock_MicroscopyPlaneSegmentation( @@ -261,8 +261,10 @@ def test_roundtrip(self): ) 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") + segmentations = mock_MicroscopySegmentations( + name="MicroscopySegmentations", microscopy_plane_segmentations=microscopy_plane_segmentations + ) + processing_module = nwbfile.create_processing_module(name="ophys", description="") processing_module.add(segmentations) with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="w") as io: From bb24934261a5bddc70cb1ce1385d89293f0f2562 Mon Sep 17 00:00:00 2001 From: codycbakerphd Date: Thu, 18 Jul 2024 13:31:34 -0400 Subject: [PATCH 38/44] debugs --- src/pynwb/ndx_microscopy/testing/_mock.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 2b5e7a3..dd08d8a 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -223,7 +223,7 @@ def mock_VariableDepthMicroscopySeries( name: Optional[str] = None, description: str = "This is a mock instance of a PlanarMicroscopySeries type to be used for rapid testing.", data: Optional[np.ndarray] = None, - depth_per_frame_in_mm: Optional[np.ndarray] = None, + depth_per_frame_in_um: Optional[np.ndarray] = None, unit: str = "a.u.", conversion: float = 1.0, offset: float = 0.0, @@ -233,10 +233,10 @@ def mock_VariableDepthMicroscopySeries( ) -> ndx_microscopy.VariableDepthMicroscopySeries: series_name = name or name_generator("VariableDepthMicroscopySeries") series_data = data if data is not None else np.ones(shape=(15, 5, 5)) - series_depth_per_frame_in_mm = ( - depth_per_frame_in_mm - if depth_per_frame_in_mm is not None - else np.linspace(start=0.0, stop=1.0, num=series_data.shape[0]) + depth_per_frame_in_um = ( + depth_per_frame_in_um + if depth_per_frame_in_um is not None + else np.linspace(start=0.0, stop=30.0, num=series_data.shape[0]) ) if timestamps is None: @@ -265,7 +265,7 @@ def mock_VariableDepthMicroscopySeries( imaging_space=imaging_space, optical_channel=optical_channel, data=series_data, - depth_per_frame_in_mm=series_depth_per_frame_in_mm, + depth_per_frame_in_um=depth_per_frame_in_um, unit=unit, conversion=conversion, offset=offset, @@ -371,7 +371,7 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( 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, - depth_per_frame_in_mm: Optional[np.ndarray] = None, + depth_per_frame_in_um: Optional[np.ndarray] = None, unit: str = "n.a.", conversion: float = 1.0, offset: float = 0.0, @@ -380,9 +380,9 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( series_data = data if data is not None else np.ones(shape=(15, 5, 5)) volume_depth_per_frame_in_um = ( - depth_per_frame_in_mm - if depth_per_frame_in_mm is not None - else np.linspace(start=0.0, stop=1.0, num=series_data.shape[0]) + depth_per_frame_in_um + if depth_per_frame_in_um is not None + else np.linspace(start=0.0, stop=30.0, num=series_data.shape[0]) ) imaging_data = data if data is not None else np.ones(shape=(10, 20, 7, 3)) From 00a13e0c3f00a75b0b7e9d61728a70ead4063c77 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:13:14 +0000 Subject: [PATCH 39/44] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pynwb/tests/test_constructors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index f6054ff..3366f87 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -151,6 +151,7 @@ def test_constructor_variable_depth_multi_channel_microscopy_volume(): optical_channels=optical_channels_used_by_volume, ) + # TODO: add constructor tests for MicroscopyResponseSeries if __name__ == "__main__": From 4c5fa1e13411e4c5f751395e2c9cdee64647617c Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Tue, 27 Aug 2024 09:58:47 -0400 Subject: [PATCH 40/44] start adding tests --- src/pynwb/ndx_microscopy/testing/_mock.py | 84 ++++++++++++++++++++--- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 60944e2..ea241ec 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -11,7 +11,7 @@ def mock_Microscope( *, name: Optional[str] = None, - description: str = "This is a mock instance of a Microscope type to be used for rapid testing.", + description: str = "A mock instance of a Microscope type to be used for rapid testing.", manufacturer: str = "A fake manufacturer of the mock microscope.", model: str = "A fake model of the mock microscope.", ) -> ndx_microscopy.Microscope: @@ -27,7 +27,7 @@ def mock_Microscope( def mock_MicroscopyLightSource( *, name: Optional[str] = None, - description: str = "This is a mock instance of a MicroscopyLightSource type to be used for rapid testing.", + description: str = "A mock instance of a MicroscopyLightSource type to be used for rapid testing.", manufacturer: str = "A fake manufacturer of the mock light source.", model: str = "A fake model of the mock light source.", filter_description: str = "A description about the fake filter used by the mock light source.", @@ -57,7 +57,7 @@ def mock_MicroscopyLightSource( def mock_MicroscopyOpticalChannel( *, name: Optional[str] = None, - description: str = "This is a mock instance of a MicroscopyOpticalChannel type to be used for rapid testing.", + description: str = "A mock instance of a MicroscopyOpticalChannel type to be used for rapid testing.", indicator: str = "The indicator targeted by the mock optical channel.", filter_description: str = "A description about the fake filter used by the mock optical channel.", emission_wavelength_in_nm: float = 450.0, @@ -76,7 +76,7 @@ def mock_PlanarImagingSpace( *, microscope: ndx_microscopy.Microscope, name: Optional[str] = None, - description: str = "This is a mock instance of a PlanarImagingSpace type to be used for rapid testing.", + description: str = "A mock instance of a PlanarImagingSpace type to be used for rapid testing.", origin_coordinates: Tuple[float, float, float] = (-1.2, -0.6, -2), grid_spacing_in_um: Tuple[float, float, float] = (20, 20), location: str = "The location targeted by the mock imaging space.", @@ -98,7 +98,7 @@ def mock_VolumetricImagingSpace( *, microscope: ndx_microscopy.Microscope, name: Optional[str] = None, - description: str = "This is a mock instance of a VolumetricImagingSpace type to be used for rapid testing.", + description: str = "A mock instance of a VolumetricImagingSpace type to be used for rapid testing.", origin_coordinates: Tuple[float, float, float] = (-1.2, -0.6, -2), grid_spacing_in_um: Tuple[float, float, float] = (20, 20, 50), location: str = "The location targeted by the mock imaging space.", @@ -140,7 +140,7 @@ def mock_MicroscopyPlaneSegmentation( *, 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.", + description: str = "A mock instance of a MicroscopyPlaneSegmentation type to be used for rapid testing.", number_of_rois: int = 5, image_shape: Tuple[int, int] = (10, 10), ) -> ndx_microscopy.MicroscopyPlaneSegmentation: @@ -166,7 +166,7 @@ def mock_PlanarMicroscopySeries( imaging_space: ndx_microscopy.PlanarImagingSpace, optical_channel: ndx_microscopy.MicroscopyOpticalChannel, name: Optional[str] = None, - description: str = "This is a mock instance of a PlanarMicroscopySeries type to be used for rapid testing.", + description: str = "A mock instance of a PlanarMicroscopySeries type to be used for rapid testing.", data: Optional[np.ndarray] = None, unit: str = "a.u.", conversion: float = 1.0, @@ -221,7 +221,7 @@ def mock_VariableDepthMicroscopySeries( imaging_space: ndx_microscopy.PlanarImagingSpace, optical_channel: ndx_microscopy.MicroscopyOpticalChannel, name: Optional[str] = None, - description: str = "This is a mock instance of a PlanarMicroscopySeries type to be used for rapid testing.", + description: str = "A mock instance of a PlanarMicroscopySeries type to be used for rapid testing.", data: Optional[np.ndarray] = None, depth_per_frame_in_um: Optional[np.ndarray] = None, unit: str = "a.u.", @@ -284,7 +284,7 @@ def mock_VolumetricMicroscopySeries( imaging_space: ndx_microscopy.VolumetricImagingSpace, optical_channel: ndx_microscopy.MicroscopyOpticalChannel, name: Optional[str] = None, - description: str = "This is a mock instance of a VolumetricMicroscopySeries type to be used for rapid testing.", + description: str = "A mock instance of a VolumetricMicroscopySeries type to be used for rapid testing.", data: Optional[np.ndarray] = None, unit: str = "a.u.", conversion: float = 1.0, @@ -339,7 +339,7 @@ def mock_MultiChannelMicroscopyVolume( 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.", + description: str = "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, @@ -363,6 +363,68 @@ def mock_MultiChannelMicroscopyVolume( return volumetric_microscopy_series +def mock_MicroscopyResponseSeries( + *, + table_region: pynwb.core.DynamicTableRegion, + name: Optional[str] = None, + description: str = "A mock instance of a MicroscopyResponseSeries type to be used for rapid testing.", + data: Optional[np.ndarray] = None, + unit: str = "a.u.", + conversion: float = 1.0, + offset: float = 0.0, + starting_time: Optional[float] = None, + rate: Optional[float] = None, + timestamps: Optional[np.ndarray] = None, +) -> ndx_microscopy.MicroscopyResponseSeries: + series_name = name or name_generator("MicroscopyResponseSeries") + + response_series = ndx_microscopy.MicroscopyResponseSeries( + name=series_name, + description=description, + table_region=table_region, + data=data, + unit=unit, + conversion=conversion, + offset=offset, + starting_time=starting_time, + rate=rate, + timestamps=timestamps, + ) + + return response_series + + +def mock_MicroscopyResponseSeriesContainer( + *, + table_region: pynwb.core.DynamicTableRegion, + name: Optional[str] = None, + description: str = "A mock instance of a MicroscopyResponseSeriesContainer type to be used for rapid testing.", + data: Optional[np.ndarray] = None, + unit: str = "a.u.", + conversion: float = 1.0, + offset: float = 0.0, + starting_time: Optional[float] = None, + rate: Optional[float] = None, + timestamps: Optional[np.ndarray] = None, +) -> ndx_microscopy.MicroscopyResponseSeriesContainer: + series_name = name or name_generator("MicroscopyResponseSeries") + + response_series = ndx_microscopy.MicroscopyResponseSeries( + name=series_name, + description=description, + table_region=table_region, + data=data, + unit=unit, + conversion=conversion, + offset=offset, + starting_time=starting_time, + rate=rate, + timestamps=timestamps, + ) + + return response_series + + def mock_VariableDepthMultiChannelMicroscopyVolume( *, microscope: ndx_microscopy.Microscope, @@ -370,7 +432,7 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( 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.", + description: str = "A mock instance of a MultiChannelMicroscopyVolume type to be used for rapid testing.", data: Optional[np.ndarray] = None, depth_per_frame_in_um: Optional[np.ndarray] = None, unit: str = "n.a.", From 3d66f799b5432ec727792b4daee8c6e627977574 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Tue, 27 Aug 2024 11:01:34 -0400 Subject: [PATCH 41/44] start adding tests --- src/pynwb/ndx_microscopy/testing/__init__.py | 4 + src/pynwb/ndx_microscopy/testing/_mock.py | 38 ++---- src/pynwb/tests/test_constructors.py | 132 +++++++++++-------- 3 files changed, 90 insertions(+), 84 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/__init__.py b/src/pynwb/ndx_microscopy/testing/__init__.py index e27103f..848c090 100644 --- a/src/pynwb/ndx_microscopy/testing/__init__.py +++ b/src/pynwb/ndx_microscopy/testing/__init__.py @@ -3,6 +3,8 @@ mock_MicroscopyLightSource, mock_MicroscopyOpticalChannel, mock_MicroscopyPlaneSegmentation, + mock_MicroscopyResponseSeries, + mock_MicroscopyResponseSeriesContainer, mock_MicroscopySegmentations, mock_MultiChannelMicroscopyVolume, mock_PlanarImagingSpace, @@ -25,5 +27,7 @@ "mock_VariableDepthMicroscopySeries", "mock_VolumetricMicroscopySeries", "mock_MultiChannelMicroscopyVolume", + "mock_MicroscopyResponseSeries", + "mock_MicroscopyResponseSeriesContainer", "mock_VariableDepthMultiChannelMicroscopyVolume", ] diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index ea241ec..cf1c020 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -378,7 +378,11 @@ def mock_MicroscopyResponseSeries( ) -> ndx_microscopy.MicroscopyResponseSeries: series_name = name or name_generator("MicroscopyResponseSeries") - response_series = ndx_microscopy.MicroscopyResponseSeries( + number_of_frames = 100 + number_of_rois = len(table_region.data) + series_data = data if data is not None else np.ones(shape=(number_of_frames, number_of_rois)) + + microscopy_response_series = ndx_microscopy.MicroscopyResponseSeries( name=series_name, description=description, table_region=table_region, @@ -391,38 +395,21 @@ def mock_MicroscopyResponseSeries( timestamps=timestamps, ) - return response_series + return microscopy_response_series def mock_MicroscopyResponseSeriesContainer( *, - table_region: pynwb.core.DynamicTableRegion, + microscopy_response_series: List[microscopy_response_series], name: Optional[str] = None, - description: str = "A mock instance of a MicroscopyResponseSeriesContainer type to be used for rapid testing.", - data: Optional[np.ndarray] = None, - unit: str = "a.u.", - conversion: float = 1.0, - offset: float = 0.0, - starting_time: Optional[float] = None, - rate: Optional[float] = None, - timestamps: Optional[np.ndarray] = None, ) -> ndx_microscopy.MicroscopyResponseSeriesContainer: - series_name = name or name_generator("MicroscopyResponseSeries") + container_name = name or name_generator("MicroscopyResponseSeriesContainer") - response_series = ndx_microscopy.MicroscopyResponseSeries( - name=series_name, - description=description, - table_region=table_region, - data=data, - unit=unit, - conversion=conversion, - offset=offset, - starting_time=starting_time, - rate=rate, - timestamps=timestamps, + microscopy_response_series_container = ndx_microscopy.MicroscopyResponseSeriesContainer( + name=container_name, microscopy_response_series=microscopy_response_series ) - return response_series + return microscopy_response_series_container def mock_VariableDepthMultiChannelMicroscopyVolume( @@ -464,6 +451,3 @@ def mock_VariableDepthMultiChannelMicroscopyVolume( offset=offset, ) return variable_depth_multi_channel_microscopy_volume - - -# TODO: add mock for MicroscopyResponseSeries diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 3366f87..419612a 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -1,112 +1,132 @@ """Test in-memory Python API constructors for the ndx-microscopy extension.""" +import pynwb.testing.mock.ophys import pytest +import ndx_microscopy.testing import pynwb -from ndx_microscopy.testing import ( - mock_Microscope, - mock_MicroscopyLightSource, - mock_MicroscopyOpticalChannel, - mock_MicroscopyPlaneSegmentation, - mock_MicroscopySegmentations, - mock_MultiChannelMicroscopyVolume, - mock_PlanarImagingSpace, - mock_PlanarMicroscopySeries, - mock_VariableDepthMicroscopySeries, - mock_VariableDepthMultiChannelMicroscopyVolume, - mock_VolumetricImagingSpace, - mock_VolumetricMicroscopySeries, -) def test_constructor_microscope(): - mock_Microscope() + ndx_microscopy.testing.mock_Microscope() def test_constructor_light_source(): - mock_MicroscopyLightSource() + ndx_microscopy.testing.mock_MicroscopyLightSource() def test_constructor_microscopy_optical_channel(): - mock_MicroscopyOpticalChannel() + ndx_microscopy.testing.mock_MicroscopyOpticalChannel() def test_constructor_planar_image_space(): - microscope = mock_Microscope() + microscope = ndx_microscopy.testing.mock_Microscope() - mock_PlanarImagingSpace(microscope=microscope) + ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) def test_constructor_volumetric_image_space(): - microscope = mock_Microscope() + microscope = ndx_microscopy.testing.mock_Microscope() - mock_VolumetricImagingSpace(microscope=microscope) + ndx_microscopy.testing.mock_VolumetricImagingSpace(microscope=microscope) def test_constructor_microscopy_segmentations(): - mock_MicroscopySegmentations() + ndx_microscopy.testing.mock_MicroscopySegmentations() def test_constructor_microscopy_plane_segmentation(): - microscope = mock_Microscope() - imaging_space = mock_PlanarImagingSpace(microscope=microscope) + microscope = ndx_microscopy.testing.mock_Microscope() + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) - mock_MicroscopyPlaneSegmentation(imaging_space=imaging_space) + ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation(imaging_space=imaging_space) def test_constructor_microscopy_image_segmentation_with_plane_segmentation(): - microscope = mock_Microscope() - imaging_space = mock_PlanarImagingSpace(microscope=microscope) + microscope = ndx_microscopy.testing.mock_Microscope() + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) - plane_segmentation_1 = mock_MicroscopyPlaneSegmentation( + plane_segmentation_1 = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( imaging_space=imaging_space, name="MicroscopyPlaneSegmentation1" ) - plane_segmentation_2 = mock_MicroscopyPlaneSegmentation( + plane_segmentation_2 = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( imaging_space=imaging_space, name="MicroscopyPlaneSegmentation2" ) microscopy_plane_segmentations = [plane_segmentation_1, plane_segmentation_2] - mock_MicroscopySegmentations(microscopy_plane_segmentations=microscopy_plane_segmentations) + ndx_microscopy.testing.mock_MicroscopySegmentations(microscopy_plane_segmentations=microscopy_plane_segmentations) def test_constructor_planar_microscopy_series(): - microscope = mock_Microscope() - light_source = mock_MicroscopyLightSource() - imaging_space = mock_PlanarImagingSpace(microscope=microscope) - optical_channel = mock_MicroscopyOpticalChannel() + microscope = ndx_microscopy.testing.mock_Microscope() + light_source = ndx_microscopy.testing.mock_MicroscopyLightSource() + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) + optical_channel = ndx_microscopy.testing.mock_MicroscopyOpticalChannel() - mock_PlanarMicroscopySeries( + ndx_microscopy.testing.mock_PlanarMicroscopySeries( microscope=microscope, light_source=light_source, imaging_space=imaging_space, optical_channel=optical_channel ) def test_constructor_variable_depth_microscopy_series(): - microscope = mock_Microscope() - light_source = mock_MicroscopyLightSource() - imaging_space = mock_PlanarImagingSpace(microscope=microscope) - optical_channel = mock_MicroscopyOpticalChannel() + microscope = ndx_microscopy.testing.mock_Microscope() + light_source = ndx_microscopy.testing.mock_MicroscopyLightSource() + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) + optical_channel = ndx_microscopy.testing.mock_MicroscopyOpticalChannel() - mock_VariableDepthMicroscopySeries( + ndx_microscopy.testing.mock_VariableDepthMicroscopySeries( microscope=microscope, light_source=light_source, imaging_space=imaging_space, optical_channel=optical_channel ) def test_constructor_volumetric_microscopy_series(): - microscope = mock_Microscope() - light_source = mock_MicroscopyLightSource() - imaging_space = mock_VolumetricImagingSpace(microscope=microscope) - optical_channel = mock_MicroscopyOpticalChannel() + microscope = ndx_microscopy.testing.mock_Microscope() + light_source = ndx_microscopy.testing.mock_MicroscopyLightSource() + imaging_space = ndx_microscopy.testing.mock_VolumetricImagingSpace(microscope=microscope) + optical_channel = ndx_microscopy.testing.mock_MicroscopyOpticalChannel() - mock_VolumetricMicroscopySeries( + ndx_microscopy.testing.mock_VolumetricMicroscopySeries( microscope=microscope, light_source=light_source, imaging_space=imaging_space, optical_channel=optical_channel ) +def test_constructor_microscopy_response_series(): + number_of_rois = 10 + + plane_segmentation = pynwb.testing.mock.ophys.mock_PlaneSegmentation() + + table_region = pynwb.core.DynamicTableRegion( + name="table_region", + description="", + data=[x for x in range(number_of_rois)], + table=plane_segmentation, + ) + + ndx_microscopy.testing.mock_MicroscopyResponseSeries(table_region=table_region) + + +def test_constructor_microscopy_response_series_container(): + number_of_rois = 10 + + plane_segmentation = pynwb.testing.mock.ophys.mock_PlaneSegmentation() + + table_region = pynwb.core.DynamicTableRegion( + name="table_region", + description="", + data=[x for x in range(number_of_rois)], + table=plane_segmentation, + ) + + microscopy_response_series = [ndx_microscopy.testing.mock_MicroscopyResponseSeries(table_region=table_region)] + + ndx_microscopy.testing.mock_MicroscopyResponseSeriesContainer(microscopy_response_series=microscopy_response_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()] + microscope = ndx_microscopy.testing.mock_Microscope() + imaging_space = ndx_microscopy.testing.mock_VolumetricImagingSpace(microscope=microscope) + light_sources = [ndx_microscopy.testing.mock_MicroscopyLightSource()] + optical_channels = [ndx_microscopy.testing.mock_MicroscopyOpticalChannel()] light_sources_used_by_volume = pynwb.base.VectorData( name="light_sources", description="Light sources used by this MultiChannelVolume.", data=light_sources @@ -119,7 +139,7 @@ def test_constructor_multi_channel_microscopy_volume(): ), data=optical_channels, ) - mock_MultiChannelMicroscopyVolume( + ndx_microscopy.testing.mock_MultiChannelMicroscopyVolume( microscope=microscope, imaging_space=imaging_space, light_sources=light_sources_used_by_volume, @@ -128,10 +148,10 @@ def test_constructor_multi_channel_microscopy_volume(): def test_constructor_variable_depth_multi_channel_microscopy_volume(): - microscope = mock_Microscope() - imaging_space = mock_VolumetricImagingSpace(microscope=microscope) - light_sources = [mock_MicroscopyLightSource()] - optical_channels = [mock_MicroscopyOpticalChannel()] + microscope = ndx_microscopy.testing.mock_Microscope() + imaging_space = ndx_microscopy.testing.mock_VolumetricImagingSpace(microscope=microscope) + light_sources = [ndx_microscopy.testing.mock_MicroscopyLightSource()] + optical_channels = [ndx_microscopy.testing.mock_MicroscopyOpticalChannel()] light_sources_used_by_volume = pynwb.base.VectorData( name="light_sources", description="Light sources used by this MultiChannelVolume.", data=light_sources @@ -144,7 +164,7 @@ def test_constructor_variable_depth_multi_channel_microscopy_volume(): ), data=optical_channels, ) - mock_VariableDepthMultiChannelMicroscopyVolume( + ndx_microscopy.testing.mock_VariableDepthMultiChannelMicroscopyVolume( microscope=microscope, imaging_space=imaging_space, light_sources=light_sources_used_by_volume, @@ -152,7 +172,5 @@ def test_constructor_variable_depth_multi_channel_microscopy_volume(): ) -# TODO: add constructor tests for MicroscopyResponseSeries - if __name__ == "__main__": pytest.main() # Required since not a typical package structure From 5110cd8d4d9e29a6f8205c4fb4541e3e9e9f6ba5 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Tue, 27 Aug 2024 12:35:10 -0400 Subject: [PATCH 42/44] complete tests --- src/pynwb/ndx_microscopy/testing/_mock.py | 26 ++++- src/pynwb/tests/test_constructors.py | 6 +- src/pynwb/tests/test_roundtrip.py | 123 +++++++++++++++------- 3 files changed, 110 insertions(+), 45 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index cf1c020..168219b 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -382,17 +382,35 @@ def mock_MicroscopyResponseSeries( number_of_rois = len(table_region.data) series_data = data if data is not None else np.ones(shape=(number_of_frames, number_of_rois)) + if timestamps is None: + series_starting_time = starting_time or 0.0 + series_rate = rate or 10.0 + series_timestamps = None + else: + if starting_time is not None or rate is not None: + warnings.warn( + message=( + "Timestamps were provided in addition to either rate or starting_time! " + "Please specify only timestamps, or both starting_time and rate. Timestamps will take precedence." + ), + stacklevel=2, + ) + + series_starting_time = None + series_rate = None + series_timestamps = timestamps + microscopy_response_series = ndx_microscopy.MicroscopyResponseSeries( name=series_name, description=description, table_region=table_region, - data=data, + data=series_data, unit=unit, conversion=conversion, offset=offset, - starting_time=starting_time, - rate=rate, - timestamps=timestamps, + starting_time=series_starting_time, + rate=series_rate, + timestamps=series_timestamps, ) return microscopy_response_series diff --git a/src/pynwb/tests/test_constructors.py b/src/pynwb/tests/test_constructors.py index 419612a..bcbb3cf 100644 --- a/src/pynwb/tests/test_constructors.py +++ b/src/pynwb/tests/test_constructors.py @@ -117,9 +117,11 @@ def test_constructor_microscopy_response_series_container(): table=plane_segmentation, ) - microscopy_response_series = [ndx_microscopy.testing.mock_MicroscopyResponseSeries(table_region=table_region)] + microscopy_response_series = ndx_microscopy.testing.mock_MicroscopyResponseSeries(table_region=table_region) - ndx_microscopy.testing.mock_MicroscopyResponseSeriesContainer(microscopy_response_series=microscopy_response_series) + ndx_microscopy.testing.mock_MicroscopyResponseSeriesContainer( + microscopy_response_series=[microscopy_response_series] + ) def test_constructor_multi_channel_microscopy_volume(): diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index a7b1330..8742507 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -4,20 +4,8 @@ from pynwb.testing import TestCase as pynwb_TestCase from pynwb.testing.mock.file import mock_NWBFile +import ndx_microscopy.testing import pynwb -from ndx_microscopy.testing import ( - mock_Microscope, - mock_MicroscopyLightSource, - mock_MicroscopyOpticalChannel, - mock_MicroscopyPlaneSegmentation, - mock_MicroscopySegmentations, - mock_MultiChannelMicroscopyVolume, - mock_PlanarImagingSpace, - mock_PlanarMicroscopySeries, - mock_VariableDepthMicroscopySeries, - mock_VolumetricImagingSpace, - mock_VolumetricMicroscopySeries, -) class TestPlanarMicroscopySeriesSimpleRoundtrip(pynwb_TestCase): @@ -32,19 +20,19 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - microscope = mock_Microscope(name="Microscope") + microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - light_source = mock_MicroscopyLightSource(name="MicroscopyLightSource") + light_source = ndx_microscopy.testing.mock_MicroscopyLightSource(name="MicroscopyLightSource") nwbfile.add_device(devices=light_source) - imaging_space = mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_spacec() - optical_channel = mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") + optical_channel = ndx_microscopy.testing.mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") nwbfile.add_lab_meta_data(lab_meta_data=optical_channel) - planar_microscopy_series = mock_PlanarMicroscopySeries( + planar_microscopy_series = ndx_microscopy.testing.mock_PlanarMicroscopySeries( name="PlanarMicroscopySeries", microscope=microscope, light_source=light_source, @@ -80,19 +68,21 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - microscope = mock_Microscope(name="Microscope") + microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - light_source = mock_MicroscopyLightSource(name="MicroscopyLightSource") + light_source = ndx_microscopy.testing.mock_MicroscopyLightSource(name="MicroscopyLightSource") nwbfile.add_device(devices=light_source) - imaging_space = mock_VolumetricImagingSpace(name="VolumetricImagingSpace", microscope=microscope) + imaging_space = ndx_microscopy.testing.mock_VolumetricImagingSpace( + name="VolumetricImagingSpace", microscope=microscope + ) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_spacec() - optical_channel = mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") + optical_channel = ndx_microscopy.testing.mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") nwbfile.add_lab_meta_data(lab_meta_data=optical_channel) - volumetric_microscopy_series = mock_VolumetricMicroscopySeries( + volumetric_microscopy_series = ndx_microscopy.testing.mock_VolumetricMicroscopySeries( name="VolumetricMicroscopySeries", microscope=microscope, light_source=light_source, @@ -130,19 +120,19 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - microscope = mock_Microscope(name="Microscope") + microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - light_source = mock_MicroscopyLightSource(name="MicroscopyLightSource") + light_source = ndx_microscopy.testing.mock_MicroscopyLightSource(name="MicroscopyLightSource") nwbfile.add_device(devices=light_source) - imaging_space = mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() - optical_channel = mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") + optical_channel = ndx_microscopy.testing.mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") nwbfile.add_lab_meta_data(lab_meta_data=optical_channel) - variable_depth_microscopy_series = mock_VariableDepthMicroscopySeries( + variable_depth_microscopy_series = ndx_microscopy.testing.mock_VariableDepthMicroscopySeries( name="VariableDepthMicroscopySeries", microscope=microscope, light_source=light_source, @@ -180,19 +170,21 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - microscope = mock_Microscope(name="Microscope") + microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - imaging_space = mock_VolumetricImagingSpace(name="VolumetricImagingSpace", microscope=microscope) + imaging_space = ndx_microscopy.testing.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") + light_source_0 = ndx_microscopy.testing.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") + optical_channel_0 = ndx_microscopy.testing.mock_MicroscopyOpticalChannel(name="MicroscopyOpticalChannel") nwbfile.add_lab_meta_data(lab_meta_data=optical_channel_0) optical_channels.append(optical_channel_0) @@ -209,7 +201,7 @@ def test_roundtrip(self): ), data=optical_channels, ) - multi_channel_microscopy_volume = mock_MultiChannelMicroscopyVolume( + multi_channel_microscopy_volume = ndx_microscopy.testing.mock_MultiChannelMicroscopyVolume( name="MultiChannelMicroscopyVolume", microscope=microscope, imaging_space=imaging_space, @@ -247,21 +239,21 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - microscope = mock_Microscope(name="Microscope") + microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - imaging_space = mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() - plane_segmentation_1 = mock_MicroscopyPlaneSegmentation( + plane_segmentation_1 = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( imaging_space=imaging_space, name="MicroscopyPlaneSegmentation1" ) - plane_segmentation_2 = mock_MicroscopyPlaneSegmentation( + plane_segmentation_2 = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( imaging_space=imaging_space, name="MicroscopyPlaneSegmentation2" ) microscopy_plane_segmentations = [plane_segmentation_1, plane_segmentation_2] - segmentations = mock_MicroscopySegmentations( + segmentations = ndx_microscopy.testing.mock_MicroscopySegmentations( name="MicroscopySegmentations", microscopy_plane_segmentations=microscopy_plane_segmentations ) processing_module = nwbfile.create_processing_module(name="ophys", description="") @@ -280,7 +272,60 @@ def test_roundtrip(self): self.assertContainerEqual(segmentations, read_nwbfile.processing["ophys"]["MicroscopySegmentations"]) -# TODO: add roundtrip test for MicroscopyResponseSeries +class TestMicroscopyResponseSeriesSimpleRoundtrip(pynwb_TestCase): + """Simple roundtrip test for MicroscopyResponseSeries.""" + + def setUp(self): + self.nwbfile_path = "test_microscopy_response_series_roundtrip.nwb" + + def tearDown(self): + pynwb.testing.remove_test_file(self.nwbfile_path) + + def test_roundtrip(self): + nwbfile = mock_NWBFile() + + ophys_module = nwbfile.create_processing_module(name="ophys", description="Optical neurophysiology data.") + + microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") + nwbfile.add_device(devices=microscope) + + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(device=device) + nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() + + plane_segmentation = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( + name="MicroscopyPlaneSegmentation", imaging_space=imaging_space + ) + ophys_module.add(plane_segmentation) + + number_of_rois = 10 + plane_segmentation_region = pynwb.ophys.DynamicTableRegion( + name="table_region", # Name must be exactly this + description="", + data=[x for x in range(number_of_rois)], + table=plane_segmentation, + ) + microscopy_response_series = ndx_microscopy.testing.mock_MicroscopyResponseSeries( + name="MicroscopyResponseSeries", + table_region=plane_segmentation_region, + ) + + container = ndx_microscopy.MicroscopyResponseSeriesContainer( + name="MicroscopyResponseSeriesContainer", microscopy_response_series=[microscopy_response_series] + ) + + 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"]) + + self.assertContainerEqual(container, read_nwbfile.processing["ophys"]["MicroscopyResponseSeriesContainer"]) if __name__ == "__main__": From 8b0fe29f8f86b66d79080461c445500875627e8d Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Tue, 27 Aug 2024 12:43:00 -0400 Subject: [PATCH 43/44] debug --- src/pynwb/ndx_microscopy/testing/_mock.py | 2 +- src/pynwb/tests/test_roundtrip.py | 27 ++++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/pynwb/ndx_microscopy/testing/_mock.py b/src/pynwb/ndx_microscopy/testing/_mock.py index 168219b..cb7d919 100644 --- a/src/pynwb/ndx_microscopy/testing/_mock.py +++ b/src/pynwb/ndx_microscopy/testing/_mock.py @@ -418,7 +418,7 @@ def mock_MicroscopyResponseSeries( def mock_MicroscopyResponseSeriesContainer( *, - microscopy_response_series: List[microscopy_response_series], + microscopy_response_series: List[ndx_microscopy.MicroscopyResponseSeries], name: Optional[str] = None, ) -> ndx_microscopy.MicroscopyResponseSeriesContainer: container_name = name or name_generator("MicroscopyResponseSeriesContainer") diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 8742507..2263d6f 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -256,8 +256,8 @@ def test_roundtrip(self): segmentations = ndx_microscopy.testing.mock_MicroscopySegmentations( name="MicroscopySegmentations", microscopy_plane_segmentations=microscopy_plane_segmentations ) - processing_module = nwbfile.create_processing_module(name="ophys", description="") - processing_module.add(segmentations) + ophys_module = nwbfile.create_processing_module(name="ophys", description="") + ophys_module.add(segmentations) with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="w") as io: io.write(nwbfile) @@ -284,34 +284,38 @@ def tearDown(self): def test_roundtrip(self): nwbfile = mock_NWBFile() - ophys_module = nwbfile.create_processing_module(name="ophys", description="Optical neurophysiology data.") - microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(device=device) + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() - plane_segmentation = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( + microscopy_plane_segmentations = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation( name="MicroscopyPlaneSegmentation", imaging_space=imaging_space ) - ophys_module.add(plane_segmentation) + + segmentations = ndx_microscopy.testing.mock_MicroscopySegmentations( + name="MicroscopySegmentations", microscopy_plane_segmentations=[microscopy_plane_segmentations] + ) + ophys_module = nwbfile.create_processing_module(name="ophys", description="") + ophys_module.add(segmentations) number_of_rois = 10 plane_segmentation_region = pynwb.ophys.DynamicTableRegion( name="table_region", # Name must be exactly this description="", data=[x for x in range(number_of_rois)], - table=plane_segmentation, + table=microscopy_plane_segmentations, ) microscopy_response_series = ndx_microscopy.testing.mock_MicroscopyResponseSeries( name="MicroscopyResponseSeries", table_region=plane_segmentation_region, ) - container = ndx_microscopy.MicroscopyResponseSeriesContainer( + microscopy_response_series_container = ndx_microscopy.MicroscopyResponseSeriesContainer( name="MicroscopyResponseSeriesContainer", microscopy_response_series=[microscopy_response_series] ) + ophys_module.add(microscopy_response_series_container) with pynwb.NWBHDF5IO(path=self.nwbfile_path, mode="w") as io: io.write(nwbfile) @@ -325,7 +329,10 @@ def test_roundtrip(self): self.assertContainerEqual(segmentations, read_nwbfile.processing["ophys"]["MicroscopySegmentations"]) - self.assertContainerEqual(container, read_nwbfile.processing["ophys"]["MicroscopyResponseSeriesContainer"]) + self.assertContainerEqual( + microscopy_response_series_container, + read_nwbfile.processing["ophys"]["MicroscopyResponseSeriesContainer"], + ) if __name__ == "__main__": From c0244905d129a17b4d16ec2ade1849ad1c588fe8 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Tue, 27 Aug 2024 14:21:04 -0400 Subject: [PATCH 44/44] debug --- src/pynwb/tests/test_roundtrip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/tests/test_roundtrip.py b/src/pynwb/tests/test_roundtrip.py index 2263d6f..80d6c54 100644 --- a/src/pynwb/tests/test_roundtrip.py +++ b/src/pynwb/tests/test_roundtrip.py @@ -287,7 +287,7 @@ def test_roundtrip(self): microscope = ndx_microscopy.testing.mock_Microscope(name="Microscope") nwbfile.add_device(devices=microscope) - imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(microscope=microscope) + imaging_space = ndx_microscopy.testing.mock_PlanarImagingSpace(name="PlanarImagingSpace", microscope=microscope) nwbfile.add_lab_meta_data(lab_meta_data=imaging_space) # Would prefer .add_imaging_space() microscopy_plane_segmentations = ndx_microscopy.testing.mock_MicroscopyPlaneSegmentation(