def test__merge(self):
        self.signal1.description = None
        self.signal1.file_origin = None
        assert_neo_object_is_compliant(self.signal1)

        data3 = np.arange(1000.0, 1066.0).reshape((11, 6)) * pq.uV
        data3scale = data3.rescale(self.data1quant.units)

        signal2 = AnalogSignal(self.data1quant,
                                    sampling_rate=1*pq.kHz,
                                    name='signal2',
                                    description='test signal',
                                    file_origin='testfile.txt')
        signal3 = AnalogSignal(data3,
                                    units="uV", sampling_rate=1*pq.kHz,
                                    name='signal3',
                                    description='test signal',
                                    file_origin='testfile.txt')
        signal4 = AnalogSignal(data3,
                                    units="uV", sampling_rate=1*pq.kHz,
                                    name='signal4',
                                    description='test signal',
                                    file_origin='testfile.txt')
        
        merged13 = self.signal1.merge(signal3)        
        merged23 = signal2.merge(signal3)
        merged24 = signal2.merge(signal4)
        mergeddata13 = np.array(merged13)
        mergeddata23 = np.array(merged23)
        mergeddata24 = np.array(merged24)

        targdata13 = np.hstack([self.data1quant, data3scale])
        targdata23 = np.hstack([self.data1quant, data3scale])
        targdata24 = np.hstack([self.data1quant, data3scale])

        assert_neo_object_is_compliant(signal2)
        assert_neo_object_is_compliant(signal3)
        assert_neo_object_is_compliant(merged13)
        assert_neo_object_is_compliant(merged23)
        assert_neo_object_is_compliant(merged24)

        self.assertEqual(merged13[0, 4], 4*pq.mV)
        self.assertEqual(merged23[0, 4], 4*pq.mV)
        self.assertEqual(merged13[0, 5], 1*pq.mV)
        self.assertEqual(merged23[0, 5], 1*pq.mV)
        self.assertEqual(merged13[10, 10], 1.065*pq.mV)
        self.assertEqual(merged23[10, 10], 1.065*pq.mV)
        self.assertEqual(merged13.t_stop, self.signal1.t_stop)
        self.assertEqual(merged23.t_stop, self.signal1.t_stop)

        self.assertEqual(merged13.name, 'merge(spam, signal3)')
        self.assertEqual(merged23.name, 'merge(signal2, signal3)')
        self.assertEqual(merged13.description, 'merge(None, test signal)')
        self.assertEqual(merged23.description, 'test signal')
        self.assertEqual(merged13.file_origin, 'merge(None, testfile.txt)')
        self.assertEqual(merged23.file_origin, 'testfile.txt')

        assert_arrays_equal(mergeddata13, targdata13)
        assert_arrays_equal(mergeddata23, targdata23)
        assert_arrays_equal(mergeddata24, targdata24)
Example #2
0
    def test__pickle(self):
        signal1 = AnalogSignal([1, 2, 3, 4], sampling_period=1 * pq.ms, units=pq.S)
        signal1.annotations['index'] = 2
        signal1.channel_index = ChannelIndex(index=[0])
        signal1.array_annotate(**{'anno1': [23], 'anno2': ['A']})

        fobj = open('./pickle', 'wb')
        pickle.dump(signal1, fobj)
        fobj.close()

        fobj = open('./pickle', 'rb')
        try:
            signal2 = pickle.load(fobj)
        except ValueError:
            signal2 = None

        assert_array_equal(signal1, signal2)
        assert_array_equal(signal2.channel_index.index, np.array([0]))
        assert_array_equal(signal2.array_annotations['anno1'], np.array([23]))
        self.assertIsInstance(signal2.array_annotations, ArrayDict)
        # Make sure the dict can perform correct checks after unpickling
        signal2.array_annotations['anno3'] = [2]
        with self.assertRaises(ValueError):
            signal2.array_annotations['anno4'] = [2, 1]
        fobj.close()
        os.remove('./pickle')
Example #3
0
 def __getitem__(self, i):
     '''
     Get the item or slice :attr:`i`.
     '''
     obj = super(BaseAnalogSignal, self).__getitem__(i)
     if isinstance(i, int):
         return obj
     elif isinstance(i, tuple):
         j, k = i
         if isinstance(k, int):
             if isinstance(j, slice):  # extract an AnalogSignal
                 obj = AnalogSignal(obj, sampling_rate=self.sampling_rate)
                 if j.start:
                     obj.t_start = (self.t_start +
                                    j.start * self.sampling_period)
             # return a Quantity (for some reason quantities does not
             # return a Quantity in this case)
             elif isinstance(j, int):
                 obj = pq.Quantity(obj, units=self.units)
             return obj
         elif isinstance(j, int):  # extract a quantity array
             # should be a better way to do this
             obj = pq.Quantity(np.array(obj), units=obj.units)
             return obj
         else:
             return obj
     elif isinstance(i, slice):
         if i.start:
             obj.t_start = self.t_start + i.start * self.sampling_period
         return obj
     else:
         raise IndexError("index should be an integer, tuple or slice")
 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")
     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)])
     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)])
 def setUp(self):
     self.data1 = np.arange(55.0).reshape((11, 5))
     self.data1quant = self.data1 * pq.nA
     self.arr_ann1 = {'anno1': np.arange(5), 'anno2': ['a', 'b', 'c', 'd', 'e']}
     self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1 * pq.kHz, name='spam',
                                 description='eggs', file_origin='testfile.txt',
                                 array_annotations=self.arr_ann1, arg1='test')
     self.data2 = np.array([[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]).T
     self.data2quant = self.data2 * pq.mV
     self.arr_ann2 = {'anno1': [10, 11], 'anno2': ['k', 'l']}
     self.signal2 = AnalogSignal(self.data2quant, sampling_rate=1.0 * pq.Hz, name='spam',
                                 description='eggs', file_origin='testfile.txt',
                                 array_annotations=self.arr_ann2, arg1='test')
 def setUp(self):
     self.data1 = np.arange(55.0).reshape((11, 5))
     self.data1quant = self.data1 * pq.nA
     self.signal1 = AnalogSignal(self.data1quant,
                                      sampling_rate=1*pq.kHz,
                                      name='spam', description='eggs',
                                      file_origin='testfile.txt',
                                      arg1='test')
     self.data2 = np.array([[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]).T
     self.data2quant = self.data2 * pq.mV
     self.signal2 = AnalogSignal(self.data2quant,
                                      sampling_rate=1.0*pq.Hz,
                                      name='spam', description='eggs',
                                      file_origin='testfile.txt',
                                      arg1='test')
    def test__pickle(self):
        a = AnalogSignal([1,2,3,4],sampling_period=1*pq.ms,units=pq.S)
        a.annotations['index'] = 2

        f = open('./pickle','wb')
        pickle.dump(a,f)
        f.close()

        f = open('./pickle','rb')
        try:
            b = pickle.load(f)
        except ValueError:
            b = None

        assert_arrays_equal(a, b)
        f.close()
        os.remove('./pickle')
 def setUp(self):
     self.data1 = np.arange(10.0)
     self.data1quant = self.data1 * pq.nA
     self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1*pq.kHz,
                                      name='spam', description='eggs',
                                      file_origin='testfile.txt', arg1='test')
     self.signal1.segment = Segment()
     self.signal1.channel_index = ChannelIndex(index=[0])
Example #9
0
 def setUp(self):
     self.data1 = np.arange(10.0)
     self.data1quant = self.data1 * pq.mV
     self.signal1 = AnalogSignal(self.data1quant,
                                      sampling_rate=1*pq.kHz,
                                      name='spam', description='eggs',
                                      file_origin='testfile.txt',
                                      arg1='test')
Example #10
0
 def setUp(self):
     self.t_start = [0.0 * pq.ms, 100 * pq.ms, -200 * pq.ms]
     self.rates = [1 * pq.kHz, 420 * pq.Hz, 999 * pq.Hz]
     self.rates2 = [2 * pq.kHz, 290 * pq.Hz, 1111 * pq.Hz]
     self.data = [np.arange(10.0) * pq.nA, np.arange(-100.0, 100.0, 10.0) * pq.mV,
                  np.random.uniform(size=100) * pq.uV]
     self.signals = [AnalogSignal(D, sampling_rate=r, t_start=t, testattr='test') for r, D, t in
                     zip(self.rates, self.data, self.t_start)]
Example #11
0
 def test__create_from_np_array(self):
     data = np.arange(10.0)
     rate = 1 * pq.kHz
     signal = AnalogSignal(data, sampling_rate=rate, units="uV")
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal.t_start, 0 * pq.ms)
     self.assertEqual(signal.t_stop, data.size / rate)
     self.assertEqual(signal[9, 0], 0.009 * pq.mV)
