Skip to content

Commit

Permalink
Add always_write_timestamps conversion option to imaging interfaces (
Browse files Browse the repository at this point in the history
  • Loading branch information
h-mayorquin authored Nov 11, 2024
1 parent 9448f95 commit 6960872
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 35 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,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 @@ -46,7 +47,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 @@ -128,6 +128,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,
):
"""
Add imaging data to the NWB file
Expand Down Expand Up @@ -167,4 +168,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

0 comments on commit 6960872

Please sign in to comment.