def setup_events(self): eventname11 = 'event 1 1' eventname12 = 'event 1 2' eventname21 = 'event 2 1' eventname22 = 'event 2 2' eventtime11 = 10 * pq.ms eventtime12 = 20 * pq.ms eventtime21 = 30 * pq.s eventtime22 = 40 * pq.s self.eventnames1 = [eventname11, eventname12] self.eventnames2 = [eventname21, eventname22] self.eventnames = [eventname11, eventname12, eventname21, eventname22] params1 = {'testattr': True} params2 = {'testattr': 5} event11 = Event(eventtime11, label=eventname11, name=eventname11, **params1) event12 = Event(eventtime12, label=eventname12, name=eventname12, **params2) event21 = Event(eventtime21, label=eventname21, name=eventname21) event22 = Event(eventtime22, label=eventname22, name=eventname22) self.event1 = [event11, event12] self.event2 = [event21, event22] self.event = [event11, event12, event21, event22]
def setUp(self): self.evt = Event(times=np.arange(0, 100, 1) * pq.s, name='Ch1', labels=np.repeat(np.array(['t0', 't1'], dtype='S'), 50)) self.evt2 = Event(times=np.arange(0, 100, 3) * pq.s, name='Ch2', labels=np.repeat(np.array(['t2', 't3'], dtype='S'), 17)) self.segment = Segment() self.segment.events.append(self.evt) self.segment.events.append(self.evt2) self.df = pd.DataFrame(data=[[1, 0], [1, 1]], index=['start', 'stop'], columns=['Ch1', 'Ch2']) self.startoftrial = ['start'] self.epochs = ['results'] self.name = 'MyEvents' self.typeframe = pd.DataFrame(data=['start', 'results'], columns=['type'], index=['start', 'stop']) ProcessEvents(seg=self.segment, tolerance=1, evtframe=self.df, name=self.name) self.columns = ['time', 'event', 'trial_idx', 'results', \ 'with_previous_results', 'event_type']
def setUp(self): self.signal = AnalogSignal(np.random.randn(1000, 1), units='V', sampling_rate=1 * pq.Hz) self.signal2 = AnalogSignal(np.random.randn(1000, 1), units='V', sampling_rate=1 * pq.Hz) self.signal_start = 10 self.signal_end = 10 self.evt = Event(np.arange(0, 100, 1) * pq.s, labels=np.repeat(np.array(['t0', 't1'], dtype='S'), 50)) self.evt2 = Event(np.arange(0, 100, 1) * pq.s, labels=np.repeat(np.array(['t2', 't3'], dtype='S'), 50)) self.evt_start = 15 self.evt_pre_start = self.evt_start - 5 self.evt_end = 85 self.evt_post_end = self.evt_end + 5 self.not_segment = [100] self.segment = Segment() self.segment.analogsignals.append(self.signal) self.segment.events.append(self.evt) self.segment2 = Segment() self.segment2.analogsignals.append(self.signal2) self.segment2.events.append(self.evt2) self.segments = [self.segment, self.segment2]
def test__add_epoch(self): starts = Event(times=[0.5, 10.0, 25.2] * pq.s) starts.annotate(event_type='trial start') starts.array_annotate(trial_id=[1, 2, 3]) stops = Event(times=[5.5, 14.9, 30.1] * pq.s) stops.annotate(event_type='trial stop') stops.array_annotate(trial_id=[1, 2, 3]) seg = Segment() seg.events = [starts, stops] # test cutting with one event only ep_starts = add_epoch(seg, starts, pre=-300 * pq.ms, post=250 * pq.ms) assert_neo_object_is_compliant(ep_starts) assert_same_annotations(ep_starts, starts) assert_arrays_almost_equal(ep_starts.times, starts.times - 300 * pq.ms, 1e-12) assert_arrays_almost_equal( ep_starts.durations, (550 * pq.ms).rescale(ep_starts.durations.units) * np.ones( (len(starts))), 1e-12) # test cutting with two events ep_trials = add_epoch(seg, starts, stops) assert_neo_object_is_compliant(ep_trials) assert_same_annotations(ep_trials, starts) assert_arrays_almost_equal(ep_trials.times, starts.times, 1e-12) assert_arrays_almost_equal(ep_trials.durations, stops - starts, 1e-12)
def test_annotations(self): self.testfilename = self.get_filename_path('nixio_fr_ann.nix') with NixIO(filename=self.testfilename, mode='ow') as io: annotations = {'my_custom_annotation': 'hello block'} bl = Block(**annotations) annotations = {'something': 'hello hello000'} seg = Segment(**annotations) an =AnalogSignal([[1, 2, 3], [4, 5, 6]], units='V', sampling_rate=1*pq.Hz) an.annotations['ansigrandom'] = 'hello chars' sp = SpikeTrain([3, 4, 5]* s, t_stop=10.0) sp.annotations['railway'] = 'hello train' ev = Event(np.arange(0, 30, 10)*pq.Hz, labels=np.array(['trig0', 'trig1', 'trig2'], dtype='S')) ev.annotations['venue'] = 'hello event' ev2 = Event(np.arange(0, 30, 10) * pq.Hz, labels=np.array(['trig0', 'trig1', 'trig2'], dtype='S')) ev2.annotations['evven'] = 'hello ev' seg.spiketrains.append(sp) seg.events.append(ev) seg.events.append(ev2) seg.analogsignals.append(an) bl.segments.append(seg) io.write_block(bl) io.close() with NixIOfr(filename=self.testfilename) as frio: frbl = frio.read_block() assert 'my_custom_annotation' in frbl.annotations assert 'something' in frbl.segments[0].annotations # assert 'ansigrandom' in frbl.segments[0].analogsignals[0].annotations assert 'railway' in frbl.segments[0].spiketrains[0].annotations assert 'venue' in frbl.segments[0].events[0].annotations assert 'evven' in frbl.segments[0].events[1].annotations os.remove(self.testfilename)
def test__get_events(self): starts_1 = Event(times=[0.5, 10.0, 25.2] * pq.s) starts_1.annotate(event_type='trial start', pick='me') starts_1.array_annotate(trial_id=[1, 2, 3]) stops_1 = Event(times=[5.5, 14.9, 30.1] * pq.s) stops_1.annotate(event_type='trial stop') stops_1.array_annotate(trial_id=[1, 2, 3]) proxy_event = EventProxy(rawio=self.reader, event_channel_index=0, block_index=0, seg_index=0) proxy_event.annotate(event_type='trial start') seg = Segment() seg.events = [starts_1, stops_1, proxy_event] # test getting multiple events including a proxy extracted_starts = get_events(seg, event_type='trial start') self.assertEqual(len(extracted_starts), 2) # make sure the event is loaded and a neo.Event object is returned self.assertTrue(isinstance(extracted_starts[0], Event)) self.assertTrue(isinstance(extracted_starts[1], Event))
def setUp(self): self.evt = Event(np.arange(0, 100, 1) * pq.s, labels=np.repeat(np.array(['t0', 't1'], dtype='S'), 50)) self.evt2 = Event(np.arange(0, 100, 1) * pq.s, labels=np.repeat(np.array(['t2', 't3'], dtype='S'), 50)) self.events = [self.evt, self.evt2] self.evt_start = 10 self.evt_pre_start = self.evt_start - 5 self.evt_end = 90 self.evt_post_end = self.evt_end + 5
def setUp(self): self.evt = Event(times=np.arange(0, 100, 1) * pq.s, name='Ch1', labels=np.repeat(np.array(['t0', 't1'], dtype='S'), 50)) self.evt2 = Event(times=np.arange(0, 100, 3) * pq.s, name='Ch2', labels=np.repeat(np.array(['t2', 't3'], dtype='S'), 17)) self.eventlist = [{'ch': 0, 'times': self.evt.times}, \ {'ch': 1, 'times': self.evt2.times}] self.df = pd.DataFrame(data=[[1, 0], [1, 1]], index=['start', 'stop'], columns=['Ch1', 'Ch2'])
def setUp(self): self.evt = Event(times=np.arange(0, 100, 1) * pq.s, name='Ch1', labels=np.repeat(np.array(['t0', 't1'], dtype='S'), 50)) self.evt2 = Event(times=np.arange(0, 100, 3) * pq.s, name='Ch2', labels=np.repeat(np.array(['t2', 't3'], dtype='S'), 17)) self.segment = Segment() self.segment.events.append(self.evt) self.segment.events.append(self.evt2) self.df = pd.DataFrame(data=[[1, 0], [1, 1]], index=['start', 'stop'], columns=['Ch1', 'Ch2'])
def _read_main_pulse_file(filepaths: List[str]) -> Event: try: # read pulse file pulse_file = [ file for file in filepaths if "pulses" in os.path.basename(file).lower() ][0] pulses_df = pd.read_csv(filepath_or_buffer=pulse_file, header=None, names=["timestamp", "comment"]) times = Quantity(pulses_df["timestamp"], "s") pulses = Event(times=times, labels=pulses_df["comment"], name="Dapsys Main Pulse", file_origin=pulse_file) channel_id = f"{TypeID.ELECTRICAL_STIMULUS.value}.0" pulses.annotate(id=channel_id, type_id=TypeID.ELECTRICAL_STIMULUS.value) intervals: Quantity = np.diff(times) intervals = quantity_concat(intervals, np.array([float("inf")]) * second) pulses.array_annotate(intervals=intervals) return pulses except Exception as ex: traceback.print_exc()
def test__add_epoch(self): proxy_event = EventProxy(rawio=self.reader, event_channel_index=0, block_index=0, seg_index=0) loaded_event = proxy_event.load() regular_event = Event(times=loaded_event.times - 1 * loaded_event.units) loaded_event.annotate(nix_name='neo.event.0') regular_event.annotate(nix_name='neo.event.1') seg = Segment() seg.events = [regular_event, proxy_event] # test cutting with two events one of which is a proxy epoch = add_epoch(seg, regular_event, proxy_event) assert_neo_object_is_compliant(epoch) exp_annos = { k: v for k, v in regular_event.annotations.items() if k != 'nix_name' } self.assertDictEqual(epoch.annotations, exp_annos) assert_arrays_almost_equal(epoch.times, regular_event.times, 1e-12) assert_arrays_almost_equal( epoch.durations, np.ones(regular_event.shape) * loaded_event.units, 1e-12)
def merge(self, other): ''' Merge the another :class:`Event` into this one. The :class:`Event` objects are concatenated horizontally (column-wise), :func:`np.hstack`). If the attributes of the two :class:`Event` are not compatible, and Exception is raised. ''' othertimes = other.times.rescale(self.times.units) times = np.hstack([self.times, othertimes]) * self.times.units labels = np.hstack([self.labels, other.labels]) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) return Event(times=times, labels=labels, **kwargs)
def _read_eventarray(self, node, parent): attributes = self._get_standard_attributes(node) times = self._get_quantity(node["times"]) labels = node["labels"].value.astype('U') event = Event(times=times, labels=labels, **attributes) event.segment = parent return event
def process_events(seg, tolerence): if 'Events' not in [cur_evts.name for cur_evts in seg.events]: evtlist = list() event_times = list() event_labels = list() for evtarr in seg.events: if 'DIn' in evtarr.name: evtlist.append( dict(times=evtarr.times, ch=int(evtarr.name[-1]) - 1)) while any(event_array['times'].size for event_array in evtlist): evtlist_non_empty = [x for x in evtlist if x['times'].size] first_elements = [x['times'][0] for x in evtlist_non_empty] cur_first = np.amin(first_elements) * pq.s cur_event = 0 cur_event_list = [0] * len(evtlist) for evtarr in evtlist_non_empty: if evtarr['times'][0] - cur_first < tolerence: cur_event_list[evtarr['ch']] = 1 evtarr['times'] = np.delete(evtarr['times'], 0) * pq.s for bit in cur_event_list: cur_event = (cur_event << 1) | bit event_times.append(cur_first) event_labels.append(cur_event) evtlist = evtlist_non_empty result = Event(times=np.array(event_times) * pq.s, labels=np.array(event_labels, dtype='S'), name='Events') seg.events.append(result) else: print("Events array already presented!")
def _get_tracking(self, channel, conversion): if channel is not None: eva = Event() ttls = self._kwe['event_types']['TTL']['events'][ 'time_samples'].value event_channels = self._kwe['event_types']['TTL']['events'][ 'user_data']['event_channels'].value event_id = self._kwe['event_types']['TTL']['events']['user_data'][ 'eventID'].value eva.times = (ttls[(event_channels == channel) & (event_id == 1)] / self._attrs['kwe']['sample_rate']) * pq.s eva.name = 'TrackingTTL' posdata = self._kwe['event_types']['Binary_messages']['events'][ 'user_data']['Data'].value node_id = self._kwe['event_types']['Binary_messages']['events'][ 'user_data']['nodeID'].value time_samples = self._kwe['event_types']['Binary_messages']['events'][ 'time_samples'].value sigs = [] for node in self._nodes['OSC Port']: irsig = IrregularlySampledSignal( signal=posdata[node_id == int(node['NodeId'])] * conversion * pq.m, times=(time_samples[node_id == int(node['NodeId'])] / self._attrs['kwe']['sample_rate']) * pq.s, name=node['address']) sigs += [irsig] if channel is not None: return eva, sigs else: return sigs
def create_event(self, parent=None, name='Event'): event = Event([1.0, 2.3, 4.1] * pq.s, np.array([chr(0) + 'trig1', chr(0) + 'trig2', chr(0) + 'trig3'])); event.segment = parent self._assign_basic_attributes(event, name=name) return event
def setUp(self): self.evt = Event(np.arange(0, 100, 1) * pq.s, labels=np.repeat(np.array(['t0', 't1'], dtype='S'), 50)) self.not_evt = np.random.randn(1000, 1) self.evt_start = 10 self.evt_pre_start = self.evt_start - 5 self.evt_end = 90 self.evt_post_end = self.evt_end + 5
def read_eventarray(self, lazy=False, cascade=True, channel_index=0, t_start=0., segment_duration=0.): """function to read digital timestamps. this function only reads the event onset. to get digital event durations, use the epoch function (to be implemented).""" if lazy: eva = Event(file_origin=self.filename) else: #create temporary empty lists to store data tempNames = list() tempTimeStamp = list() #get entity from file trigEntity = self.fd.get_entity(channel_index) #transform t_start into index (reading will start from this index) startat = trigEntity.get_index_by_time( t_start, 0) #zero means closest index to value #get the last index to read, using segment duration and t_start endat = trigEntity.get_index_by_time( float(segment_duration + t_start), -1) #-1 means last index before time #numIndx = endat-startat #run through specified intervals in entity for i in range(startat, endat + 1, 1): #trigEntity.item_count): #get in which digital bit was the trigger detected tempNames.append(trigEntity.label[-8:]) #get the time stamps of onset events tempData, onOrOff = trigEntity.get_data(i) #if this was an onset event, save it to the list #on triggered recordings it seems that only onset events are #recorded. On continuous recordings both onset(==1) #and offset(==255) seem to be recorded if onOrOff == 1: #append the time stamp to them empty list tempTimeStamp.append(tempData) #create an event array eva = Event(labels=np.array(tempNames, dtype="S"), times=np.array(tempTimeStamp) * pq.s, file_origin=self.filename, description="the trigger events (without durations)") return eva
def load(self, time_slice=None, strict_slicing=True): ''' *Args*: :time_slice: None or tuple of the time slice expressed with quantities. None is the entire signal. :strict_slicing: True by default. Control if an error is raise or not when one of time_slice member (t_start or t_stop) is outside the real time range of the segment. ''' t_start, t_stop = consolidate_time_slice(time_slice, self.t_start, self.t_stop, strict_slicing) _t_start, _t_stop = prepare_time_slice(time_slice) timestamp, durations, labels = self._rawio.get_event_timestamps( block_index=self._block_index, seg_index=self._seg_index, event_channel_index=self._event_channel_index, t_start=_t_start, t_stop=_t_stop) dtype = 'float64' times = self._rawio.rescale_event_timestamp(timestamp, dtype=dtype) units = 's' if durations is not None: durations = self._rawio.rescale_epoch_duration(durations, dtype=dtype) * pq.s h = self._rawio.header['event_channels'][self._event_channel_index] if h['type'] == b'event': ret = Event(times=times, labels=labels, units='s', name=self.name, file_origin=self.file_origin, description=self.description, **self.annotations) elif h['type'] == b'epoch': ret = Epoch(times=times, durations=durations, labels=labels, units='s', name=self.name, file_origin=self.file_origin, description=self.description, **self.annotations) if time_slice is None: ret.array_annotate(**self.array_annotations) else: # TODO handle array_annotations with time_slice pass return ret
def test_event_write(self): block = Block() seg = Segment() block.segments.append(seg) event = Event(times=np.arange(0, 30, 10) * pq.s, labels=np.array(["0", "1", "2"]), name="event name", description="event description") seg.events.append(event) self.write_and_compare([block])
def _read_eventarray(self, node, parent): attributes = self._get_standard_attributes(node) times = self._get_quantity(node["times"]) if self._lazy: labels = np.array((), dtype=node["labels"].dtype) else: labels = node["labels"].value event = Event(times=times, labels=labels, **attributes) event.segment = parent if self._lazy: event.lazy_shape = node["times"].shape return event
def _filter_event_channel(event_channel: Event, label_filter: Callable[[str], bool]) -> Event: # list or ndarray labels = event_channel.labels # always an ndarray times: NPArray = event_channel.times matches = label_filter(labels) if isinstance(labels, NPArray) \ else [label_filter(l) for l in labels] new_times = times[matches] new_labels = labels[matches] if isinstance(labels, NPArray) \ else [l for l in labels if label_filter(l)] return Event(times=new_times, labels=new_labels, units=event_channel.units)
def random_event(name=None, **annotations): size = random.randint(1, 7) times = np.cumsum(np.random.uniform(5, 10, size=size)) labels = [random_string() for i in range(size)] if len(annotations) == 0: annotations = random_annotations(3) obj = Event( times=times, labels=labels, units="ms", name=name or random_string(), array_annotations=None, # todo **annotations ) return obj
def test__match_events(self): starts = Event(times=[0.5, 10.0, 25.2] * pq.s) starts.annotate(event_type='trial start') starts.array_annotate(trial_id=[1, 2, 3]) stops = Event(times=[5.5, 14.9, 30.1] * pq.s) stops.annotate(event_type='trial stop') stops.array_annotate(trial_id=[1, 2, 3]) stops2 = Event(times=[0.1, 5.5, 5.6, 14.9, 25.2, 30.1] * pq.s) stops2.annotate(event_type='trial stop') stops2.array_annotate(trial_id=[1, 1, 2, 2, 3, 3]) # test for matching input events, should just return identical copies matched_starts, matched_stops = match_events(starts, stops) assert_same_attributes(matched_starts, starts) assert_same_attributes(matched_stops, stops) # test for non-matching input events, should find shortest positive non-zero durations matched_starts2, matched_stops2 = match_events(starts, stops2) assert_same_attributes(matched_starts2, starts) assert_same_attributes(matched_stops2, stops)
def test_anonymous_objects_write(self): nblocks = 2 nsegs = 2 nanasig = 4 nirrseg = 2 nepochs = 3 nevents = 4 nspiketrains = 3 nchx = 5 nunits = 10 times = self.rquant(1, pq.s) signal = self.rquant(1, pq.V) blocks = [] for blkidx in range(nblocks): blk = Block() blocks.append(blk) for segidx in range(nsegs): seg = Segment() blk.segments.append(seg) for anaidx in range(nanasig): seg.analogsignals.append(AnalogSignal(signal=signal, sampling_rate=pq.Hz)) for irridx in range(nirrseg): seg.irregularlysampledsignals.append( IrregularlySampledSignal(times=times, signal=signal, time_units=pq.s) ) for epidx in range(nepochs): seg.epochs.append(Epoch(times=times, durations=times)) for evidx in range(nevents): seg.events.append(Event(times=times)) for stidx in range(nspiketrains): seg.spiketrains.append(SpikeTrain(times=times, t_stop=times[-1]+pq.s, units=pq.s)) for chidx in range(nchx): chx = ChannelIndex(name="chx{}".format(chidx), index=[1, 2], channel_ids=[11, 22]) blk.channel_indexes.append(chx) for unidx in range(nunits): unit = Unit() chx.units.append(unit) self.writer.write_all_blocks(blocks) self.compare_blocks(blocks, self.reader.blocks)
def test__match_events(self): proxy_event = EventProxy(rawio=self.reader, event_channel_index=0, block_index=0, seg_index=0) loaded_event = proxy_event.load() regular_event = Event(times=loaded_event.times - 1 * loaded_event.units, labels=np.array(['trigger_a', 'trigger_b'] * 3, dtype='U12')) seg = Segment() seg.events = [regular_event, proxy_event] # test matching two events one of which is a proxy matched_regular, matched_proxy = match_events(regular_event, proxy_event) assert_same_attributes(matched_regular, regular_event) assert_same_attributes(matched_proxy, loaded_event)
def create_all_annotated(cls): times = cls.rquant(1, pq.s) signal = cls.rquant(1, pq.V) blk = Block() blk.annotate(**cls.rdict(3)) cls.populate_dates(blk) seg = Segment() seg.annotate(**cls.rdict(4)) cls.populate_dates(seg) blk.segments.append(seg) asig = AnalogSignal(signal=signal, sampling_rate=pq.Hz) asig.annotate(**cls.rdict(2)) seg.analogsignals.append(asig) isig = IrregularlySampledSignal(times=times, signal=signal, time_units=pq.s) isig.annotate(**cls.rdict(2)) seg.irregularlysampledsignals.append(isig) epoch = Epoch(times=times, durations=times) epoch.annotate(**cls.rdict(4)) seg.epochs.append(epoch) event = Event(times=times) event.annotate(**cls.rdict(4)) seg.events.append(event) spiketrain = SpikeTrain(times=times, t_stop=pq.s, units=pq.s) d = cls.rdict(6) d["quantity"] = pq.Quantity(10, "mV") d["qarray"] = pq.Quantity(range(10), "mA") spiketrain.annotate(**d) seg.spiketrains.append(spiketrain) chx = ChannelIndex(name="achx", index=[1, 2], channel_ids=[0, 10]) chx.annotate(**cls.rdict(5)) blk.channel_indexes.append(chx) unit = Unit() unit.annotate(**cls.rdict(2)) chx.units.append(unit) return blk
def test_multiref_write(self): blk = Block("blk1") signal = AnalogSignal(name="sig1", signal=[0, 1, 2], units="mV", sampling_period=pq.Quantity(1, "ms")) othersignal = IrregularlySampledSignal(name="i1", signal=[0, 0, 0], units="mV", times=[1, 2, 3], time_units="ms") event = Event(name="Evee", times=[0.3, 0.42], units="year") epoch = Epoch(name="epoche", times=[0.1, 0.2] * pq.min, durations=[0.5, 0.5] * pq.min) st = SpikeTrain(name="the train of spikes", times=[0.1, 0.2, 10.3], t_stop=11, units="us") for idx in range(3): segname = "seg" + str(idx) seg = Segment(segname) blk.segments.append(seg) seg.analogsignals.append(signal) seg.irregularlysampledsignals.append(othersignal) seg.events.append(event) seg.epochs.append(epoch) seg.spiketrains.append(st) chidx = ChannelIndex([10, 20, 29]) seg = blk.segments[0] st = SpikeTrain(name="choochoo", times=[10, 11, 80], t_stop=1000, units="s") seg.spiketrains.append(st) blk.channel_indexes.append(chidx) for idx in range(6): unit = Unit("unit" + str(idx)) chidx.units.append(unit) unit.spiketrains.append(st) self.writer.write_block(blk) self.compare_blocks([blk], self.reader.blocks)
def load(self, time_slice=None, strict_slicing=True): """ Load EventProxy args: :param time_slice: None or tuple of the time slice expressed with quantities. None is the entire signal. :param strict_slicing: True by default. Control if an error is raised or not when one of the time_slice members (t_start or t_stop) is outside the real time range of the segment. """ if time_slice: raise NotImplementedError("todo") else: times = self._timeseries.timestamps[:] labels = self._timeseries.data[:] return Event(times * pq.s, labels=labels, name=self.name, description=self.description, **self.annotations)
def test__add_epoch(self): proxy_event = EventProxy(rawio=self.reader, event_channel_index=0, block_index=0, seg_index=0) loaded_event = proxy_event.load() regular_event = Event(times=loaded_event.times - 1 * loaded_event.units) seg = Segment() seg.events = [regular_event, proxy_event] # test cutting with two events one of which is a proxy epoch = add_epoch(seg, regular_event, proxy_event) assert_neo_object_is_compliant(epoch) assert_same_annotations(epoch, regular_event) assert_arrays_almost_equal(epoch.times, regular_event.times, 1e-12) assert_arrays_almost_equal(epoch.durations, np.ones(regular_event.shape) * loaded_event.units, 1e-12)