Repository: SpikeInterface/spikeinterface
Pull request #3034 (2024-06-17 23:31:12)

add recording.time_slice like recording.frame_slice
Many times when I use spikeinterface I wish had this facility. recording.time_slice() to avoid having to do the conversion myself. This PR adds the functionality and a test.

That said, I am not sure I really like name, any suggestions @zm711, @JoeZiminski? 

I am thinking on discoverability.
I think that if the methods started by slice it would be nice to get the auto-completition to either complete it to time or frame but  because they are not

Maybe there is a better name?


Patch:
diff --git a/src/spikeinterface/core/baserecording.py b/src/spikeinterface/core/baserecording.py
index 68a7dd744..184959512 100644
--- a/src/spikeinterface/core/baserecording.py
+++ b/src/spikeinterface/core/baserecording.py
@@ -679,6 +679,30 @@ class BaseRecording(BaseRecordingSnippets):
         sub_recording = FrameSliceRecording(self, start_frame=start_frame, end_frame=end_frame)
         return sub_recording
 
+    def time_slice(self, start_time: float, end_time: float) -> BaseRecording:
+        """
+        Returns a new recording with sliced time. Note that this operation is not in place.
+
+        Parameters
+        ----------
+        start_time : float
+            The start time in seconds.
+        end_time : float
+            The end time in seconds.
+
+        Returns
+        -------
+        BaseRecording
+            The object with sliced time.
+        """
+
+        assert self.get_num_segments() == 1, "Time slicing is only supported for single segment recordings."
+
+        start_frame = self.time_to_sample_index(start_time)
+        end_frame = self.time_to_sample_index(end_time)
+
+        return self.frame_slice(start_frame=start_frame, end_frame=end_frame)
+
     def _select_segments(self, segment_indices):
         from .segmentutils import SelectSegmentRecording
 


Test patch:
diff --git a/src/spikeinterface/core/tests/test_baserecording.py b/src/spikeinterface/core/tests/test_baserecording.py
index eb6cf7ac1..682881af8 100644
--- a/src/spikeinterface/core/tests/test_baserecording.py
+++ b/src/spikeinterface/core/tests/test_baserecording.py
@@ -361,5 +361,30 @@ def test_select_channels():
     assert np.array_equal(selected_channel_ids, ["a", "c"])
 
 
+def test_time_slice():
+    # Case with sampling frequency
+    sampling_frequency = 10_000.0
+    recording = generate_recording(durations=[1.0], num_channels=3, sampling_frequency=sampling_frequency)
+
+    sliced_recording_times = recording.time_slice(start_time=0.1, end_time=0.8)
+    sliced_recording_frames = recording.frame_slice(start_frame=1000, end_frame=8000)
+
+    assert np.allclose(sliced_recording_times.get_traces(), sliced_recording_frames.get_traces())
+
+
+def test_time_slice_with_time_vector():
+
+    # Case with time vector
+    sampling_frequency = 10_000.0
+    recording = generate_recording(durations=[1.0], num_channels=3, sampling_frequency=sampling_frequency)
+    times = 1 + np.arange(0, 10_000) / sampling_frequency
+    recording.set_times(times=times, segment_index=0, with_warning=False)
+
+    sliced_recording_times = recording.time_slice(start_time=1.1, end_time=1.8)
+    sliced_recording_frames = recording.frame_slice(start_frame=1000, end_frame=8000)
+
+    assert np.allclose(sliced_recording_times.get_traces(), sliced_recording_frames.get_traces())
+
+
 if __name__ == "__main__":
     test_BaseRecording()