class TestArrayMethods(unittest.TestCase): def setUp(self): self.signal = AnalogSignal(numpy.arange(10.0), units="nA", sampling_rate=1 * kHz) def test__slice_should_return_AnalogSignal(self): sub = self.signal[3:8] self.assertIsInstance(sub, AnalogSignal) self.assertEqual(sub.size, 5) self.assertEqual(sub.sampling_period, self.signal.sampling_period) self.assertEqual(sub.sampling_rate, self.signal.sampling_rate) self.assertEqual(sub.t_start, self.signal.t_start + 3 * sub.sampling_period) self.assertEqual(sub.t_stop, sub.t_start + 5 * sub.sampling_period) # Test other attributes were copied over (in this case, defaults) self.assertEqual(sub.file_origin, self.signal.file_origin) self.assertEqual(sub.name, self.signal.name) self.assertEqual(sub.description, self.signal.description) self.assertEqual(sub.annotations, self.signal.annotations) sub = self.signal[3:8] self.assertEqual(sub.file_origin, self.signal.file_origin) self.assertEqual(sub.name, self.signal.name) self.assertEqual(sub.description, self.signal.description) self.assertEqual(sub.annotations, self.signal.annotations) def test__slice_with_attributes(self): # Set attributes, slice, test that they are copied self.signal.file_origin = 'crack.txt' self.signal.name = 'sig' self.signal.description = 'a signal' self.signal.annotate(ratname='Georges') # slice sub = self.signal[3:8] # tests from other slice test self.assertIsInstance(sub, AnalogSignal) self.assertEqual(sub.size, 5) self.assertEqual(sub.sampling_period, self.signal.sampling_period) self.assertEqual(sub.sampling_rate, self.signal.sampling_rate) self.assertEqual(sub.t_start, self.signal.t_start + 3 * sub.sampling_period) self.assertEqual(sub.t_stop, sub.t_start + 5 * sub.sampling_period) # Test other attributes were copied over (in this case, set by user) self.assertEqual(sub.file_origin, self.signal.file_origin) self.assertEqual(sub.name, self.signal.name) self.assertEqual(sub.description, self.signal.description) self.assertEqual(sub.annotations, self.signal.annotations) self.assertEqual(sub.annotations, {'ratname': 'Georges'}) def test__slice_should_change_sampling_period(self): sub = self.signal[:2] self.assertEqual(sub.sampling_period, self.signal.sampling_period) sub = self.signal[::2] self.assertEqual(sub.sampling_period, self.signal.sampling_period * 2) sub = self.signal[1:7:2] self.assertEqual(sub.sampling_period, self.signal.sampling_period * 2) def test__getitem_should_return_single_quantity(self): self.assertEqual(self.signal[0], 0 * nA) self.assertEqual(self.signal[9], 9 * nA) self.assertRaises(IndexError, self.signal.__getitem__, 10) def test_comparison_operators(self): assert_arrays_equal( self.signal >= 5 * nA, numpy.array([ False, False, False, False, False, True, True, True, True, True ])) assert_arrays_equal( self.signal >= 5 * pA, numpy.array( [False, True, True, True, True, True, True, True, True, True])) def test__comparison_with_inconsistent_units_should_raise_Exception(self): self.assertRaises(ValueError, self.signal.__gt__, 5 * mV) def test_simple_statistics(self): self.assertEqual(self.signal.max(), 9 * nA) self.assertEqual(self.signal.min(), 0 * nA) self.assertEqual(self.signal.mean(), 4.5 * nA)
class TestAnalogSignalArrayMethods(unittest.TestCase): def setUp(self): self.data1 = np.arange(10.0) self.data1quant = self.data1 * pq.nA self.arr_ann = {'anno1': [23], 'anno2': ['A']} self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1 * pq.kHz, name='spam', description='eggs', file_origin='testfile.txt', arg1='test', array_annotations=self.arr_ann) self.signal1.segment = Segment() self.signal1.channel_index = ChannelIndex(index=[0]) def test__compliant(self): assert_neo_object_is_compliant(self.signal1) def test__slice_should_return_AnalogSignalArray(self): # slice for index in (0, np.int64(0)): result = self.signal1[3:8, index] self.assertIsInstance(result, AnalogSignal) assert_neo_object_is_compliant(result) # should slicing really preserve name and description? self.assertEqual(result.name, 'spam') # perhaps these should be modified to indicate the slice? self.assertEqual(result.description, 'eggs') self.assertEqual(result.file_origin, 'testfile.txt') self.assertEqual(result.annotations, {'arg1': 'test'}) # Array annotations remain the same, because number of signals was not altered self.assertEqual(result.array_annotations, {'anno1': [23], 'anno2': ['A']}) self.assertIsInstance(result.array_annotations, ArrayDict) self.assertEqual(result.size, 5) self.assertEqual(result.sampling_period, self.signal1.sampling_period) self.assertEqual(result.sampling_rate, self.signal1.sampling_rate) self.assertEqual(result.t_start, self.signal1.t_start + 3 * result.sampling_period) self.assertEqual(result.t_stop, result.t_start + 5 * result.sampling_period) assert_array_equal(result.magnitude, self.data1[3:8].reshape(-1, 1)) # Test other attributes were copied over (in this case, defaults) self.assertEqual(result.file_origin, self.signal1.file_origin) self.assertEqual(result.name, self.signal1.name) self.assertEqual(result.description, self.signal1.description) self.assertEqual(result.annotations, self.signal1.annotations) def test__time_slice_deepcopy_annotations(self): params1 = {'test0': 'y1', 'test1': ['deeptest'], 'test2': True} self.signal1.annotate(**params1) result = self.signal1.time_slice(None, None) # Change annotations of original params2 = {'test0': 'y2', 'test2': False} self.signal1.annotate(**params2) self.signal1.annotations['test1'][0] = 'shallowtest' self.assertNotEqual(self.signal1.annotations['test0'], result.annotations['test0']) self.assertNotEqual(self.signal1.annotations['test1'], result.annotations['test1']) self.assertNotEqual(self.signal1.annotations['test2'], result.annotations['test2']) # Change annotations of result params3 = {'test0': 'y3'} result.annotate(**params3) result.annotations['test1'][0] = 'shallowtest2' self.assertNotEqual(self.signal1.annotations['test0'], result.annotations['test0']) self.assertNotEqual(self.signal1.annotations['test1'], result.annotations['test1']) self.assertNotEqual(self.signal1.annotations['test2'], result.annotations['test2']) def test__time_slice_deepcopy_array_annotations(self): length = self.signal1.shape[-1] params1 = {'test0': ['y{}'.format(i) for i in range(length)], 'test1': ['deeptest' for i in range(length)], 'test2': [(-1)**i > 0 for i in range(length)]} self.signal1.array_annotate(**params1) result = self.signal1.time_slice(None, None) # Change annotations of original params2 = {'test0': ['x{}'.format(i) for i in range(length)], 'test2': [(-1) ** (i + 1) > 0 for i in range(length)]} self.signal1.array_annotate(**params2) self.signal1.array_annotations['test1'][0] = 'shallowtest' self.assertFalse(all(self.signal1.array_annotations['test0'] == result.array_annotations['test0'])) self.assertFalse(all(self.signal1.array_annotations['test1'] == result.array_annotations['test1'])) self.assertFalse(all(self.signal1.array_annotations['test2'] == result.array_annotations['test2'])) # Change annotations of result params3 = {'test0': ['z{}'.format(i) for i in range(1, result.shape[-1]+1)]} result.array_annotate(**params3) result.array_annotations['test1'][0] = 'shallow2' self.assertFalse(all(self.signal1.array_annotations['test0'] == result.array_annotations['test0'])) self.assertFalse(all(self.signal1.array_annotations['test1'] == result.array_annotations['test1'])) self.assertFalse(all(self.signal1.array_annotations['test2'] == result.array_annotations['test2'])) def test__time_slice_deepcopy_data(self): result = self.signal1.time_slice(None, None) # Change values of original array self.signal1[2] = 7.3*self.signal1.units self.assertFalse(all(self.signal1 == result)) # Change values of sliced array result[3] = 9.5*result.units self.assertFalse(all(self.signal1 == result)) def test__slice_should_change_sampling_period(self): result1 = self.signal1[:2, 0] result2 = self.signal1[::2, 0] result3 = self.signal1[1:7:2, 0] self.assertIsInstance(result1, AnalogSignal) assert_neo_object_is_compliant(result1) self.assertEqual(result1.name, 'spam') self.assertEqual(result1.description, 'eggs') self.assertEqual(result1.file_origin, 'testfile.txt') self.assertEqual(result1.annotations, {'arg1': 'test'}) self.assertEqual(result1.array_annotations, {'anno1': [23], 'anno2': ['A']}) self.assertIsInstance(result1.array_annotations, ArrayDict) self.assertIsInstance(result2, AnalogSignal) assert_neo_object_is_compliant(result2) self.assertEqual(result2.name, 'spam') self.assertEqual(result2.description, 'eggs') self.assertEqual(result2.file_origin, 'testfile.txt') self.assertEqual(result2.annotations, {'arg1': 'test'}) self.assertEqual(result2.array_annotations, {'anno1': [23], 'anno2': ['A']}) self.assertIsInstance(result2.array_annotations, ArrayDict) self.assertIsInstance(result3, AnalogSignal) assert_neo_object_is_compliant(result3) self.assertEqual(result3.name, 'spam') self.assertEqual(result3.description, 'eggs') self.assertEqual(result3.file_origin, 'testfile.txt') self.assertEqual(result3.annotations, {'arg1': 'test'}) self.assertEqual(result3.array_annotations, {'anno1': [23], 'anno2': ['A']}) self.assertIsInstance(result3.array_annotations, ArrayDict) self.assertEqual(result1.sampling_period, self.signal1.sampling_period) self.assertEqual(result2.sampling_period, self.signal1.sampling_period * 2) self.assertEqual(result3.sampling_period, self.signal1.sampling_period * 2) assert_array_equal(result1.magnitude, self.data1[:2].reshape(-1, 1)) assert_array_equal(result2.magnitude, self.data1[::2].reshape(-1, 1)) assert_array_equal(result3.magnitude, self.data1[1:7:2].reshape(-1, 1)) def test__slice_should_modify_linked_channelindex(self): n = 8 # number of channels signal = AnalogSignal(np.arange(n * 100.0).reshape(100, n), sampling_rate=1 * pq.kHz, units="mV", name="test") self.assertEqual(signal.shape, (100, n)) signal.channel_index = ChannelIndex(index=np.arange(n, dtype=int), channel_names=["channel{0}".format(i) for i in range(n)]) signal.channel_index.analogsignals.append(signal) odd_channels = signal[:, 1::2] self.assertEqual(odd_channels.shape, (100, n // 2)) assert_array_equal(odd_channels.channel_index.index, np.arange(n // 2, dtype=int)) assert_array_equal(odd_channels.channel_index.channel_names, ["channel{0}".format(i) for i in range(1, n, 2)]) assert_array_equal(signal.channel_index.channel_names, ["channel{0}".format(i) for i in range(n)]) self.assertEqual(odd_channels.channel_index.analogsignals[0].name, signal.name) def test__time_slice_should_set_parents_to_None(self): # When timeslicing, a deep copy is made, # thus the reference to parent objects should be destroyed result = self.signal1.time_slice(1 * pq.ms, 3 * pq.ms) self.assertEqual(result.segment, None) self.assertEqual(result.channel_index, None) def test__time_slice_close_to_sample_boundaries(self): # see issue 530 sig = AnalogSignal(np.arange(25000) * pq.uV, t_start=0 * pq.ms, sampling_rate=25 * pq.kHz) window_size = 3.0 * pq.ms expected_shape = int(np.rint((window_size * sig.sampling_rate).simplified.magnitude)) # test with random times t_start = (window_size / 2).magnitude t_stop = (sig.t_stop.rescale(pq.ms) - window_size / 2).magnitude for t in np.random.uniform(t_start, t_stop, size=1000): tq = t * pq.ms sliced_sig = sig.time_slice(tq - window_size / 2, tq + window_size / 2) self.assertEqual(expected_shape, sliced_sig.shape[0]) # test with times on or close to sample boundaries for i in np.random.randint(1000, sig.size - 1000, size=1000): tq = i * sig.sampling_period sliced_sig = sig.time_slice(tq - window_size / 2, tq + window_size / 2) self.assertEqual(expected_shape, sliced_sig.shape[0]) def test__time_shift_same_attributes(self): result = self.signal1.time_shift(1 * pq.ms) assert_same_attributes(result, self.signal1, exclude=['times', 't_start', 't_stop']) def test__time_shift_same_annotations(self): result = self.signal1.time_shift(1 * pq.ms) assert_same_annotations(result, self.signal1) def test__time_shift_same_array_annotations(self): result = self.signal1.time_shift(1 * pq.ms) assert_same_array_annotations(result, self.signal1) def test__time_shift_should_set_parents_to_None(self): # When time-shifting, a deep copy is made, # thus the reference to parent objects should be destroyed result = self.signal1.time_shift(1 * pq.ms) self.assertEqual(result.segment, None) self.assertEqual(result.channel_index, None) def test__time_shift_by_zero(self): shifted = self.signal1.time_shift(0 * pq.ms) assert_arrays_equal(shifted.times, self.signal1.times) def test__time_shift_same_units(self): shifted = self.signal1.time_shift(10 * pq.ms) assert_arrays_equal(shifted.times, self.signal1.times + 10 * pq.ms) def test__time_shift_different_units(self): shifted = self.signal1.time_shift(1 * pq.s) assert_arrays_equal(shifted.times, self.signal1.times + 1000 * pq.ms) # TODO: XXX ??? def test__copy_should_let_access_to_parents_objects(self): result = self.signal1.copy() self.assertIs(result.segment, self.signal1.segment) self.assertIs(result.channel_index, self.signal1.channel_index) def test__deepcopy_should_set_parents_objects_to_None(self): # Deepcopy should destroy references to parents result = copy.deepcopy(self.signal1) self.assertEqual(result.segment, None) self.assertEqual(result.channel_index, None) def test__getitem_should_return_single_quantity(self): result1 = self.signal1[0, 0] result2 = self.signal1[9, 0] self.assertIsInstance(result1, pq.Quantity) self.assertFalse(hasattr(result1, 'name')) self.assertFalse(hasattr(result1, 'description')) self.assertFalse(hasattr(result1, 'file_origin')) self.assertFalse(hasattr(result1, 'annotations')) self.assertFalse(hasattr(result1, 'array_annotations')) self.assertIsInstance(result2, pq.Quantity) self.assertFalse(hasattr(result2, 'name')) self.assertFalse(hasattr(result2, 'description')) self.assertFalse(hasattr(result2, 'file_origin')) self.assertFalse(hasattr(result2, 'annotations')) self.assertFalse(hasattr(result2, 'array_annotations')) self.assertEqual(result1, 0 * pq.nA) self.assertEqual(result2, 9 * pq.nA) def test__getitem_out_of_bounds_IndexError(self): self.assertRaises(IndexError, self.signal1.__getitem__, (10, 0)) def test_comparison_operators(self): assert_array_equal(self.signal1 >= 5 * pq.nA, np.array( [False, False, False, False, False, True, True, True, True, True]).reshape(-1, 1)) assert_array_equal(self.signal1 >= 5 * pq.pA, np.array( [False, True, True, True, True, True, True, True, True, True]).reshape(-1, 1)) assert_array_equal(self.signal1 == 5 * pq.nA, np.array( [False, False, False, False, False, True, False, False, False, False]).reshape(-1, 1)) assert_array_equal(self.signal1 == self.signal1, np.array( [True, True, True, True, True, True, True, True, True, True]).reshape(-1, 1)) def test__comparison_as_indexing_single_trace(self): self.assertEqual(self.signal1[self.signal1 == 5], [5 * pq.mV]) def test__comparison_as_indexing_double_trace(self): signal = AnalogSignal(np.arange(20).reshape((-1, 2)) * pq.V, sampling_rate=1 * pq.Hz) assert_array_equal(signal[signal < 10], np.array([[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]]).T * pq.V) def test__indexing_keeps_order_across_channels(self): # AnalogSignals with 10 traces each having 5 samples (eg. data[0] = [0,10,20,30,40]) data = np.array([range(10), range(10, 20), range(20, 30), range(30, 40), range(40, 50)]) mask = np.full((5, 10), fill_value=False, dtype=bool) # selecting one entry per trace mask[[0, 1, 0, 3, 0, 2, 4, 3, 1, 4], range(10)] = True signal = AnalogSignal(np.array(data) * pq.V, sampling_rate=1 * pq.Hz) assert_array_equal(signal[mask], np.array([[0, 11, 2, 33, 4, 25, 46, 37, 18, 49]]) * pq.V) def test__indexing_keeps_order_across_time(self): # AnalogSignals with 10 traces each having 5 samples (eg. data[0] = [0,10,20,30,40]) data = np.array([range(10), range(10, 20), range(20, 30), range(30, 40), range(40, 50)]) mask = np.full((5, 10), fill_value=False, dtype=bool) # selecting two entries per trace temporal_ids = [0, 1, 0, 3, 1, 2, 4, 2, 1, 4] + [4, 3, 2, 1, 0, 1, 2, 3, 2, 1] mask[temporal_ids, list(range(10)) + list(range(10))] = True signal = AnalogSignal(np.array(data) * pq.V, sampling_rate=1 * pq.Hz) assert_array_equal(signal[mask], np.array([[0, 11, 2, 13, 4, 15, 26, 27, 18, 19], [40, 31, 22, 33, 14, 25, 46, 37, 28, 49]]) * pq.V) def test__comparison_with_inconsistent_units_should_raise_Exception(self): self.assertRaises(ValueError, self.signal1.__gt__, 5 * pq.mV) def test__simple_statistics(self): self.assertEqual(self.signal1.max(), 9 * pq.nA) self.assertEqual(self.signal1.min(), 0 * pq.nA) self.assertEqual(self.signal1.mean(), 4.5 * pq.nA) def test__rescale_same(self): result = self.signal1.copy() result = result.rescale(pq.nA) self.assertIsInstance(result, AnalogSignal) assert_neo_object_is_compliant(result) self.assertEqual(result.name, 'spam') self.assertEqual(result.description, 'eggs') self.assertEqual(result.file_origin, 'testfile.txt') self.assertEqual(result.annotations, {'arg1': 'test'}) self.assertEqual(result.array_annotations, {'anno1': [23], 'anno2': ['A']}) self.assertIsInstance(result.array_annotations, ArrayDict) self.assertEqual(result.units, 1 * pq.nA) assert_array_equal(result.magnitude, self.data1.reshape(-1, 1)) assert_same_sub_schema(result, self.signal1) self.assertIsInstance(result.channel_index, ChannelIndex) self.assertIsInstance(result.segment, Segment) self.assertIs(result.channel_index, self.signal1.channel_index) self.assertIs(result.segment, self.signal1.segment) def test__rescale_new(self): result = self.signal1.copy() result = result.rescale(pq.pA) self.assertIsInstance(result, AnalogSignal) assert_neo_object_is_compliant(result) self.assertEqual(result.name, 'spam') self.assertEqual(result.description, 'eggs') self.assertEqual(result.file_origin, 'testfile.txt') self.assertEqual(result.annotations, {'arg1': 'test'}) self.assertEqual(result.array_annotations, {'anno1': [23], 'anno2': ['A']}) self.assertIsInstance(result.array_annotations, ArrayDict) self.assertEqual(result.units, 1 * pq.pA) assert_arrays_almost_equal(np.array(result), self.data1.reshape(-1, 1) * 1000., 1e-10) self.assertIsInstance(result.channel_index, ChannelIndex) self.assertIsInstance(result.segment, Segment) self.assertIs(result.channel_index, self.signal1.channel_index) self.assertIs(result.segment, self.signal1.segment) def test__rescale_new_incompatible_ValueError(self): self.assertRaises(ValueError, self.signal1.rescale, pq.mV) def test_as_array(self): sig_as_arr = self.signal1.as_array() self.assertIsInstance(sig_as_arr, np.ndarray) assert_array_equal(self.data1, sig_as_arr.flat) def test_as_quantity(self): sig_as_q = self.signal1.as_quantity() self.assertIsInstance(sig_as_q, pq.Quantity) assert_array_equal(self.data1, sig_as_q.magnitude.flat) def test_splice_1channel_inplace(self): signal_for_splicing = AnalogSignal([0.1, 0.1, 0.1], t_start=3 * pq.ms, sampling_rate=self.signal1.sampling_rate, units=pq.uA, array_annotations={'anno1': [0], 'anno2': ['C']}) result = self.signal1.splice(signal_for_splicing, copy=False) assert_array_equal(result.magnitude.flatten(), np.array([0.0, 1.0, 2.0, 100.0, 100.0, 100.0, 6.0, 7.0, 8.0, 9.0])) assert_array_equal(self.signal1, result) # in-place self.assertEqual(result.segment, self.signal1.segment) self.assertEqual(result.channel_index, self.signal1.channel_index) assert_array_equal(result.array_annotations['anno1'], np.array([23])) assert_array_equal(result.array_annotations['anno2'], np.array(['A'])) self.assertIsInstance(result.array_annotations, ArrayDict) def test_splice_1channel_with_copy(self): signal_for_splicing = AnalogSignal([0.1, 0.1, 0.1], t_start=3 * pq.ms, sampling_rate=self.signal1.sampling_rate, units=pq.uA, array_annotations={'anno1': [0], 'anno2': ['C']}) result = self.signal1.splice(signal_for_splicing, copy=True) assert_array_equal(result.magnitude.flatten(), np.array([0.0, 1.0, 2.0, 100.0, 100.0, 100.0, 6.0, 7.0, 8.0, 9.0])) assert_array_equal(self.signal1.magnitude.flatten(), np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])) self.assertIs(result.segment, None) self.assertIs(result.channel_index, None) assert_array_equal(result.array_annotations['anno1'], np.array([23])) assert_array_equal(result.array_annotations['anno2'], np.array(['A'])) self.assertIsInstance(result.array_annotations, ArrayDict) def test_splice_2channels_inplace(self): arr_ann1 = {'index': np.arange(10, 12)} arr_ann2 = {'index': np.arange(2), 'test': ['a', 'b']} signal = AnalogSignal(np.arange(20.0).reshape((10, 2)), sampling_rate=1 * pq.kHz, units="mV", array_annotations=arr_ann1) signal_for_splicing = AnalogSignal(np.array([[0.1, 0.0], [0.2, 0.0], [0.3, 0.0]]), t_start=3 * pq.ms, array_annotations=arr_ann2, sampling_rate=self.signal1.sampling_rate, units=pq.V) result = signal.splice(signal_for_splicing, copy=False) assert_array_equal(result.magnitude, np.array( [[0.0, 1.0], [2.0, 3.0], [4.0, 5.0], [100.0, 0.0], [200.0, 0.0], [300.0, 0.0], [12.0, 13.0], [14.0, 15.0], [16.0, 17.0], [18.0, 19.0]])) assert_array_equal(signal, result) # in-place # Array annotations are taken from the main signal assert_array_equal(result.array_annotations['index'], np.arange(10, 12)) self.assertIsInstance(result.array_annotations, ArrayDict) self.assertNotIn('test', result.array_annotations) def test_splice_1channel_invalid_t_start(self): signal_for_splicing = AnalogSignal([0.1, 0.1, 0.1], t_start=12 * pq.ms, # after the end of the signal sampling_rate=self.signal1.sampling_rate, units=pq.uA) self.assertRaises(ValueError, self.signal1.splice, signal_for_splicing, copy=False) def test_splice_1channel_invalid_t_stop(self): signal_for_splicing = AnalogSignal([0.1, 0.1, 0.1], t_start=8 * pq.ms, # too close to the end of the signal sampling_rate=self.signal1.sampling_rate, units=pq.uA) self.assertRaises(ValueError, self.signal1.splice, signal_for_splicing, copy=False) def test_splice_1channel_invalid_sampling_rate(self): signal_for_splicing = AnalogSignal([0.1, 0.1, 0.1], t_start=3 * pq.ms, sampling_rate=2 * self.signal1.sampling_rate, units=pq.uA) self.assertRaises(ValueError, self.signal1.splice, signal_for_splicing, copy=False) def test_splice_1channel_invalid_units(self): signal_for_splicing = AnalogSignal([0.1, 0.1, 0.1], t_start=3 * pq.ms, sampling_rate=self.signal1.sampling_rate, units=pq.uV) self.assertRaises(ValueError, self.signal1.splice, signal_for_splicing, copy=False) def test_array_annotations_getitem(self): data = np.arange(15).reshape(5, 3) * pq.mV arr_ann1 = [10, 15, 20] arr_ann2 = ['abc', 'def', 'ghi'] arr_anns = {'index': arr_ann1, 'label': arr_ann2} signal = AnalogSignal(data, sampling_rate=30000 * pq.Hz, array_annotations=arr_anns) # A time slice of all signals is selected, so all array annotations need to remain result1 = signal[0:2] assert_arrays_equal(result1.array_annotations['index'], np.array(arr_ann1)) assert_arrays_equal(result1.array_annotations['label'], np.array(arr_ann2)) self.assertIsInstance(result1.array_annotations, ArrayDict) # Only elements from signal with index 2 are selected, # so only those array_annotations should be returned result2 = signal[1:2, 2] assert_arrays_equal(result2.array_annotations['index'], np.array([20])) assert_arrays_equal(result2.array_annotations['label'], np.array(['ghi'])) self.assertIsInstance(result2.array_annotations, ArrayDict) # Because comparison of list with single element to scalar is possible, # we need to make sure that array_annotations remain arrays self.assertIsInstance(result2.array_annotations['index'], np.ndarray) self.assertIsInstance(result2.array_annotations['label'], np.ndarray) # Signals 0 and 1 are selected completely, # so their respective array_annotations should be returned result3 = signal[:, 0:2] assert_arrays_equal(result3.array_annotations['index'], np.array([10, 15])) assert_arrays_equal(result3.array_annotations['label'], np.array(['abc', 'def'])) self.assertIsInstance(result3.array_annotations, ArrayDict)
class TestArrayMethods(unittest.TestCase): def setUp(self): self.signal = AnalogSignal(numpy.arange(10.0), units="nA", sampling_rate=1*kHz) def test__slice_should_return_AnalogSignal(self): sub = self.signal[3:8] self.assertIsInstance(sub, AnalogSignal) self.assertEqual(sub.size, 5) self.assertEqual(sub.sampling_period, self.signal.sampling_period) self.assertEqual(sub.sampling_rate, self.signal.sampling_rate) self.assertEqual(sub.t_start, self.signal.t_start+3*sub.sampling_period) self.assertEqual(sub.t_stop, sub.t_start + 5*sub.sampling_period) # Test other attributes were copied over (in this case, defaults) self.assertEqual(sub.file_origin, self.signal.file_origin) self.assertEqual(sub.name, self.signal.name) self.assertEqual(sub.description, self.signal.description) self.assertEqual(sub.annotations, self.signal.annotations) sub = self.signal[3:8] self.assertEqual(sub.file_origin, self.signal.file_origin) self.assertEqual(sub.name, self.signal.name) self.assertEqual(sub.description, self.signal.description) self.assertEqual(sub.annotations, self.signal.annotations) def test__slice_with_attributes(self): # Set attributes, slice, test that they are copied self.signal.file_origin = 'crack.txt' self.signal.name = 'sig' self.signal.description = 'a signal' self.signal.annotate(ratname='Georges') # slice sub = self.signal[3:8] # tests from other slice test self.assertIsInstance(sub, AnalogSignal) self.assertEqual(sub.size, 5) self.assertEqual(sub.sampling_period, self.signal.sampling_period) self.assertEqual(sub.sampling_rate, self.signal.sampling_rate) self.assertEqual(sub.t_start, self.signal.t_start+3*sub.sampling_period) self.assertEqual(sub.t_stop, sub.t_start + 5*sub.sampling_period) # Test other attributes were copied over (in this case, set by user) self.assertEqual(sub.file_origin, self.signal.file_origin) self.assertEqual(sub.name, self.signal.name) self.assertEqual(sub.description, self.signal.description) self.assertEqual(sub.annotations, self.signal.annotations) self.assertEqual(sub.annotations, {'ratname': 'Georges'}) def test__slice_should_change_sampling_period(self): sub = self.signal[:2] self.assertEqual(sub.sampling_period, self.signal.sampling_period) sub = self.signal[::2] self.assertEqual(sub.sampling_period, self.signal.sampling_period * 2) sub = self.signal[1:7:2] self.assertEqual(sub.sampling_period, self.signal.sampling_period * 2) def test__getitem_should_return_single_quantity(self): self.assertEqual(self.signal[0], 0*nA) self.assertEqual(self.signal[9], 9*nA) self.assertRaises(IndexError, self.signal.__getitem__, 10) def test_comparison_operators(self): assert_arrays_equal(self.signal >= 5*nA, numpy.array([False, False, False, False, False, True, True, True, True, True])) assert_arrays_equal(self.signal >= 5*pA, numpy.array([False, True, True, True, True, True, True, True, True, True])) def test__comparison_with_inconsistent_units_should_raise_Exception(self): self.assertRaises(ValueError, self.signal.__gt__, 5*mV) def test_simple_statistics(self): self.assertEqual(self.signal.max(), 9*nA) self.assertEqual(self.signal.min(), 0*nA) self.assertEqual(self.signal.mean(), 4.5*nA)