Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change identifier of plane to plane_segmentation_name #623

Merged
merged 13 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* Added alignment methods support to `MockRecordingInterface` [PR #611](https://github.com/catalystneuro/neuroconv/pull/611)
* Added `NeuralynxNvtInterface`, which can read position tracking NVT files. [PR #580](https://github.com/catalystneuro/neuroconv/pull/580)
* Adding radius as a conversion factor in `FicTracDataInterface`. [PR #619](https://github.com/catalystneuro/neuroconv/pull/619)
* Added `plane_segmentation_name` keyword argument to determine which plane segmentation to add from the metadata by name instead of `plane_segmentation_index`.
`plane_segmentation_name` is exposed at `BaseSegmentationExtractorInterface.add_to_nwbfile()` function to support adding segmentation output from multiple planes. [PR #623](https://github.com/catalystneuro/neuroconv/pull/623)

### Fixes
* Remove `starting_time` reset to default value (0.0) when adding the rate and updating the `photon_series_kwargs` or `roi_response_series_kwargs`, in `add_photon_series` or `add_fluorescence_traces`. [PR #595](https://github.com/catalystneuro/neuroconv/pull/595)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def add_to_nwbfile(
include_roi_centroids: bool = True,
include_roi_acceptance: bool = True,
mask_type: Optional[str] = "image", # Literal["image", "pixel", "voxel"]
plane_segmentation_name: Optional[str] = None,
iterator_options: Optional[dict] = None,
compression_options: Optional[dict] = None,
):
Expand Down Expand Up @@ -112,6 +113,8 @@ def add_to_nwbfile(
Specify your choice between these three as mask_type='image', 'pixel', 'voxel', or None.
If None, the mask information is not written to the NWB file.
Defaults to 'image'.
plane_segmentation_name : str, optional
The name of the plane segmentation to be added.
iterator_options : dict, optional
The options to use when iterating over the image masks of the segmentation extractor.
compression_options : dict, optional
Expand All @@ -136,6 +139,7 @@ def add_to_nwbfile(
include_roi_centroids=include_roi_centroids,
include_roi_acceptance=include_roi_acceptance,
mask_type=mask_type,
plane_segmentation_name=plane_segmentation_name,
iterator_options=iterator_options,
compression_options=compression_options,
)
105 changes: 80 additions & 25 deletions src/neuroconv/tools/roiextractors/roiextractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,8 @@ def add_plane_segmentation(
segmentation_extractor: SegmentationExtractor,
nwbfile: NWBFile,
metadata: Optional[dict],
plane_segmentation_index: int = 0,
plane_segmentation_name: Optional[str] = None,
plane_segmentation_index: Optional[int] = None, # TODO: to be removed
include_roi_centroids: bool = True,
include_roi_acceptance: bool = True,
mask_type: Optional[str] = "image", # Optional[Literal["image", "pixel"]]
Expand All @@ -676,8 +677,8 @@ def add_plane_segmentation(
The NWBFile to add the plane segmentation to.
metadata : dict, optional
The metadata for the plane segmentation.
plane_segmentation_index : int, optional
The index of the plane segmentation to add.
plane_segmentation_name : str, optional
The name of the plane segmentation to be added.
include_roi_centroids : bool, default: True
Whether to include the ROI centroids on the PlaneSegmentation table.
If there are a very large number of ROIs (such as in whole-brain recordings),
Expand Down Expand Up @@ -721,8 +722,26 @@ def add_plane_segmentation(
metadata_copy = dict_deep_update(default_metadata, metadata_copy, append_list=False)

image_segmentation_metadata = metadata_copy["Ophys"]["ImageSegmentation"]
plane_segmentation_metadata = image_segmentation_metadata["plane_segmentations"][plane_segmentation_index]
plane_segmentation_name = plane_segmentation_metadata["name"]
plane_segmentation_name = (
plane_segmentation_name or default_metadata["Ophys"]["ImageSegmentation"]["plane_segmentations"][0]["name"]
)
if plane_segmentation_index:
warn(
"Keyword argument 'plane_segmentation_index' is deprecated and it will be removed on 2024-04-16. Use 'plane_segmentation_name' instead."
)
plane_segmentation_name = image_segmentation_metadata["plane_segmentations"][plane_segmentation_index]["name"]
plane_segmentation_metadata = next(
(
plane_segmentation_metadata
for plane_segmentation_metadata in image_segmentation_metadata["plane_segmentations"]
if plane_segmentation_metadata["name"] == plane_segmentation_name
),
None,
)
if plane_segmentation_metadata is None:
raise ValueError(
f"Metadata for Plane Segmentation '{plane_segmentation_name}' not found in metadata['Ophys']['ImageSegmentation']['plane_segmentations']."
)

imaging_plane_name = plane_segmentation_metadata["imaging_plane"]
add_imaging_plane(nwbfile=nwbfile, metadata=metadata_copy, imaging_plane_name=imaging_plane_name)
Expand All @@ -740,10 +759,7 @@ def add_plane_segmentation(
accepted_ids = [int(roi_id in segmentation_extractor.get_accepted_list()) for roi_id in roi_ids]
rejected_ids = [int(roi_id in segmentation_extractor.get_rejected_list()) for roi_id in roi_ids]

imaging_plane_metadata = metadata_copy["Ophys"]["ImagingPlane"][plane_segmentation_index]
imaging_plane_name = imaging_plane_metadata["name"]
imaging_plane = nwbfile.imaging_planes[imaging_plane_name]

plane_segmentation_kwargs = deepcopy(plane_segmentation_metadata)
plane_segmentation_kwargs.update(imaging_plane=imaging_plane)
if mask_type is None:
Expand Down Expand Up @@ -812,7 +828,8 @@ def add_fluorescence_traces(
segmentation_extractor: SegmentationExtractor,
nwbfile: NWBFile,
metadata: Optional[dict],
plane_index: int = 0,
plane_segmentation_name: Optional[str] = None,
plane_index: Optional[int] = None, # TODO: to be removed
iterator_options: Optional[dict] = None,
compression_options: Optional[dict] = None,
) -> NWBFile:
Expand All @@ -829,8 +846,8 @@ def add_fluorescence_traces(
The nwbfile to add the fluorescence traces to.
metadata : dict
The metadata for the fluorescence traces.
plane_index : int, default: 0
The index of the plane to add the fluorescence traces to.
plane_segmentation_name : str, optional
The name of the plane segmentation that identifies which plane to add the fluorescence traces to.
iterator_options : dict, optional
compression_options : dict, optional

Expand All @@ -847,6 +864,16 @@ def add_fluorescence_traces(
default_metadata = get_default_segmentation_metadata()
metadata_copy = dict_deep_update(default_metadata, metadata_copy, append_list=False)

if plane_index:
warn(
"Keyword argument 'plane_index' is deprecated and it will be removed on 2024-04-16. Use 'plane_segmentation_name' instead."
)
plane_segmentation_name = metadata_copy["Ophys"]["ImageSegmentation"]["plane_segmentations"][plane_index][
"name"
]
plane_segmentation_name = (
plane_segmentation_name or default_metadata["Ophys"]["ImageSegmentation"]["plane_segmentations"][0]["name"]
)
# df/F metadata
df_over_f_metadata = metadata_copy["Ophys"]["DfOverF"]
df_over_f_name = df_over_f_metadata["name"]
Expand Down Expand Up @@ -874,7 +901,7 @@ def add_fluorescence_traces(
segmentation_extractor=segmentation_extractor,
nwbfile=nwbfile,
metadata=metadata_copy,
plane_index=plane_index,
plane_segmentation_name=plane_segmentation_name,
)

roi_response_series_kwargs = dict(rois=roi_table_region, unit="n.a.")
Expand Down Expand Up @@ -912,16 +939,18 @@ def add_fluorescence_traces(
# The name of the roi_response_series is "RoiResponseSeries" for raw and df/F traces,
# otherwise it is capitalized trace_name.
trace_name = "RoiResponseSeries" if trace_name in ["raw", "dff"] else trace_name.capitalize()
trace_name = trace_name if plane_index == 0 else trace_name + f"_Plane{plane_index}"

if trace_name in data_interface.roi_response_series:
continue

data_interface_metadata = df_over_f_metadata if isinstance(data_interface, DfOverF) else fluorescence_metadata
response_series_metadata = data_interface_metadata["roi_response_series"]
trace_metadata = next(
trace_metadata for trace_metadata in response_series_metadata if trace_name == trace_metadata["name"]
(trace_metadata for trace_metadata in response_series_metadata if trace_name == trace_metadata["name"]),
None,
)
if trace_metadata is None:
raise ValueError(f"Metadata for '{trace_name}' trace not found in {response_series_metadata}.")

# Pop the rate from the metadata if irregular time series
if "timestamps" in roi_response_series_kwargs and "rate" in trace_metadata:
Expand All @@ -945,25 +974,51 @@ def _create_roi_table_region(
segmentation_extractor: SegmentationExtractor,
nwbfile: NWBFile,
metadata: dict,
plane_index: int,
plane_segmentation_name: Optional[str] = None,
plane_index: Optional[int] = None,
):
"""Private method to create ROI table region."""
add_plane_segmentation(segmentation_extractor=segmentation_extractor, nwbfile=nwbfile, metadata=metadata)
"""Private method to create ROI table region.

# Get plane segmentation from the image segmentation
Parameters
----------
segmentation_extractor : SegmentationExtractor
The segmentation extractor to get the results from.
nwbfile : NWBFile
The NWBFile to add the plane segmentation to.
metadata : dict, optional
The metadata for the plane segmentation.
plane_segmentation_name : str, optional
The name of the plane segmentation that identifies which plane to add the ROI table region to.
"""
image_segmentation_metadata = metadata["Ophys"]["ImageSegmentation"]

if plane_index:
warn(
"Keyword argument 'plane_index' is deprecated and it will be removed on 2024-04-16. Use 'plane_segmentation_name' instead."
)
plane_segmentation_name = image_segmentation_metadata["plane_segmentations"][plane_index]["name"]

add_plane_segmentation(
segmentation_extractor=segmentation_extractor,
nwbfile=nwbfile,
metadata=metadata,
plane_segmentation_name=plane_segmentation_name,
)

image_segmentation_name = image_segmentation_metadata["name"]
ophys = get_module(nwbfile, "ophys")
image_segmentation = ophys.get_data_interface(image_segmentation_name)

plane_segmentation_name = image_segmentation_metadata["plane_segmentations"][0]["name"]
# Get plane segmentation from the image segmentation
plane_segmentation = image_segmentation.plane_segmentations[plane_segmentation_name]

# Create a reference for ROIs from the plane segmentation
id_list = list(plane_segmentation.id)

imaging_plane_name = plane_segmentation.imaging_plane.name
roi_table_region = plane_segmentation.create_roi_table_region(
region=[id_list.index(id) for id in segmentation_extractor.get_roi_ids()],
description=f"region for Imaging plane{plane_index}",
description=f"The ROIs for {imaging_plane_name}.",
)

return roi_table_region
Expand Down Expand Up @@ -1032,7 +1087,8 @@ def add_segmentation(
segmentation_extractor: SegmentationExtractor,
nwbfile: NWBFile,
metadata: Optional[dict] = None,
plane_num: int = 0,
plane_segmentation_name: Optional[str] = None,
plane_num: Optional[int] = None, # TODO: to be removed
include_roi_centroids: bool = True,
include_roi_acceptance: bool = True,
mask_type: Optional[str] = "image", # Literal["image", "pixel"]
Expand All @@ -1042,14 +1098,12 @@ def add_segmentation(
# Add device:
add_devices(nwbfile=nwbfile, metadata=metadata)

CodyCBakerPhD marked this conversation as resolved.
Show resolved Hide resolved
# Add imaging plane
add_imaging_plane(nwbfile=nwbfile, metadata=metadata)

# PlaneSegmentation:
CodyCBakerPhD marked this conversation as resolved.
Show resolved Hide resolved
# Add PlaneSegmentation:
add_plane_segmentation(
segmentation_extractor=segmentation_extractor,
nwbfile=nwbfile,
metadata=metadata,
plane_segmentation_name=plane_segmentation_name,
include_roi_centroids=include_roi_centroids,
include_roi_acceptance=include_roi_acceptance,
mask_type=mask_type,
Expand All @@ -1062,6 +1116,7 @@ def add_segmentation(
segmentation_extractor=segmentation_extractor,
nwbfile=nwbfile,
metadata=metadata,
plane_segmentation_name=plane_segmentation_name,
iterator_options=iterator_options,
compression_options=compression_options,
)
Expand Down
Loading
Loading