Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
alessandratrapani committed Dec 3, 2024
2 parents 7955601 + 6f5ceae commit 65ba204
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 16 deletions.
3 changes: 2 additions & 1 deletion requirements-min.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pynwb
ndx-ophys-devices git+https://github.com/catalystneuro/ndx-ophys-devices.git@create_specs
git+https://github.com/catalystneuro/ndx-ophys-devices.git@main#egg=ndx-ophys-devices

28 changes: 28 additions & 0 deletions spec/ndx-microscopy.extensions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,31 @@ 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: 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: '+'
8 changes: 7 additions & 1 deletion src/pynwb/ndx_microscopy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os

from pynwb import get_class, load_namespaces

from pynwb.spec import NWBNamespaceBuilder
try:
from importlib.resources import files
except ImportError:
Expand Down Expand Up @@ -36,6 +36,10 @@
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__ = [
"OpticalFilter",
"ExcitationSource",
Expand All @@ -53,4 +57,6 @@
"VolumetricMicroscopySeries",
"MultiChannelMicroscopyVolume",
"VariableDepthMultiChannelMicroscopyVolume",
"MicroscopyResponseSeries",
"MicroscopyResponseSeriesContainer",
]
4 changes: 4 additions & 0 deletions src/pynwb/ndx_microscopy/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
mock_ExcitationLightPath,
mock_Microscope,
mock_MicroscopyPlaneSegmentation,
mock_MicroscopyResponseSeries,
mock_MicroscopyResponseSeriesContainer,
mock_MicroscopySegmentations,
mock_MultiChannelMicroscopyVolume,
mock_PlanarImagingSpace,
Expand All @@ -25,5 +27,7 @@
"mock_VariableDepthMicroscopySeries",
"mock_VolumetricMicroscopySeries",
"mock_MultiChannelMicroscopyVolume",
"mock_MicroscopyResponseSeries",
"mock_MicroscopyResponseSeriesContainer",
"mock_VariableDepthMultiChannelMicroscopyVolume",
]
89 changes: 78 additions & 11 deletions src/pynwb/ndx_microscopy/testing/_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,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:
Expand All @@ -34,7 +34,7 @@ def mock_Microscope(
def mock_ExcitationLightPath(
*,
name: Optional[str] = None,
description: str = "This is a mock instance of a ExcitationLightPath type to be used for rapid testing.",
description: str = "A mock instance of a ExcitationLightPath type to be used for rapid testing.",
excitation_wavelength_in_nm: float = 500.0,
excitation_source: ExcitationSource = None,
excitation_filter: OpticalFilter = None,
Expand All @@ -52,7 +52,7 @@ def mock_ExcitationLightPath(
def mock_EmissionLightPath(
*,
name: Optional[str] = None,
description: str = "This is a mock instance of a EmissionLightPath type to be used for rapid testing.",
description: str = "A mock instance of a EmissionLightPath type to be used for rapid testing.",
indicator: Indicator = None,
photodetector: Photodetector = None,
emission_filter: OpticalFilter = None,
Expand All @@ -72,7 +72,7 @@ def mock_EmissionLightPath(
def mock_PlanarImagingSpace(
*,
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.",
Expand All @@ -92,7 +92,7 @@ def mock_PlanarImagingSpace(
def mock_VolumetricImagingSpace(
*,
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.",
Expand Down Expand Up @@ -131,7 +131,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:
Expand All @@ -157,7 +157,7 @@ def mock_PlanarMicroscopySeries(
imaging_space: ndx_microscopy.PlanarImagingSpace,
emission_light_path: ndx_microscopy.EmissionLightPath,
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,
Expand Down Expand Up @@ -212,7 +212,7 @@ def mock_VariableDepthMicroscopySeries(
imaging_space: ndx_microscopy.PlanarImagingSpace,
emission_light_path: ndx_microscopy.EmissionLightPath,
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.",
Expand Down Expand Up @@ -275,7 +275,7 @@ def mock_VolumetricMicroscopySeries(
imaging_space: ndx_microscopy.VolumetricImagingSpace,
emission_light_path: ndx_microscopy.EmissionLightPath,
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,
Expand Down Expand Up @@ -330,7 +330,7 @@ def mock_MultiChannelMicroscopyVolume(
excitation_light_paths: pynwb.base.VectorData,
emission_light_paths: 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,
Expand All @@ -354,14 +354,81 @@ 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")

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))

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=series_data,
unit=unit,
conversion=conversion,
offset=offset,
starting_time=series_starting_time,
rate=series_rate,
timestamps=series_timestamps,
)

return microscopy_response_series


def mock_MicroscopyResponseSeriesContainer(
*,
microscopy_response_series: List[ndx_microscopy.MicroscopyResponseSeries],
name: Optional[str] = None,
) -> ndx_microscopy.MicroscopyResponseSeriesContainer:
container_name = name or name_generator("MicroscopyResponseSeriesContainer")

microscopy_response_series_container = ndx_microscopy.MicroscopyResponseSeriesContainer(
name=container_name, microscopy_response_series=microscopy_response_series
)

return microscopy_response_series_container


def mock_VariableDepthMultiChannelMicroscopyVolume(
*,
microscope: ndx_microscopy.Microscope,
imaging_space: ndx_microscopy.VolumetricImagingSpace,
excitation_light_paths: pynwb.base.VectorData,
emission_light_paths: 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.",
Expand Down
37 changes: 37 additions & 0 deletions src/pynwb/tests/test_constructors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Test in-memory Python API constructors for the ndx-microscopy extension."""

import pynwb.testing.mock.ophys
import pytest

import pynwb
Expand All @@ -9,6 +10,8 @@
mock_Microscope,
mock_MicroscopyPlaneSegmentation,
mock_MicroscopySegmentations,
mock_MicroscopyResponseSeries,
mock_MicroscopyResponseSeriesContainer,
mock_MultiChannelMicroscopyVolume,
mock_PlanarImagingSpace,
mock_PlanarMicroscopySeries,
Expand Down Expand Up @@ -103,6 +106,40 @@ def test_constructor_volumetric_microscopy_series():
)


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,
)

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 = mock_MicroscopyResponseSeries(table_region=table_region)

mock_MicroscopyResponseSeriesContainer(
microscopy_response_series=[microscopy_response_series]
)


def test_constructor_multi_channel_microscopy_volume():
microscope = mock_Microscope()
imaging_space = mock_VolumetricImagingSpace()
Expand Down
Loading

0 comments on commit 65ba204

Please sign in to comment.