Example #12
0
    def test__create_with_additional_argument(self):
        signal = AnalogSignal([1, 2, 3], units="mV", sampling_rate=1*pq.kHz,
                              file_origin='crack.txt', ratname='Nicolas')
        assert_neo_object_is_compliant(signal)
        self.assertEqual(signal.annotations, {'ratname': 'Nicolas'})

        # This one is universally recommended and handled by BaseNeo
        self.assertEqual(signal.file_origin, 'crack.txt')
Example #13
0
 def test__create2D_with_copy_false_should_return_view(self):
     data = np.arange(10.0) * pq.mV
     data = data.reshape((5, 2))
     rate = 5000*pq.Hz
     signal = AnalogSignal(data, copy=False, sampling_rate=rate)
     data[3, 0] = 99*pq.mV
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal[3, 0], 99*pq.mV)
Example #14
0
 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 setUp(self):
     self.data1 = np.arange(55.0).reshape((11, 5))
     self.data1quant = self.data1 * pq.mV
     self.signal1 = AnalogSignal(self.data1quant,
                                 sampling_rate=1 * pq.kHz,
                                 name='spam',
                                 description='eggs',
                                 file_origin='testfile.txt',
                                 arg1='test')
     self.data2 = np.arange(100.0, 155.0).reshape((11, 5))
     self.data2quant = self.data2 * pq.mV
     self.signal2 = AnalogSignal(self.data2quant,
                                 sampling_rate=1 * pq.kHz,
                                 name='spam',
                                 description='eggs',
                                 file_origin='testfile.txt',
                                 arg1='test')
Example #16
0
 def test__create_from_quantities_array(self):
     data = np.arange(10.0) * pq.mV
     rate = 5000 * pq.Hz
     signal = AnalogSignal(data, sampling_rate=rate)
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal.t_start, 0 * pq.ms)
     self.assertEqual(signal.t_stop, data.size / rate)
     self.assertEqual(signal[9, 0], 0.009 * pq.V)
Example #17
0
 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)
Example #18
0
 def test__create_from_list(self):
     data = range(10)
     rate = 1000*pq.Hz
     signal = AnalogSignal(data, sampling_rate=rate, units="mV")
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal.t_start, 0*pq.ms)
     self.assertEqual(signal.t_stop, len(data)/rate)
     self.assertEqual(signal[9, 0], 9000*pq.uV)
Example #19
0
 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)
Example #20
0
 def test__create_from_quantities_array(self):
     data = np.arange(20.0).reshape((10, 2)) * pq.mV
     rate = 5000*pq.Hz
     signal = AnalogSignal(data, sampling_rate=rate)
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal.t_start, 0*pq.ms)
     self.assertEqual(signal.t_stop, data.shape[0]/rate)
     self.assertEqual(signal[9, 0], 18000*pq.uV)
Example #21
0
    def resample(self, sample_count, **kwargs):
        """
        Resample the data points of the signal.
        This method interpolates the signal and returns a new signal with a fixed number of
        samples defined by `sample_count`.
        This function is a wrapper of scipy.signal.resample and accepts the same set of keyword
        arguments, except for specifying the axis of resampling which is fixed to the first axis
        here, and the sample positions. .

        Parameters:
        -----------
        sample_count: integer
            Number of desired samples. The resulting signal starts at the same sample as the
            original and is sampled regularly.

        Returns:
        --------
        resampled_signal: :class:`AnalogSignal`
            New instance of a :class:`AnalogSignal` object containing the resampled data points.
            The original :class:`AnalogSignal` is not modified.
        """

        if not HAVE_SCIPY:
            raise ImportError('Resampling requires availability of scipy.signal')

        # Resampling is only permitted along the time axis (axis=0)
        if 'axis' in kwargs:
            kwargs.pop('axis')
        if 't' in kwargs:
            kwargs.pop('t')

        resampled_data, resampled_times = scipy.signal.resample(self.magnitude, sample_count,
                                                                t=self.times.magnitude,
                                                                axis=0, **kwargs)

        new_sampling_rate = (sample_count - 1) / self.duration
        resampled_signal = AnalogSignal(resampled_data, units=self.units, dtype=self.dtype,
                                        t_start=self.t_start,
                                        sampling_rate=new_sampling_rate,
                                        array_annotations=self.array_annotations.copy(),
                                        **self.annotations.copy())

        # since the number of channels stays the same, we can also copy array annotations here
        resampled_signal.array_annotations = self.array_annotations.copy()
        return resampled_signal
Example #22
0
    def test__add_signals_with_inconsistent_data_complement_ValueError(self):
        self.signal1.t_start = 0.0*pq.ms
        assert_neo_object_is_compliant(self.signal1)

        signal2 = AnalogSignal(np.arange(10.0), units="mV",
                                    t_start=100.0*pq.ms, sampling_rate=0.5*pq.kHz)
        assert_neo_object_is_compliant(signal2)

        self.assertRaises(ValueError, self.signal1.__add__, signal2)
Example #23
0
    def test__pickle(self):
        signal1 = AnalogSignal([1, 2, 3, 4], sampling_period=1*pq.ms,
                                    units=pq.S)
        signal1.annotations['index'] = 2

        fobj = open('./pickle', 'wb')
        pickle.dump(signal1, fobj)
        fobj.close()

        fobj = open('./pickle', 'rb')
        try:
            signal2 = pickle.load(fobj)
        except ValueError:
            signal2 = None

        assert_array_equal(signal1, signal2)
        fobj.close()
        os.remove('./pickle')
 def test__create_from_numpy_array(self):
     data = np.arange(20.0).reshape((10, 2))
     rate = 1 * pq.kHz
     signal = AnalogSignal(data, sampling_rate=rate, units="uV")
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal.t_start, 0 * pq.ms)
     self.assertEqual(signal.t_stop, data.shape[0] / rate)
     self.assertEqual(signal[9, 0], 0.018 * pq.mV)
     self.assertEqual(signal[9, 1], 19 * pq.uV)
Example #25
0
    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__create_from_list(self):
     data = [(i, i, i) for i in range(10)]  # 3 signals each with 10 samples
     rate = 1000 * pq.Hz
     signal = AnalogSignal(data, sampling_rate=rate, units="mV")
     assert_neo_object_is_compliant(signal)
     self.assertEqual(signal.shape, (10, 3))
     self.assertEqual(signal.t_start, 0 * pq.ms)
     self.assertEqual(signal.t_stop, len(data) / rate)
     self.assertEqual(signal[9, 0], 9000 * pq.uV)
