@@ -143,10 +143,6 @@ def __init__(
143143 raise ValueError ('You must provide "segment_index" for multisegment recordings.' )
144144 segment_index = 0
145145
146- if not rec0 .has_time_vector (segment_index = segment_index ):
147- times = None
148- else :
149- times = rec0 .get_times (segment_index = segment_index )
150146 t_start = rec0 .get_start_time (segment_index = segment_index )
151147 t_end = rec0 .get_end_time (segment_index = segment_index )
152148
@@ -172,7 +168,7 @@ def __init__(
172168 cmap = cmap
173169
174170 times_in_range , list_traces , frame_range , channel_ids = _get_trace_list (
175- recordings , channel_ids , time_range , segment_index , return_in_uV = return_in_uV , times = times
171+ recordings , channel_ids , segment_index , time_range = time_range , return_in_uV = return_in_uV
176172 )
177173
178174 list_traces = [traces * scale for traces in list_traces ]
@@ -405,25 +401,12 @@ def plot_ipywidgets(self, data_plot, **backend_kwargs):
405401 self .figure .canvas .header_visible = False
406402 plt .show ()
407403
408- if not self .rec0 .has_time_vector (segment_index = data_plot ["segment_index" ]):
409- times = None
410- t_starts = [
411- rec0 .get_start_time (segment_index = segment_index ) for segment_index in range (rec0 .get_num_segments ())
412- ]
413- else :
414- times = [
415- np .array (self .rec0 .get_times (segment_index = segment_index ))
416- for segment_index in range (self .rec0 .get_num_segments ())
417- ]
418- t_starts = None
419-
420404 # some widgets
421405 self .time_slider = TimeSlider (
422406 durations = [rec0 .get_duration (s ) for s in range (rec0 .get_num_segments ())],
423407 sampling_frequency = rec0 .sampling_frequency ,
424- time_range = data_plot ["time_range" ],
425- times = times ,
426- t_starts = t_starts ,
408+ frame_range = data_plot ["frame_range" ],
409+ rec0 = rec0 ,
427410 )
428411 # handle times
429412 if data_plot ["events" ] is not None :
@@ -559,24 +542,17 @@ def _retrieve_traces(self, change=None):
559542
560543 start_frame , end_frame , segment_index = self .time_slider .value
561544
562- if not self .rec0 .has_time_vector (segment_index = segment_index ):
563- times = None
564- time_range = np .array ([start_frame , end_frame ]) / self .rec0 .sampling_frequency + self .rec0 .get_start_time (
565- segment_index = segment_index
566- )
567- else :
568- times = self .rec0 .get_times (segment_index = segment_index )
569- time_range = np .array ([times [start_frame ], times [end_frame ]])
545+ frame_range = np .array ([start_frame , end_frame ])
570546
571547 self ._selected_recordings = {k : self .recordings [k ] for k in self ._get_layers ()}
572548 times_in_range , list_traces , frame_range , channel_ids = _get_trace_list (
573549 self ._selected_recordings ,
574550 channel_ids ,
575- time_range ,
576551 segment_index ,
577552 return_in_uV = self .return_in_uV ,
578- times = times ,
553+ frame_range = frame_range ,
579554 )
555+ time_range = np .array ([times_in_range [0 ], times_in_range [- 1 ]])
580556
581557 self ._channel_ids = channel_ids
582558 self ._list_traces = list_traces
@@ -640,12 +616,11 @@ def plot_figpack(self, data_plot, **backend_kwargs):
640616 handle_display_and_url ,
641617 import_figpack_or_sortingview ,
642618 )
619+ import importlib .util
643620
644621 use_sortingview = backend_kwargs .get ("use_sortingview" , False )
645622 vv_base , vv_views = import_figpack_or_sortingview (use_sortingview )
646623
647- import importlib .util
648-
649624 spec = importlib .util .find_spec ("pyvips" )
650625 if spec is None :
651626 raise ImportError ("To use `plot_traces()` in sortingview you need the pyvips package." )
@@ -705,25 +680,28 @@ def plot_ephyviewer(self, data_plot, **backend_kwargs):
705680 app .exec ()
706681
707682
708- def _get_trace_list (recordings , channel_ids , time_range , segment_index , return_in_uV = False , times = None ):
683+ def _get_trace_list (recordings , channel_ids , segment_index , time_range = None , return_in_uV = False , frame_range = None ):
709684 # function also used in ipywidgets plotter
710685 k0 = list (recordings .keys ())[0 ]
711686 rec0 = recordings [k0 ]
712687
713- fs = rec0 .get_sampling_frequency ()
714-
715688 if return_in_uV :
716689 assert all (
717690 rec .has_scaleable_traces () for rec in recordings .values ()
718691 ), "Some recording layers do not have scaled traces. Use `return_in_uV=False`"
719- if times is not None :
720- frame_range = np .searchsorted (times , time_range )
721- times = times [frame_range [0 ] : frame_range [1 ]]
722- else :
723- frame_range = rec0 .time_to_sample_index (time_range , segment_index = segment_index )
692+
693+ assert time_range is not None or frame_range is not None , "You must provide either time_range or frame_range"
694+
695+ if frame_range is None :
696+ # use the sampling-frequency approximation to avoid loading the full time vector
697+ t_start = rec0 .get_start_time (segment_index = segment_index )
698+ fs = rec0 .get_sampling_frequency ()
699+ frame_range = np .round ((np .asarray (time_range ) - t_start ) * fs ).astype (np .int64 )
724700 a_max = rec0 .get_num_frames (segment_index = segment_index )
725701 frame_range = np .clip (frame_range , 0 , a_max )
726- times = np .arange (frame_range [0 ], frame_range [1 ]) / fs + rec0 .get_start_time (segment_index = segment_index )
702+
703+ # lazily load only the needed time slice
704+ times_in_range = rec0 .get_times (segment_index = segment_index , start_frame = frame_range [0 ], end_frame = frame_range [1 ])
727705
728706 list_traces = []
729707 for rec_name , rec in recordings .items ():
@@ -737,4 +715,4 @@ def _get_trace_list(recordings, channel_ids, time_range, segment_index, return_i
737715
738716 list_traces .append (traces )
739717
740- return times , list_traces , frame_range , channel_ids
718+ return times_in_range , list_traces , frame_range , channel_ids
0 commit comments