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

Add always_write_timestamps conversion option to imaging interfaces #1125

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## Bug Fixes

## Features
* Imaging interfaces have a new conversion option `always_write_timestamps` that can be used to force writing timestamps even if neuroconv's heuristics indicates regular sampling rate [PR #1125](https://github.com/catalystneuro/neuroconv/pull/1125)

## Improvements

Expand Down Expand Up @@ -45,7 +46,7 @@
* Added automated EFS volume creation and mounting to the `submit_aws_job` helper function. [PR #1018](https://github.com/catalystneuro/neuroconv/pull/1018)
* Added a mock for segmentation extractors interfaces in ophys: `MockSegmentationInterface` [PR #1067](https://github.com/catalystneuro/neuroconv/pull/1067)
* Added a `MockSortingInterface` for testing purposes. [PR #1065](https://github.com/catalystneuro/neuroconv/pull/1065)
* BaseRecordingInterfaces have a new conversion options `always_write_timestamps` that ca be used to force writing timestamps even if neuroconv heuristic indicates regular sampling rate [PR #1091](https://github.com/catalystneuro/neuroconv/pull/1091)
* BaseRecordingInterfaces have a new conversion options `always_write_timestamps` that can be used to force writing timestamps even if neuroconv heuristic indicates regular sampling rate [PR #1091](https://github.com/catalystneuro/neuroconv/pull/1091)


## Improvements
Expand Down
26 changes: 13 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -270,50 +270,50 @@ icephys = [

## Ophys
brukertiff = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
"tifffile>=2023.3.21",
]
caiman = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
cnmfe = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
extract = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
hdf5 = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
micromanagertiff = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
"tifffile>=2023.3.21",
]
miniscope = [
"natsort>=8.3.1",
"ndx-miniscope>=0.5.1",
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
sbx = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
scanimage = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
"scanimage-tiff-reader>=1.4.1",
]
sima = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
suite2p = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
]
tdt_fp = [
"ndx-fiber-photometry",
"roiextractors>=0.5.7",
"roiextractors>=0.5.10",
"tdt",
]
tiff = [
"roiextractors>=0.5.7",
"roiextractors>=0.5.9",
"tiffile>=2018.10.18",
]
ophys = [
Expand Down
13 changes: 0 additions & 13 deletions src/neuroconv/datainterfaces/behavior/video/videodatainterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,6 @@ def add_to_nwbfile(
chunk_data: bool = True,
module_name: Optional[str] = None,
module_description: Optional[str] = None,
compression: Optional[str] = "gzip",
compression_options: Optional[int] = None,
):
"""
Convert the video data files to :py:class:`~pynwb.image.ImageSeries` and write them in the
Expand Down Expand Up @@ -431,17 +429,6 @@ def add_to_nwbfile(
pbar.update(1)
iterable = video

# TODO: remove completely after 03/1/2024
if compression is not None or compression_options is not None:
warnings.warn(
message=(
"Specifying compression methods and their options for this interface has been deprecated. "
"Please use the `configure_backend` tool function for this purpose."
),
category=DeprecationWarning,
stacklevel=2,
)

image_series_kwargs.update(data=iterable)

if timing_type == "starting_time and rate":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ def add_to_nwbfile(
parent_container: Literal["acquisition", "processing/ophys"] = "acquisition",
stub_test: bool = False,
stub_frames: int = 100,
always_write_timestamps: bool = False,
):
from ...tools.roiextractors import add_imaging_to_nwbfile

Expand All @@ -162,4 +163,5 @@ def add_to_nwbfile(
photon_series_type=photon_series_type,
photon_series_index=photon_series_index,
parent_container=parent_container,
always_write_timestamps=always_write_timestamps,
)
34 changes: 27 additions & 7 deletions src/neuroconv/tools/roiextractors/roiextractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ def add_photon_series_to_nwbfile(
parent_container: Literal["acquisition", "processing/ophys"] = "acquisition",
iterator_type: Optional[str] = "v2",
iterator_options: Optional[dict] = None,
always_write_timestamps: bool = False,
) -> NWBFile:
"""
Auxiliary static method for nwbextractor.
Expand Down Expand Up @@ -472,6 +473,11 @@ def add_photon_series_to_nwbfile(
iterator_type: str, default: 'v2'
The type of iterator to use when adding the photon series to the NWB file.
iterator_options: dict, optional
always_write_timestamps : bool, default: False
Set to True to always write timestamps.
By default (False), the function checks if the timestamps are uniformly sampled, and if so, stores the data
using a regular sampling rate instead of explicit timestamps. If set to True, timestamps will be written
explicitly, regardless of whether the sampling rate is uniform.

Returns
-------
Expand Down Expand Up @@ -530,16 +536,23 @@ def add_photon_series_to_nwbfile(
photon_series_kwargs.update(dimension=imaging.get_image_size())

# Add timestamps or rate
if imaging.has_time_vector():
if always_write_timestamps:
timestamps = imaging.frame_to_time(np.arange(imaging.get_num_frames()))
estimated_rate = calculate_regular_series_rate(series=timestamps)
photon_series_kwargs.update(timestamps=timestamps)
else:
imaging_has_timestamps = imaging.has_time_vector()
if imaging_has_timestamps:
timestamps = imaging.frame_to_time(np.arange(imaging.get_num_frames()))
estimated_rate = calculate_regular_series_rate(series=timestamps)
starting_time = timestamps[0]
else:
estimated_rate = float(imaging.get_sampling_frequency())
starting_time = 0.0

if estimated_rate:
photon_series_kwargs.update(starting_time=timestamps[0], rate=estimated_rate)
photon_series_kwargs.update(rate=estimated_rate, starting_time=starting_time)
else:
photon_series_kwargs.update(timestamps=timestamps, rate=None)
else:
rate = float(imaging.get_sampling_frequency())
photon_series_kwargs.update(rate=rate)
photon_series_kwargs.update(timestamps=timestamps)

# Add the photon series to the nwbfile (either as OnePhotonSeries or TwoPhotonSeries)
photon_series = dict(
Expand Down Expand Up @@ -682,6 +695,7 @@ def add_imaging_to_nwbfile(
iterator_type: Optional[str] = "v2",
iterator_options: Optional[dict] = None,
parent_container: Literal["acquisition", "processing/ophys"] = "acquisition",
always_write_timestamps: bool = False,
) -> NWBFile:
"""
Add imaging data from an ImagingExtractor object to an NWBFile.
Expand All @@ -705,6 +719,11 @@ def add_imaging_to_nwbfile(
parent_container : {"acquisition", "processing/ophys"}, optional
Specifies the parent container to which the photon series should be added, either as part of "acquisition" or
under the "processing/ophys" module, by default "acquisition".
always_write_timestamps : bool, default: False
Set to True to always write timestamps.
By default (False), the function checks if the timestamps are uniformly sampled, and if so, stores the data
using a regular sampling rate instead of explicit timestamps. If set to True, timestamps will be written
explicitly, regardless of whether the sampling rate is uniform.

Returns
-------
Expand All @@ -722,6 +741,7 @@ def add_imaging_to_nwbfile(
iterator_type=iterator_type,
iterator_options=iterator_options,
parent_container=parent_container,
always_write_timestamps=always_write_timestamps,
)

return nwbfile
Expand Down
2 changes: 2 additions & 0 deletions src/neuroconv/tools/testing/mock_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ def __init__(
sampling_frequency=sampling_frequency,
dtype=dtype,
verbose=verbose,
seed=seed,
)

self.verbose = verbose
Expand Down Expand Up @@ -334,6 +335,7 @@ def __init__(
has_deconvolved_signal=has_deconvolved_signal,
has_neuropil_signal=has_neuropil_signal,
verbose=verbose,
seed=seed,
)

def get_metadata(self) -> dict:
Expand Down
14 changes: 13 additions & 1 deletion tests/test_ophys/test_ophys_interfaces.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import numpy as np

from neuroconv.tools.testing.data_interface_mixins import (
ImagingExtractorInterfaceTestMixin,
SegmentationExtractorInterfaceTestMixin,
Expand All @@ -12,7 +14,17 @@ class TestMockImagingInterface(ImagingExtractorInterfaceTestMixin):
data_interface_cls = MockImagingInterface
interface_kwargs = dict()

# TODO: fix this by setting a seed on the dummy imaging extractor
def test_always_write_timestamps(self, setup_interface):
# By default the MockImagingInterface has a uniform sampling rate

nwbfile = self.interface.create_nwbfile(always_write_timestamps=True)
two_photon_series = nwbfile.acquisition["TwoPhotonSeries"]
imaging = self.interface.imaging_extractor
expected_timestamps = imaging.frame_to_time(np.arange(imaging.get_num_frames()))

np.testing.assert_array_equal(two_photon_series.timestamps[:], expected_timestamps)

# Remove this after roiextractors 0.5.10 is released
def test_all_conversion_checks(self):
pass

Expand Down
Loading