Example #27
0
    def test__pickle(self):
        signal1 = AnalogSignal([1, 2, 3, 4], sampling_period=1*pq.ms,
                                    units=pq.S)
        signal1.annotations['index'] = 2

        fobj = open('./pickle', 'wb')
        pickle.dump(signal1, fobj)
        fobj.close()

        fobj = open('./pickle', 'rb')
        try:
            signal2 = pickle.load(fobj)
        except ValueError:
            signal2 = None

        assert_array_equal(signal1, signal2)
        fobj.close()
        os.remove('./pickle')
    def test__pickle(self):
        signal1 = AnalogSignal([1, 2, 3, 4], sampling_period=1 * pq.ms, units=pq.S, channel_index=42)
        signal1.annotations["index"] = 2

        fobj = open("./pickle", "wb")
        pickle.dump(signal1, fobj)
        fobj.close()

        fobj = open("./pickle", "rb")
        try:
            signal2 = pickle.load(fobj)
        except ValueError:
            signal2 = None

        assert_arrays_equal(signal1, signal2)
        self.assertEqual(signal1.channel_index, signal2.channel_index, 42)
        fobj.close()
        os.remove("./pickle")
Example #29
0
 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)
Example #30
0
 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)
Example #31
0
 def setUp(self):
     self.t_start = [0.0*pq.ms, 100*pq.ms, -200*pq.ms]
     self.rates = [1*pq.kHz, 420*pq.Hz, 999*pq.Hz]
     self.data = [np.arange(10.0).reshape((5, 2))*pq.nA,
                  np.arange(-100.0, 100.0, 10.0).reshape((4, 5))*pq.mV,
                  np.random.uniform(size=(100, 4))*pq.uV]
     self.signals = [AnalogSignal(D, sampling_rate=r, t_start=t)
                     for r, D, t in zip(self.rates,
                                        self.data,
                                        self.t_start)]
Example #32
0
 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)
     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)
 def setUp(self):
     self.data1 = np.arange(10.0)
     self.data1quant = self.data1 * pq.nA
     self.signal1 = AnalogSignal(
         self.data1quant,
         sampling_rate=1 * pq.kHz,
         name="spam",
         description="eggs",
         file_origin="testfile.txt",
         arg1="test",
     )
 def test__subtracting_a_constant_from_a_signal_should_preserve_data_complement(
         self):
     signal = AnalogSignal(numpy.arange(10.0),
                           units="mV",
                           sampling_rate=1 * kHz,
                           name="foo")
     signal_with_offset = signal - 65 * mV
     self.assertEqual(signal[9], 9 * mV)
     self.assertEqual(signal_with_offset[9], -56 * mV)
     for attr in "t_start", "sampling_rate":
         self.assertEqual(getattr(signal, attr),
                          getattr(signal_with_offset, attr))
 def test__dividing_a_signal_by_a_constant_should_preserve_data_complement(
         self):
     signal = AnalogSignal(numpy.arange(10.0),
                           units="mV",
                           sampling_rate=1 * kHz,
                           name="foo")
     amplified_signal = signal / 0.5
     self.assertEqual(signal[9], 9 * mV)
     self.assertEqual(amplified_signal[9], 18 * mV)
     for attr in "t_start", "sampling_rate":
         self.assertEqual(getattr(signal, attr),
                          getattr(amplified_signal, attr))
 def test__subtracting_a_signal_from_a_constant_should_return_a_signal(
         self):
     signal = AnalogSignal(numpy.arange(10.0),
                           units="mV",
                           sampling_rate=1 * kHz,
                           name="foo")
     signal_with_offset = 10 * mV - signal
     self.assertEqual(signal[9], 9 * mV)
     self.assertEqual(signal_with_offset[9], 1 * mV)
     for attr in "t_start", "sampling_rate":
         self.assertEqual(getattr(signal, attr),
                          getattr(signal_with_offset, attr))
    def test__pickle(self):
        a = AnalogSignal([1, 2, 3, 4],
                         sampling_period=1 * pq.ms,
                         units=pq.S,
                         channel_index=42)
        a.annotations['index'] = 2

        f = open('./pickle', 'wb')
        pickle.dump(a, f)
        f.close()

        f = open('./pickle', 'rb')
        try:
            b = pickle.load(f)
        except ValueError:
            b = None

        assert_arrays_equal(a, b)
        self.assertEqual(a.channel_index, b.channel_index, 42)
        f.close()
        os.remove('./pickle')
 def setUp(self):
     self.t_start = [0.0 * ms, 100 * ms, -200 * ms]
     self.rates = [1 * kHz, 420 * Hz, 999 * Hz]
     self.data = [
         numpy.arange(10.0) * nA,
         numpy.arange(-100.0, 100.0, 10.0) * mV,
         numpy.random.uniform(size=100) * uV
     ]
     self.signals = [
         AnalogSignal(D, sampling_rate=r, t_start=t)
         for r, D, t in zip(self.rates, self.data, self.t_start)
     ]
Example #39
0
 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)
     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)
Example #40
0
    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)
Example #41
0
 def test_splice_2channels_inplace(self):
     signal = AnalogSignal(np.arange(20.0).reshape((10, 2)),
                           sampling_rate=1 * pq.kHz,
                           units="mV")
     signal_for_splicing = AnalogSignal(np.array([[0.1, 0.0], [0.2, 0.0], [0.3, 0.0]]),
                                        t_start=3 * pq.ms,
                                        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
 def test_splice_2channels_inplace(self):
     signal = AnalogSignal(np.arange(20.0).reshape((10, 2)),
                           sampling_rate=1 * pq.kHz,
                           units="mV")
     signal_for_splicing = AnalogSignal(np.array([[0.1, 0.0], [0.2, 0.0], [0.3, 0.0]]),
                                        t_start=3*pq.ms,
                                        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
    def test__pickle(self):
        signal1 = AnalogSignal([1, 2, 3, 4],
                               sampling_period=1 * pq.ms,
                               units=pq.S)
        signal1.annotations['index'] = 2
        signal1.channel_index = ChannelIndex(index=[0])
        signal1.array_annotate(**{'anno1': [23], 'anno2': ['A']})

        fobj = open('./pickle', 'wb')
        pickle.dump(signal1, fobj)
        fobj.close()

        fobj = open('./pickle', 'rb')
        try:
            signal2 = pickle.load(fobj)
        except ValueError:
            signal2 = None

        assert_array_equal(signal1, signal2)
        assert_array_equal(signal2.channel_index.index, np.array([0]))
        assert_array_equal(signal2.array_annotations['anno1'], np.array([23]))
        self.assertIsInstance(signal2.array_annotations, ArrayDict)
        # Make sure the dict can perform correct checks after unpickling
        signal2.array_annotations['anno3'] = [2]
        with self.assertRaises(ValueError):
            signal2.array_annotations['anno4'] = [2, 1]
        fobj.close()
        os.remove('./pickle')
Example #44
0
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__slice_should_let_access_to_parents_objects(self):
        result = self.signal1.time_slice(1 * pq.ms, 3 * pq.ms)
        self.assertEqual(result.segment, self.signal1.segment)
        self.assertEqual(result.channel_index, self.signal1.channel_index)

    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__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_let_access_to_parents_objects(self):
        result = copy.deepcopy(self.signal1)
        self.assertIsInstance(result.segment, Segment)
        self.assertIsInstance(result.channel_index, ChannelIndex)
        assert_same_sub_schema(result.segment, self.signal1.segment)
        assert_same_sub_schema(result.channel_index, self.signal1.channel_index)

    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 TestAnalogSignalArrayCombination(unittest.TestCase):
    def setUp(self):
        self.data1 = np.arange(55.0).reshape((11, 5))
        self.data1quant = self.data1 * pq.mV
        self.signal1 = AnalogSignal(self.data1quant,
                                         sampling_rate=1*pq.kHz,
                                         name='spam', description='eggs',
                                         file_origin='testfile.txt',
                                         arg1='test')
        self.data2 = np.arange(100.0, 155.0).reshape((11, 5))
        self.data2quant = self.data2 * pq.mV
        self.signal2 = AnalogSignal(self.data2quant,
                                         sampling_rate=1*pq.kHz,
                                         name='spam', description='eggs',
                                         file_origin='testfile.txt',
                                         arg1='test')

    def test__compliant(self):
        assert_neo_object_is_compliant(self.signal1)
        self.assertEqual(self.signal1.name, 'spam')
        self.assertEqual(self.signal1.description, 'eggs')
        self.assertEqual(self.signal1.file_origin, 'testfile.txt')
        self.assertEqual(self.signal1.annotations, {'arg1': 'test'})

        assert_neo_object_is_compliant(self.signal2)
        self.assertEqual(self.signal2.name, 'spam')
        self.assertEqual(self.signal2.description, 'eggs')
        self.assertEqual(self.signal2.file_origin, 'testfile.txt')
        self.assertEqual(self.signal2.annotations, {'arg1': 'test'})

    def test__add_const_quantity_should_preserve_data_complement(self):
        result = self.signal1 + 0.065*pq.V
        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'})

        # time zero, signal index 4
        assert_arrays_equal(result, self.data1 + 65)
        self.assertEqual(self.signal1[0, 4], 4*pq.mV)
        self.assertEqual(result[0, 4], 69000*pq.uV)
        self.assertEqual(self.signal1.t_start, result.t_start)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__add_two_consistent_signals_should_preserve_data_complement(self):
        result = self.signal1 + self.signal2
        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'})

        targdata = np.arange(100.0, 210.0, 2.0).reshape((11, 5))
        targ = AnalogSignal(targdata, units="mV",
                                 sampling_rate=1*pq.kHz,
                                 name='spam', description='eggs',
                                 file_origin='testfile.txt', arg1='test')
        assert_neo_object_is_compliant(targ)

        assert_arrays_equal(result, targdata)
        assert_same_sub_schema(result, targ)

    def test__add_signals_with_inconsistent_data_complement_ValueError(self):
        self.signal2.sampling_rate = 0.5*pq.kHz
        assert_neo_object_is_compliant(self.signal2)

        self.assertRaises(ValueError, self.signal1.__add__, self.signal2)

    def test__subtract_const_should_preserve_data_complement(self):
        result = self.signal1 - 65*pq.mV
        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(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), -56)
        assert_arrays_equal(result, self.data1 - 65)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__subtract_from_const_should_return_signal(self):
        result = 10*pq.mV - self.signal1
        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(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), 1)
        assert_arrays_equal(result, 10 - self.data1)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__mult_by_const_float_should_preserve_data_complement(self):
        result = self.signal1*2
        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(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), 18)
        assert_arrays_equal(result, self.data1*2)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__divide_by_const_should_preserve_data_complement(self):
        result = self.signal1/0.5
        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(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), 18)
        assert_arrays_equal(result, self.data1/0.5)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__merge(self):
        self.signal1.description = None
        self.signal1.file_origin = None
        assert_neo_object_is_compliant(self.signal1)

        data3 = np.arange(1000.0, 1066.0).reshape((11, 6)) * pq.uV
        data3scale = data3.rescale(self.data1quant.units)

        signal2 = AnalogSignal(self.data1quant,
                                    sampling_rate=1*pq.kHz,
                                    name='signal2',
                                    description='test signal',
                                    file_origin='testfile.txt')
        signal3 = AnalogSignal(data3,
                                    units="uV", sampling_rate=1*pq.kHz,
                                    name='signal3',
                                    description='test signal',
                                    file_origin='testfile.txt')
        signal4 = AnalogSignal(data3,
                                    units="uV", sampling_rate=1*pq.kHz,
                                    name='signal4',
                                    description='test signal',
                                    file_origin='testfile.txt')
        
        merged13 = self.signal1.merge(signal3)        
        merged23 = signal2.merge(signal3)
        merged24 = signal2.merge(signal4)
        mergeddata13 = np.array(merged13)
        mergeddata23 = np.array(merged23)
        mergeddata24 = np.array(merged24)

        targdata13 = np.hstack([self.data1quant, data3scale])
        targdata23 = np.hstack([self.data1quant, data3scale])
        targdata24 = np.hstack([self.data1quant, data3scale])

        assert_neo_object_is_compliant(signal2)
        assert_neo_object_is_compliant(signal3)
        assert_neo_object_is_compliant(merged13)
        assert_neo_object_is_compliant(merged23)
        assert_neo_object_is_compliant(merged24)

        self.assertEqual(merged13[0, 4], 4*pq.mV)
        self.assertEqual(merged23[0, 4], 4*pq.mV)
        self.assertEqual(merged13[0, 5], 1*pq.mV)
        self.assertEqual(merged23[0, 5], 1*pq.mV)
        self.assertEqual(merged13[10, 10], 1.065*pq.mV)
        self.assertEqual(merged23[10, 10], 1.065*pq.mV)
        self.assertEqual(merged13.t_stop, self.signal1.t_stop)
        self.assertEqual(merged23.t_stop, self.signal1.t_stop)

        self.assertEqual(merged13.name, 'merge(spam, signal3)')
        self.assertEqual(merged23.name, 'merge(signal2, signal3)')
        self.assertEqual(merged13.description, 'merge(None, test signal)')
        self.assertEqual(merged23.description, 'test signal')
        self.assertEqual(merged13.file_origin, 'merge(None, testfile.txt)')
        self.assertEqual(merged23.file_origin, 'testfile.txt')

        assert_arrays_equal(mergeddata13, targdata13)
        assert_arrays_equal(mergeddata23, targdata23)
        assert_arrays_equal(mergeddata24, targdata24)
class TestAnalogSignalArrayMethods(unittest.TestCase):
    def setUp(self):
        self.data1 = np.arange(10.0)
        self.data1quant = self.data1 * pq.nA
        self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1*pq.kHz,
                                         name='spam', description='eggs',
                                         file_origin='testfile.txt', arg1='test')
        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)
            self.assertEqual(result.name, 'spam')         # should slicing really preserve name and description?
            self.assertEqual(result.description, 'eggs')  # perhaps these should be modified to indicate the slice?
            self.assertEqual(result.file_origin, 'testfile.txt')
            self.assertEqual(result.annotations, {'arg1': 'test'})

            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__slice_should_let_access_to_parents_objects(self):
        result =  self.signal1.time_slice(1*pq.ms,3*pq.ms)
        self.assertEqual(result.segment, self.signal1.segment)
        self.assertEqual(result.channel_index, self.signal1.channel_index)

    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.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.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(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__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_let_access_to_parents_objects(self):
        result = copy.deepcopy(self.signal1)
        self.assertIsInstance(result.segment, Segment)
        self.assertIsInstance(result.channel_index, ChannelIndex)
        assert_same_sub_schema(result.segment, self.signal1.segment)
        assert_same_sub_schema(result.channel_index, self.signal1.channel_index)

    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.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.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))

    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.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.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)
        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)

    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)
        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)

    def test_splice_2channels_inplace(self):
        signal = AnalogSignal(np.arange(20.0).reshape((10, 2)),
                              sampling_rate=1 * pq.kHz,
                              units="mV")
        signal_for_splicing = AnalogSignal(np.array([[0.1, 0.0], [0.2, 0.0], [0.3, 0.0]]),
                                           t_start=3*pq.ms,
                                           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

    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 setUp(self):
     self.data1 = np.arange(10.0)
     self.data1quant = self.data1 * pq.nA
     self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1*pq.kHz,
                                 name='spam', description='eggs',
                                 file_origin='testfile.txt', arg1='test')
class TestAnalogSignalArrayMethods(unittest.TestCase):
    def setUp(self):
        self.data1 = np.arange(10.0)
        self.data1quant = self.data1 * pq.nA
        self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1*pq.kHz,
                                    name='spam', description='eggs',
                                    file_origin='testfile.txt', arg1='test')

    def test__compliant(self):
        assert_neo_object_is_compliant(self.signal1)

    def test__slice_should_return_AnalogSignal(self):
        # slice
        result = self.signal1[3:8]
        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.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_arrays_equal(result, self.data1[3:8])

        # 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__slice_should_change_sampling_period(self):
        result1 = self.signal1[:2]
        result2 = self.signal1[::2]
        result3 = self.signal1[1:7:2]

        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.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.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(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_arrays_equal(result1, self.data1[:2])
        assert_arrays_equal(result2, self.data1[::2])
        assert_arrays_equal(result3, self.data1[1:7:2])

    def test__getitem_should_return_single_quantity(self):
        result1 = self.signal1[0]
        result2 = self.signal1[9]

        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.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.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)

    def test_comparison_operators(self):
        assert_arrays_equal(self.signal1 >= 5*pq.nA,
                            np.array([False, False, False, False, False,
                                      True, True, True, True, True]))
        assert_arrays_equal(self.signal1 >= 5*pq.pA,
                            np.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.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.units, 1*pq.nA)
        assert_arrays_equal(result, self.data1)
        assert_same_sub_schema(result, self.signal1)

    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.units, 1*pq.pA)
        assert_arrays_almost_equal(np.array(result), self.data1*1000., 1e-10)

    def test__rescale_new_incompatible_ValueError(self):
        self.assertRaises(ValueError, self.signal1.rescale, pq.mV)
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)
 def setUp(self):
     self.signal = AnalogSignal(numpy.arange(10.0), units="nA", sampling_rate=1*kHz)
Example #51
0
class TestAnalogSignalArrayMethods(unittest.TestCase):
    def setUp(self):
        self.data1 = np.arange(10.0)
        self.data1quant = self.data1 * pq.nA
        self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1*pq.kHz,
                                         name='spam', description='eggs',
                                         file_origin='testfile.txt', arg1='test')
        self.signal1.segment = 1
        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
        result = self.signal1[3:8, 0]
        self.assertIsInstance(result, AnalogSignal)
        assert_neo_object_is_compliant(result)
        self.assertEqual(result.name, 'spam')         # should slicing really preserve name and description?
        self.assertEqual(result.description, 'eggs')  # perhaps these should be modified to indicate the slice?
        self.assertEqual(result.file_origin, 'testfile.txt')
        self.assertEqual(result.annotations, {'arg1': 'test'})

        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__slice_should_let_access_to_parents_objects(self):
        result =  self.signal1.time_slice(1*pq.ms,3*pq.ms)
        self.assertEqual(result.segment, self.signal1.segment)
        self.assertEqual(result.channel_index, self.signal1.channel_index)

    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.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.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(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")
        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)])
        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)])

    def test__copy_should_let_access_to_parents_objects(self):
        ##copy
        result =  self.signal1.copy()
        self.assertEqual(result.segment, self.signal1.segment)
        self.assertEqual(result.channel_index, self.signal1.channel_index)
        ## deep copy (not fixed yet)
        #result = copy.deepcopy(self.signal1)
        #self.assertEqual(result.segment, self.signal1.segment)
        #self.assertEqual(result.channel_index, self.signal1.channel_index)

    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.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.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))

    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.units, 1*pq.nA)
        assert_array_equal(result.magnitude, self.data1.reshape(-1, 1))
        assert_same_sub_schema(result, self.signal1)

    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.units, 1*pq.pA)
        assert_arrays_almost_equal(np.array(result), self.data1.reshape(-1, 1)*1000., 1e-10)

    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)
class TestAnalogSignalArrayArrayMethods(unittest.TestCase):
    def setUp(self):
        self.data1 = np.arange(55.0).reshape((11, 5))
        self.data1quant = self.data1 * pq.nA
        self.arr_ann1 = {'anno1': np.arange(5), 'anno2': ['a', 'b', 'c', 'd', 'e']}
        self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1 * pq.kHz, name='spam',
                                    description='eggs', file_origin='testfile.txt',
                                    array_annotations=self.arr_ann1, arg1='test')
        self.data2 = np.array([[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]).T
        self.data2quant = self.data2 * pq.mV
        self.arr_ann2 = {'anno1': [10, 11], 'anno2': ['k', 'l']}
        self.signal2 = AnalogSignal(self.data2quant, sampling_rate=1.0 * pq.Hz, name='spam',
                                    description='eggs', file_origin='testfile.txt',
                                    array_annotations=self.arr_ann2, arg1='test')

    def test__compliant(self):
        assert_neo_object_is_compliant(self.signal1)
        self.assertEqual(self.signal1.name, 'spam')
        self.assertEqual(self.signal1.description, 'eggs')
        self.assertEqual(self.signal1.file_origin, 'testfile.txt')
        self.assertEqual(self.signal1.annotations, {'arg1': 'test'})
        assert_arrays_equal(self.signal1.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(self.signal1.array_annotations['anno2'],
                            np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(self.signal1.array_annotations, ArrayDict)

        assert_neo_object_is_compliant(self.signal2)
        self.assertEqual(self.signal2.name, 'spam')
        self.assertEqual(self.signal2.description, 'eggs')
        self.assertEqual(self.signal2.file_origin, 'testfile.txt')
        self.assertEqual(self.signal2.annotations, {'arg1': 'test'})
        assert_arrays_equal(self.signal2.array_annotations['anno1'], np.array([10, 11]))
        assert_arrays_equal(self.signal2.array_annotations['anno2'], np.array(['k', 'l']))
        self.assertIsInstance(self.signal2.array_annotations, ArrayDict)

    def test__index_dim1_should_return_single_channel_analogsignalarray(self):
        result = self.signal1[:, 0]
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([0]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(result.t_stop, self.signal1.t_stop)
        self.assertEqual(result.t_start, self.signal1.t_start)
        self.assertEqual(result.sampling_rate, self.signal1.sampling_rate)
        assert_arrays_equal(result, self.data1[:, 0].reshape(-1, 1))

    def test__index_dim1_and_slice_dim0_should_return_single_channel_analogsignalarray(self):
        result = self.signal1[2:7, 0]
        self.assertIsInstance(result, AnalogSignal)
        assert_neo_object_is_compliant(result)
        self.assertEqual(result.shape, (5, 1))
        self.assertEqual(result.name, 'spam')
        self.assertEqual(result.description, 'eggs')
        self.assertEqual(result.file_origin, 'testfile.txt')
        self.assertEqual(result.annotations, {'arg1': 'test'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([0]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(result.t_start, self.signal1.t_start + 2 * self.signal1.sampling_period)
        self.assertEqual(result.t_stop, self.signal1.t_start + 7 * self.signal1.sampling_period)
        self.assertEqual(result.sampling_rate, self.signal1.sampling_rate)
        assert_arrays_equal(result, self.data1[2:7, 0].reshape(-1, 1))

    def test__index_dim0_should_return_quantity_array(self):
        # i.e. values from all signals for a single point in time
        result = self.signal1[3, :]
        self.assertIsInstance(result, pq.Quantity)
        self.assertFalse(hasattr(result, 'name'))
        self.assertFalse(hasattr(result, 'description'))
        self.assertFalse(hasattr(result, 'file_origin'))
        self.assertFalse(hasattr(result, 'annotations'))
        self.assertFalse(hasattr(result, 'array_annotations'))

        self.assertEqual(result.shape, (5,))
        self.assertFalse(hasattr(result, "t_start"))
        self.assertEqual(result.units, pq.nA)
        assert_arrays_equal(result, self.data1[3, :])

    def test__index_dim0_and_slice_dim1_should_return_quantity_array(self):
        # i.e. values from a subset of signals for a single point in time
        result = self.signal1[3, 2:5]
        self.assertIsInstance(result, pq.Quantity)
        self.assertFalse(hasattr(result, 'name'))
        self.assertFalse(hasattr(result, 'description'))
        self.assertFalse(hasattr(result, 'file_origin'))
        self.assertFalse(hasattr(result, 'annotations'))
        self.assertFalse(hasattr(result, 'array_annotations'))

        self.assertEqual(result.shape, (3,))
        self.assertFalse(hasattr(result, "t_start"))
        self.assertEqual(result.units, pq.nA)
        assert_arrays_equal(result, self.data1[3, 2:5])

    def test__index_as_string_IndexError(self):
        self.assertRaises(IndexError, self.signal1.__getitem__, 5.)

    def test__slice_both_dimensions_should_return_analogsignalarray(self):
        result = self.signal1[0:3, 0:3]
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([0, 1, 2]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        targ = AnalogSignal([[0, 1, 2], [5, 6, 7], [10, 11, 12]], dtype=float, units="nA",
                            sampling_rate=1 * pq.kHz, name='spam', description='eggs',
                            file_origin='testfile.txt', arg1='test')
        assert_neo_object_is_compliant(targ)

        self.assertEqual(result.t_stop, targ.t_stop)
        self.assertEqual(result.t_start, targ.t_start)
        self.assertEqual(result.sampling_rate, targ.sampling_rate)
        self.assertEqual(result.shape, targ.shape)
        assert_same_sub_schema(result, targ)
        assert_arrays_equal(result, self.data1[0:3, 0:3])

    def test__slice_only_first_dimension_should_return_analogsignalarray(self):
        result = self.signal1[2:7]
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(result.shape, (5, 5))
        self.assertEqual(result.t_start, self.signal1.t_start + 2 * self.signal1.sampling_period)
        self.assertEqual(result.t_stop, self.signal1.t_start + 7 * self.signal1.sampling_period)
        self.assertEqual(result.sampling_rate, self.signal1.sampling_rate)
        assert_arrays_equal(result, self.data1[2:7])

    def test__getitem_should_return_single_quantity(self):
        # quantities drops the units in this case
        self.assertEqual(self.signal1[9, 3], 48000 * pq.pA)
        self.assertEqual(self.signal1[9][3], self.signal1[9, 3])
        self.assertTrue(hasattr(self.signal1[9, 3], 'units'))
        self.assertRaises(IndexError, self.signal1.__getitem__, (99, 73))

    def test_comparison_operators(self):
        assert_arrays_equal(self.signal1[0:3, 0:3] >= 5 * pq.nA, np.array(
            [[False, False, False], [True, True, True], [True, True, True]]))
        assert_arrays_equal(self.signal1[0:3, 0:3] >= 5 * pq.pA, np.array(
            [[False, True, True], [True, True, True], [True, True, True]]))
        assert_arrays_equal(self.signal1[0:3, 0:3] == 5 * pq.nA, np.array(
            [[False, False, False], [True, False, False], [False, False, False]]))
        assert_arrays_equal(self.signal1[0:3, 0:3] == self.signal1[0:3, 0:3],
                            np.array([[True, True, True], [True, True, True], [True, True, True]]))

    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(), 54000 * pq.pA)
        self.assertEqual(self.signal1.min(), 0 * pq.nA)
        self.assertEqual(self.signal1.mean(), 27 * pq.nA)
        self.assertEqual(self.signal1.std(), self.signal1.magnitude.std() * pq.nA)
        self.assertEqual(self.signal1.var(), self.signal1.magnitude.var() * pq.nA ** 2)

    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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(result.units, 1 * pq.nA)
        assert_arrays_equal(result, self.data1)
        assert_same_sub_schema(result, self.signal1)

    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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(result.units, 1 * pq.pA)
        assert_arrays_almost_equal(np.array(result), self.data1 * 1000., 1e-10)

    def test__time_slice(self):
        t_start = 2 * pq.s
        t_stop = 4 * pq.s

        result = self.signal2.time_slice(t_start, t_stop)
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([10, 11]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['k', 'l']))

        targ = AnalogSignal(np.array([[2., 3.], [2., 3.]]).T, sampling_rate=1.0 * pq.Hz,
                            units='mV', t_start=t_start, name='spam', description='eggs',
                            file_origin='testfile.txt', arg1='test')
        assert_neo_object_is_compliant(result)

        self.assertEqual(result.t_stop, t_stop)
        self.assertEqual(result.t_start, t_start)
        self.assertEqual(result.sampling_rate, targ.sampling_rate)
        assert_array_equal(result, targ)
        assert_same_sub_schema(result, targ)

    def test__time_slice__out_of_bounds_ValueError(self):
        t_start_good = 2 * pq.s
        t_stop_good = 4 * pq.s
        t_start_bad = -2 * pq.s
        t_stop_bad = 40 * pq.s

        self.assertRaises(ValueError, self.signal2.time_slice, t_start_good, t_stop_bad)
        self.assertRaises(ValueError, self.signal2.time_slice, t_start_bad, t_stop_good)
        self.assertRaises(ValueError, self.signal2.time_slice, t_start_bad, t_stop_bad)

    def test__time_equal(self):
        t_start = 0 * pq.s
        t_stop = 6 * pq.s

        result = self.signal2.time_slice(t_start, t_stop)
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([10, 11]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['k', 'l']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(result.t_stop, t_stop)
        self.assertEqual(result.t_start, t_start)
        assert_array_equal(result, self.signal2)
        assert_same_sub_schema(result, self.signal2)

    def test__time_slice__offset(self):
        self.signal2.t_start = 10.0 * pq.s
        assert_neo_object_is_compliant(self.signal2)

        t_start = 12 * pq.s
        t_stop = 14 * pq.s

        result = self.signal2.time_slice(t_start, t_stop)
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([10, 11]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['k', 'l']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        targ = AnalogSignal(np.array([[2., 3.], [2., 3.]]).T, t_start=12.0 * pq.ms,
                            sampling_rate=1.0 * pq.Hz, units='mV', name='spam', description='eggs',
                            file_origin='testfile.txt', arg1='test')
        assert_neo_object_is_compliant(result)

        self.assertEqual(self.signal2.t_start, 10.0 * pq.s)
        self.assertEqual(result.t_stop, t_stop)
        self.assertEqual(result.t_start, t_start)
        self.assertEqual(result.sampling_rate, targ.sampling_rate)
        assert_arrays_equal(result, targ)
        assert_same_sub_schema(result, targ)

    def test__time_slice__different_units(self):
        self.signal2.t_start = 10.0 * pq.ms
        assert_neo_object_is_compliant(self.signal2)

        t_start = 2 * pq.s + 10.0 * pq.ms
        t_stop = 4 * pq.s + 10.0 * pq.ms

        result = self.signal2.time_slice(t_start, t_stop)
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.array([10, 11]))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['k', 'l']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        targ = AnalogSignal(np.array([[2., 3.], [2., 3.]]).T, t_start=t_start.rescale(pq.ms),
                            sampling_rate=1.0 * pq.Hz, units='mV', name='spam', description='eggs',
                            file_origin='testfile.txt', arg1='test')
        assert_neo_object_is_compliant(result)

        assert_neo_object_is_compliant(self.signal2)
        self.assertEqual(self.signal2.t_start, 10.0 * pq.ms)
        self.assertAlmostEqual(result.t_stop, t_stop, delta=1e-12 * pq.ms)
        self.assertAlmostEqual(result.t_start, t_start, delta=1e-12 * pq.ms)
        assert_arrays_almost_equal(result.times, targ.times, 1e-12 * pq.ms)
        self.assertEqual(result.sampling_rate, targ.sampling_rate)
        assert_arrays_equal(result, targ)
        assert_same_sub_schema(result, targ)

    def test__time_slice__no_explicit_time(self):
        self.signal2.t_start = 10.0 * pq.ms
        assert_neo_object_is_compliant(self.signal2)

        t1 = 2 * pq.s + 10.0 * pq.ms
        t2 = 4 * pq.s + 10.0 * pq.ms

        for t_start, t_stop in [(t1, None), (None, None), (None, t2)]:
            t_start_targ = t1 if t_start is not None else self.signal2.t_start
            t_stop_targ = t2 if t_stop is not None else self.signal2.t_stop

            result = self.signal2.time_slice(t_start, t_stop)
            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'})
            assert_arrays_equal(result.array_annotations['anno1'], np.array([10, 11]))
            assert_arrays_equal(result.array_annotations['anno2'], np.array(['k', 'l']))
            self.assertIsInstance(result.array_annotations, ArrayDict)

            targ_ind = np.where(
                (self.signal2.times >= t_start_targ) & (self.signal2.times < t_stop_targ))
            targ_array = self.signal2.magnitude[targ_ind]

            targ = AnalogSignal(targ_array, t_start=t_start_targ.rescale(pq.ms),
                                sampling_rate=1.0 * pq.Hz, units='mV', name='spam',
                                description='eggs', file_origin='testfile.txt', arg1='test')
            assert_neo_object_is_compliant(result)

            assert_neo_object_is_compliant(self.signal2)
            self.assertEqual(self.signal2.t_start, 10.0 * pq.ms)
            self.assertAlmostEqual(result.t_stop, t_stop_targ, delta=1e-12 * pq.ms)
            self.assertAlmostEqual(result.t_start, t_start_targ, delta=1e-12 * pq.ms)
            assert_arrays_almost_equal(result.times, targ.times, 1e-12 * pq.ms)
            self.assertEqual(result.sampling_rate, targ.sampling_rate)
            assert_array_equal(result.magnitude, targ.magnitude)
            assert_same_sub_schema(result, targ)
class TestAnalogSignalArrayCombination(unittest.TestCase):
    def setUp(self):
        self.data1 = np.arange(55.0).reshape((11, 5))
        self.data1quant = self.data1 * pq.mV
        self.arr_ann1 = {'anno1': np.arange(5), 'anno2': ['a', 'b', 'c', 'd', 'e']}
        self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1 * pq.kHz, name='spam',
                                    description='eggs', file_origin='testfile.txt',
                                    array_annotations=self.arr_ann1, arg1='test')
        self.data2 = np.arange(100.0, 155.0).reshape((11, 5))
        self.data2quant = self.data2 * pq.mV
        self.arr_ann2 = {'anno1': np.arange(10, 15), 'anno2': ['k', 'l', 'm', 'n', 'o']}
        self.signal2 = AnalogSignal(self.data2quant, sampling_rate=1 * pq.kHz, name='spam',
                                    description='eggs', file_origin='testfile.txt',
                                    array_annotations=self.arr_ann2, arg1='test')

    def test__compliant(self):
        assert_neo_object_is_compliant(self.signal1)
        self.assertEqual(self.signal1.name, 'spam')
        self.assertEqual(self.signal1.description, 'eggs')
        self.assertEqual(self.signal1.file_origin, 'testfile.txt')
        self.assertEqual(self.signal1.annotations, {'arg1': 'test'})
        assert_arrays_equal(self.signal1.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(self.signal1.array_annotations['anno2'],
                            np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(self.signal1.array_annotations, ArrayDict)

        assert_neo_object_is_compliant(self.signal2)
        self.assertEqual(self.signal2.name, 'spam')
        self.assertEqual(self.signal2.description, 'eggs')
        self.assertEqual(self.signal2.file_origin, 'testfile.txt')
        self.assertEqual(self.signal2.annotations, {'arg1': 'test'})
        assert_arrays_equal(self.signal2.array_annotations['anno1'], np.arange(10, 15))
        assert_arrays_equal(self.signal2.array_annotations['anno2'],
                            np.array(['k', 'l', 'm', 'n', 'o']))
        self.assertIsInstance(self.signal2.array_annotations, ArrayDict)

    def test__add_const_quantity_should_preserve_data_complement(self):
        result = self.signal1 + 0.065 * pq.V
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        # time zero, signal index 4
        assert_arrays_equal(result, self.data1 + 65)
        self.assertEqual(self.signal1[0, 4], 4 * pq.mV)
        self.assertEqual(result[0, 4], 69000 * pq.uV)
        self.assertEqual(self.signal1.t_start, result.t_start)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__add_two_consistent_signals_should_preserve_data_complement(self):
        result = self.signal1 + self.signal2
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        targdata = np.arange(100.0, 210.0, 2.0).reshape((11, 5))
        targ = AnalogSignal(targdata, units="mV", sampling_rate=1 * pq.kHz, name='spam',
                            description='eggs', file_origin='testfile.txt', arg1='test')
        assert_neo_object_is_compliant(targ)

        assert_arrays_equal(result, targdata)
        assert_same_sub_schema(result, targ)

    def test__add_signals_with_inconsistent_data_complement_ValueError(self):
        self.signal2.sampling_rate = 0.5 * pq.kHz
        assert_neo_object_is_compliant(self.signal2)

        self.assertRaises(ValueError, self.signal1.__add__, self.signal2)

    def test__subtract_const_should_preserve_data_complement(self):
        result = self.signal1 - 65 * pq.mV
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), -56)
        assert_arrays_equal(result, self.data1 - 65)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__subtract_from_const_should_return_signal(self):
        result = 10 * pq.mV - self.signal1
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), 1)
        assert_arrays_equal(result, 10 - self.data1)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__mult_by_const_float_should_preserve_data_complement(self):
        result = self.signal1 * 2
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), 18)
        assert_arrays_equal(result, self.data1 * 2)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__divide_by_const_should_preserve_data_complement(self):
        result = self.signal1 / 0.5
        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'})
        assert_arrays_equal(result.array_annotations['anno1'], np.arange(5))
        assert_arrays_equal(result.array_annotations['anno2'], np.array(['a', 'b', 'c', 'd', 'e']))
        self.assertIsInstance(result.array_annotations, ArrayDict)

        self.assertEqual(np.array(self.signal1[1, 4]), 9)
        self.assertEqual(np.array(result[1, 4]), 18)
        assert_arrays_equal(result, self.data1 / 0.5)
        self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)

    def test__merge(self):
        self.signal1.description = None
        self.signal1.file_origin = None
        assert_neo_object_is_compliant(self.signal1)

        data3 = np.arange(1000.0, 1066.0).reshape((11, 6)) * pq.uV
        data3scale = data3.rescale(self.data1quant.units)
        arr_ann3 = {'anno1': np.arange(5, 11), 'anno3': ['h', 'i', 'j', 'k', 'l', 'm']}
        arr_ann4 = {'anno1': np.arange(100, 106), 'anno3': ['o', 'p', 'q', 'r', 's', 't']}

        signal2 = AnalogSignal(self.data1quant, sampling_rate=1 * pq.kHz, name='signal2',
                               description='test signal', file_origin='testfile.txt',
                               array_annotations=self.arr_ann1)
        signal3 = AnalogSignal(data3, units="uV", sampling_rate=1 * pq.kHz, name='signal3',
                               description='test signal', file_origin='testfile.txt',
                               array_annotations=arr_ann3)
        signal4 = AnalogSignal(data3, units="uV", sampling_rate=1 * pq.kHz, name='signal4',
                               description='test signal', file_origin='testfile.txt',
                               array_annotations=arr_ann4)

        with warnings.catch_warnings(record=True) as w:
            warnings.filterwarnings('always')
            merged13 = self.signal1.merge(signal3)
            merged23 = signal2.merge(signal3)
            merged24 = signal2.merge(signal4)

            self.assertTrue(len(w) == 3)
            self.assertEqual(w[-1].category, UserWarning)
            self.assertSequenceEqual(str(w[2].message), str(w[0].message))
            self.assertSequenceEqual(str(w[2].message), str(w[1].message))
            self.assertSequenceEqual(str(w[2].message), "The following array annotations were "
                                                        "omitted, because they were only present"
                                                        " in one of the merged objects: "
                                                        "['anno2'] from the one that was merged "
                                                        "into and ['anno3'] from the one that "
                                                        "was merged into the other")

        mergeddata13 = np.array(merged13)
        mergeddata23 = np.array(merged23)
        mergeddata24 = np.array(merged24)

        targdata13 = np.hstack([self.data1quant, data3scale])
        targdata23 = np.hstack([self.data1quant, data3scale])
        targdata24 = np.hstack([self.data1quant, data3scale])

        assert_neo_object_is_compliant(signal2)
        assert_neo_object_is_compliant(signal3)
        assert_neo_object_is_compliant(merged13)
        assert_neo_object_is_compliant(merged23)
        assert_neo_object_is_compliant(merged24)

        self.assertEqual(merged13[0, 4], 4 * pq.mV)
        self.assertEqual(merged23[0, 4], 4 * pq.mV)
        self.assertEqual(merged13[0, 5], 1 * pq.mV)
        self.assertEqual(merged23[0, 5], 1 * pq.mV)
        self.assertEqual(merged13[10, 10], 1.065 * pq.mV)
        self.assertEqual(merged23[10, 10], 1.065 * pq.mV)
        self.assertEqual(merged13.t_stop, self.signal1.t_stop)
        self.assertEqual(merged23.t_stop, self.signal1.t_stop)

        self.assertEqual(merged13.name, 'merge(spam, signal3)')
        self.assertEqual(merged23.name, 'merge(signal2, signal3)')
        self.assertEqual(merged13.description, 'merge(None, test signal)')
        self.assertEqual(merged23.description, 'test signal')
        self.assertEqual(merged13.file_origin, 'merge(None, testfile.txt)')
        self.assertEqual(merged23.file_origin, 'testfile.txt')

        assert_arrays_equal(merged13.array_annotations['anno1'], np.arange(11))
        self.assertIsInstance(merged13.array_annotations, ArrayDict)
        self.assertNotIn('anno2', merged13.array_annotations)
        self.assertNotIn('anno3', merged13.array_annotations)
        assert_arrays_equal(merged23.array_annotations['anno1'], np.arange(11))
        self.assertIsInstance(merged23.array_annotations, ArrayDict)
        self.assertNotIn('anno2', merged23.array_annotations)
        self.assertNotIn('anno3', merged23.array_annotations)
        assert_arrays_equal(merged24.array_annotations['anno1'],
                            np.array([0, 1, 2, 3, 4, 100, 101, 102, 103, 104, 105]))
        self.assertIsInstance(merged24.array_annotations, ArrayDict)
        self.assertNotIn('anno2', merged24.array_annotations)
        self.assertNotIn('anno3', merged24.array_annotations)

        assert_arrays_equal(mergeddata13, targdata13)
        assert_arrays_equal(mergeddata23, targdata23)
        assert_arrays_equal(mergeddata24, targdata24)
    def test__merge(self):
        self.signal1.description = None
        self.signal1.file_origin = None
        assert_neo_object_is_compliant(self.signal1)

        data3 = np.arange(1000.0, 1066.0).reshape((11, 6)) * pq.uV
        data3scale = data3.rescale(self.data1quant.units)
        arr_ann3 = {'anno1': np.arange(5, 11), 'anno3': ['h', 'i', 'j', 'k', 'l', 'm']}
        arr_ann4 = {'anno1': np.arange(100, 106), 'anno3': ['o', 'p', 'q', 'r', 's', 't']}

        signal2 = AnalogSignal(self.data1quant, sampling_rate=1 * pq.kHz, name='signal2',
                               description='test signal', file_origin='testfile.txt',
                               array_annotations=self.arr_ann1)
        signal3 = AnalogSignal(data3, units="uV", sampling_rate=1 * pq.kHz, name='signal3',
                               description='test signal', file_origin='testfile.txt',
                               array_annotations=arr_ann3)
        signal4 = AnalogSignal(data3, units="uV", sampling_rate=1 * pq.kHz, name='signal4',
                               description='test signal', file_origin='testfile.txt',
                               array_annotations=arr_ann4)

        with warnings.catch_warnings(record=True) as w:
            warnings.filterwarnings('always')
            merged13 = self.signal1.merge(signal3)
            merged23 = signal2.merge(signal3)
            merged24 = signal2.merge(signal4)

            self.assertTrue(len(w) == 3)
            self.assertEqual(w[-1].category, UserWarning)
            self.assertSequenceEqual(str(w[2].message), str(w[0].message))
            self.assertSequenceEqual(str(w[2].message), str(w[1].message))
            self.assertSequenceEqual(str(w[2].message), "The following array annotations were "
                                                        "omitted, because they were only present"
                                                        " in one of the merged objects: "
                                                        "['anno2'] from the one that was merged "
                                                        "into and ['anno3'] from the one that "
                                                        "was merged into the other")

        mergeddata13 = np.array(merged13)
        mergeddata23 = np.array(merged23)
        mergeddata24 = np.array(merged24)

        targdata13 = np.hstack([self.data1quant, data3scale])
        targdata23 = np.hstack([self.data1quant, data3scale])
        targdata24 = np.hstack([self.data1quant, data3scale])

        assert_neo_object_is_compliant(signal2)
        assert_neo_object_is_compliant(signal3)
        assert_neo_object_is_compliant(merged13)
        assert_neo_object_is_compliant(merged23)
        assert_neo_object_is_compliant(merged24)

        self.assertEqual(merged13[0, 4], 4 * pq.mV)
        self.assertEqual(merged23[0, 4], 4 * pq.mV)
        self.assertEqual(merged13[0, 5], 1 * pq.mV)
        self.assertEqual(merged23[0, 5], 1 * pq.mV)
        self.assertEqual(merged13[10, 10], 1.065 * pq.mV)
        self.assertEqual(merged23[10, 10], 1.065 * pq.mV)
        self.assertEqual(merged13.t_stop, self.signal1.t_stop)
        self.assertEqual(merged23.t_stop, self.signal1.t_stop)

        self.assertEqual(merged13.name, 'merge(spam, signal3)')
        self.assertEqual(merged23.name, 'merge(signal2, signal3)')
        self.assertEqual(merged13.description, 'merge(None, test signal)')
        self.assertEqual(merged23.description, 'test signal')
        self.assertEqual(merged13.file_origin, 'merge(None, testfile.txt)')
        self.assertEqual(merged23.file_origin, 'testfile.txt')

        assert_arrays_equal(merged13.array_annotations['anno1'], np.arange(11))
        self.assertIsInstance(merged13.array_annotations, ArrayDict)
        self.assertNotIn('anno2', merged13.array_annotations)
        self.assertNotIn('anno3', merged13.array_annotations)
        assert_arrays_equal(merged23.array_annotations['anno1'], np.arange(11))
        self.assertIsInstance(merged23.array_annotations, ArrayDict)
        self.assertNotIn('anno2', merged23.array_annotations)
        self.assertNotIn('anno3', merged23.array_annotations)
        assert_arrays_equal(merged24.array_annotations['anno1'],
                            np.array([0, 1, 2, 3, 4, 100, 101, 102, 103, 104, 105]))
        self.assertIsInstance(merged24.array_annotations, ArrayDict)
        self.assertNotIn('anno2', merged24.array_annotations)
        self.assertNotIn('anno3', merged24.array_annotations)

        assert_arrays_equal(mergeddata13, targdata13)
        assert_arrays_equal(mergeddata23, targdata23)
        assert_arrays_equal(mergeddata24, targdata24)