test_analogsignalarray.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests of the neo.core.analogsignalarray.AnalogSignalArrayArray class
  4. """
  5. import os
  6. import pickle
  7. import unittest
  8. import numpy as np
  9. import quantities as pq
  10. try:
  11. from IPython.lib.pretty import pretty
  12. except ImportError as err:
  13. HAVE_IPYTHON = False
  14. else:
  15. HAVE_IPYTHON = True
  16. from numpy.testing import assert_array_equal
  17. from neo.core.analogsignal import AnalogSignal
  18. from neo.core import Segment, ChannelIndex
  19. from neo.test.tools import (assert_arrays_almost_equal, assert_arrays_equal,
  20. assert_neo_object_is_compliant,
  21. assert_same_sub_schema)
  22. from neo.test.generate_datasets import (get_fake_value, get_fake_values,
  23. fake_neo, TEST_ANNOTATIONS)
  24. class Test__generate_datasets(unittest.TestCase):
  25. def setUp(self):
  26. np.random.seed(0)
  27. self.annotations = dict([(str(x), TEST_ANNOTATIONS[x]) for x in
  28. range(len(TEST_ANNOTATIONS))])
  29. def test__get_fake_values(self):
  30. self.annotations['seed'] = 0
  31. signal = get_fake_value('signal', pq.Quantity, seed=0, dim=2)
  32. sampling_rate = get_fake_value('sampling_rate', pq.Quantity,
  33. seed=1, dim=0)
  34. t_start = get_fake_value('t_start', pq.Quantity, seed=2, dim=0)
  35. name = get_fake_value('name', str, seed=3, obj=AnalogSignal)
  36. description = get_fake_value('description', str, seed=4,
  37. obj='AnalogSignal')
  38. file_origin = get_fake_value('file_origin', str)
  39. attrs1 = {'name': name,
  40. 'description': description,
  41. 'file_origin': file_origin}
  42. attrs2 = attrs1.copy()
  43. attrs2.update(self.annotations)
  44. res11 = get_fake_values(AnalogSignal, annotate=False, seed=0)
  45. res12 = get_fake_values('AnalogSignal', annotate=False, seed=0)
  46. res21 = get_fake_values(AnalogSignal, annotate=True, seed=0)
  47. res22 = get_fake_values('AnalogSignal', annotate=True, seed=0)
  48. assert_arrays_equal(res11.pop('signal'), signal)
  49. assert_arrays_equal(res12.pop('signal'), signal)
  50. assert_arrays_equal(res21.pop('signal'), signal)
  51. assert_arrays_equal(res22.pop('signal'), signal)
  52. assert_arrays_equal(res11.pop('sampling_rate'), sampling_rate)
  53. assert_arrays_equal(res12.pop('sampling_rate'), sampling_rate)
  54. assert_arrays_equal(res21.pop('sampling_rate'), sampling_rate)
  55. assert_arrays_equal(res22.pop('sampling_rate'), sampling_rate)
  56. assert_arrays_equal(res11.pop('t_start'), t_start)
  57. assert_arrays_equal(res12.pop('t_start'), t_start)
  58. assert_arrays_equal(res21.pop('t_start'), t_start)
  59. assert_arrays_equal(res22.pop('t_start'), t_start)
  60. self.assertEqual(res11, attrs1)
  61. self.assertEqual(res12, attrs1)
  62. self.assertEqual(res21, attrs2)
  63. self.assertEqual(res22, attrs2)
  64. def test__fake_neo__cascade(self):
  65. self.annotations['seed'] = None
  66. obj_type = 'AnalogSignal'
  67. cascade = True
  68. res = fake_neo(obj_type=obj_type, cascade=cascade)
  69. self.assertTrue(isinstance(res, AnalogSignal))
  70. assert_neo_object_is_compliant(res)
  71. self.assertEqual(res.annotations, self.annotations)
  72. def test__fake_neo__nocascade(self):
  73. self.annotations['seed'] = None
  74. obj_type = AnalogSignal
  75. cascade = False
  76. res = fake_neo(obj_type=obj_type, cascade=cascade)
  77. self.assertTrue(isinstance(res, AnalogSignal))
  78. assert_neo_object_is_compliant(res)
  79. self.assertEqual(res.annotations, self.annotations)
  80. class TestAnalogSignalArrayConstructor(unittest.TestCase):
  81. def test__create_from_list(self):
  82. data = [(i, i, i) for i in range(10)] # 3 signals each with 10 samples
  83. rate = 1000*pq.Hz
  84. signal = AnalogSignal(data, sampling_rate=rate, units="mV")
  85. assert_neo_object_is_compliant(signal)
  86. self.assertEqual(signal.shape, (10, 3))
  87. self.assertEqual(signal.t_start, 0*pq.ms)
  88. self.assertEqual(signal.t_stop, len(data)/rate)
  89. self.assertEqual(signal[9, 0], 9000*pq.uV)
  90. def test__create_from_numpy_array(self):
  91. data = np.arange(20.0).reshape((10, 2))
  92. rate = 1*pq.kHz
  93. signal = AnalogSignal(data, sampling_rate=rate, units="uV")
  94. assert_neo_object_is_compliant(signal)
  95. self.assertEqual(signal.t_start, 0*pq.ms)
  96. self.assertEqual(signal.t_stop, data.shape[0]/rate)
  97. self.assertEqual(signal[9, 0], 0.018*pq.mV)
  98. self.assertEqual(signal[9, 1], 19*pq.uV)
  99. def test__create_from_quantities_array(self):
  100. data = np.arange(20.0).reshape((10, 2)) * pq.mV
  101. rate = 5000*pq.Hz
  102. signal = AnalogSignal(data, sampling_rate=rate)
  103. assert_neo_object_is_compliant(signal)
  104. self.assertEqual(signal.t_start, 0*pq.ms)
  105. self.assertEqual(signal.t_stop, data.shape[0]/rate)
  106. self.assertEqual(signal[9, 0], 18000*pq.uV)
  107. def test__create_from_quantities_with_inconsistent_units_ValueError(self):
  108. data = np.arange(20.0).reshape((10, 2)) * pq.mV
  109. self.assertRaises(ValueError, AnalogSignal, data,
  110. sampling_rate=1*pq.kHz, units="nA")
  111. def test__create_with_copy_true_should_return_copy(self):
  112. data = np.arange(20.0).reshape((10, 2)) * pq.mV
  113. rate = 5000*pq.Hz
  114. signal = AnalogSignal(data, copy=True, sampling_rate=rate)
  115. assert_neo_object_is_compliant(signal)
  116. data[3, 0] = 0.099*pq.V
  117. self.assertNotEqual(signal[3, 0], 99*pq.mV)
  118. def test__create_with_copy_false_should_return_view(self):
  119. data = np.arange(20.0).reshape((10, 2)) * pq.mV
  120. rate = 5000*pq.Hz
  121. signal = AnalogSignal(data, copy=False, sampling_rate=rate)
  122. assert_neo_object_is_compliant(signal)
  123. data[3, 0] = 99*pq.mV
  124. self.assertEqual(signal[3, 0], 99000*pq.uV)
  125. # signal must not be 1D - should raise Exception if 1D
  126. class TestAnalogSignalArrayProperties(unittest.TestCase):
  127. def setUp(self):
  128. self.t_start = [0.0*pq.ms, 100*pq.ms, -200*pq.ms]
  129. self.rates = [1*pq.kHz, 420*pq.Hz, 999*pq.Hz]
  130. self.data = [np.arange(10.0).reshape((5, 2))*pq.nA,
  131. np.arange(-100.0, 100.0, 10.0).reshape((4, 5))*pq.mV,
  132. np.random.uniform(size=(100, 4))*pq.uV]
  133. self.signals = [AnalogSignal(D, sampling_rate=r, t_start=t)
  134. for r, D, t in zip(self.rates,
  135. self.data,
  136. self.t_start)]
  137. def test__compliant(self):
  138. for signal in self.signals:
  139. assert_neo_object_is_compliant(signal)
  140. def test__t_stop(self):
  141. for i, signal in enumerate(self.signals):
  142. targ = self.t_start[i] + self.data[i].shape[0]/self.rates[i]
  143. self.assertEqual(signal.t_stop, targ)
  144. def test__duration(self):
  145. for signal in self.signals:
  146. self.assertAlmostEqual(signal.duration,
  147. signal.t_stop - signal.t_start,
  148. delta=1e-15)
  149. def test__sampling_period(self):
  150. for signal, rate in zip(self.signals, self.rates):
  151. self.assertEqual(signal.sampling_period, 1/rate)
  152. def test__times(self):
  153. for i, signal in enumerate(self.signals):
  154. targ = np.arange(self.data[i].shape[0])
  155. targ = targ/self.rates[i] + self.t_start[i]
  156. assert_arrays_almost_equal(signal.times, targ, 1e-12*pq.ms)
  157. def test__children(self):
  158. signal = self.signals[0]
  159. segment = Segment(name='seg1')
  160. segment.analogsignals = [signal]
  161. segment.create_many_to_one_relationship()
  162. chx = ChannelIndex(name='chx1', index=np.arange(signal.shape[1]))
  163. chx.analogsignals = [signal]
  164. chx.create_many_to_one_relationship()
  165. self.assertEqual(signal._single_parent_objects,
  166. ('Segment', 'ChannelIndex'))
  167. self.assertEqual(signal._multi_parent_objects, ())
  168. self.assertEqual(signal._single_parent_containers,
  169. ('segment', 'channel_index'))
  170. self.assertEqual(signal._multi_parent_containers, ())
  171. self.assertEqual(signal._parent_objects,
  172. ('Segment', 'ChannelIndex'))
  173. self.assertEqual(signal._parent_containers,
  174. ('segment', 'channel_index'))
  175. self.assertEqual(len(signal.parents), 2)
  176. self.assertEqual(signal.parents[0].name, 'seg1')
  177. self.assertEqual(signal.parents[1].name, 'chx1')
  178. assert_neo_object_is_compliant(signal)
  179. def test__repr(self):
  180. for i, signal in enumerate(self.signals):
  181. prepr = repr(signal)
  182. targ = '<AnalogSignal(%s, [%s, %s], sampling rate: %s)>' % \
  183. (repr(self.data[i]),
  184. self.t_start[i],
  185. self.t_start[i] + len(self.data[i])/self.rates[i],
  186. self.rates[i])
  187. self.assertEqual(prepr, targ)
  188. class TestAnalogSignalArrayArrayMethods(unittest.TestCase):
  189. def setUp(self):
  190. self.data1 = np.arange(55.0).reshape((11, 5))
  191. self.data1quant = self.data1 * pq.nA
  192. self.signal1 = AnalogSignal(self.data1quant,
  193. sampling_rate=1*pq.kHz,
  194. name='spam', description='eggs',
  195. file_origin='testfile.txt',
  196. arg1='test')
  197. self.data2 = np.array([[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]).T
  198. self.data2quant = self.data2 * pq.mV
  199. self.signal2 = AnalogSignal(self.data2quant,
  200. sampling_rate=1.0*pq.Hz,
  201. name='spam', description='eggs',
  202. file_origin='testfile.txt',
  203. arg1='test')
  204. def test__compliant(self):
  205. assert_neo_object_is_compliant(self.signal1)
  206. self.assertEqual(self.signal1.name, 'spam')
  207. self.assertEqual(self.signal1.description, 'eggs')
  208. self.assertEqual(self.signal1.file_origin, 'testfile.txt')
  209. self.assertEqual(self.signal1.annotations, {'arg1': 'test'})
  210. assert_neo_object_is_compliant(self.signal2)
  211. self.assertEqual(self.signal2.name, 'spam')
  212. self.assertEqual(self.signal2.description, 'eggs')
  213. self.assertEqual(self.signal2.file_origin, 'testfile.txt')
  214. self.assertEqual(self.signal2.annotations, {'arg1': 'test'})
  215. def test__index_dim1_should_return_single_channel_analogsignalarray(self):
  216. result = self.signal1[:, 0]
  217. self.assertIsInstance(result, AnalogSignal)
  218. assert_neo_object_is_compliant(result)
  219. self.assertEqual(result.name, 'spam')
  220. self.assertEqual(result.description, 'eggs')
  221. self.assertEqual(result.file_origin, 'testfile.txt')
  222. self.assertEqual(result.annotations, {'arg1': 'test'})
  223. self.assertEqual(result.t_stop, self.signal1.t_stop)
  224. self.assertEqual(result.t_start, self.signal1.t_start)
  225. self.assertEqual(result.sampling_rate,
  226. self.signal1.sampling_rate)
  227. assert_arrays_equal(result, self.data1[:, 0].reshape(-1, 1))
  228. def test__index_dim1_and_slice_dim0_should_return_single_channel_analogsignalarray(self):
  229. result = self.signal1[2:7, 0]
  230. self.assertIsInstance(result, AnalogSignal)
  231. assert_neo_object_is_compliant(result)
  232. self.assertEqual(result.shape, (5, 1))
  233. self.assertEqual(result.name, 'spam')
  234. self.assertEqual(result.description, 'eggs')
  235. self.assertEqual(result.file_origin, 'testfile.txt')
  236. self.assertEqual(result.annotations, {'arg1': 'test'})
  237. self.assertEqual(result.t_start,
  238. self.signal1.t_start+2*self.signal1.sampling_period)
  239. self.assertEqual(result.t_stop,
  240. self.signal1.t_start+7*self.signal1.sampling_period)
  241. self.assertEqual(result.sampling_rate,
  242. self.signal1.sampling_rate)
  243. assert_arrays_equal(result, self.data1[2:7, 0].reshape(-1, 1))
  244. def test__index_dim0_should_return_quantity_array(self):
  245. # i.e. values from all signals for a single point in time
  246. result = self.signal1[3, :]
  247. self.assertIsInstance(result, pq.Quantity)
  248. self.assertFalse(hasattr(result, 'name'))
  249. self.assertFalse(hasattr(result, 'description'))
  250. self.assertFalse(hasattr(result, 'file_origin'))
  251. self.assertFalse(hasattr(result, 'annotations'))
  252. self.assertEqual(result.shape, (5,))
  253. self.assertFalse(hasattr(result, "t_start"))
  254. self.assertEqual(result.units, pq.nA)
  255. assert_arrays_equal(result, self.data1[3, :])
  256. def test__index_dim0_and_slice_dim1_should_return_quantity_array(self):
  257. # i.e. values from a subset of signals for a single point in time
  258. result = self.signal1[3, 2:5]
  259. self.assertIsInstance(result, pq.Quantity)
  260. self.assertFalse(hasattr(result, 'name'))
  261. self.assertFalse(hasattr(result, 'description'))
  262. self.assertFalse(hasattr(result, 'file_origin'))
  263. self.assertFalse(hasattr(result, 'annotations'))
  264. self.assertEqual(result.shape, (3,))
  265. self.assertFalse(hasattr(result, "t_start"))
  266. self.assertEqual(result.units, pq.nA)
  267. assert_arrays_equal(result, self.data1[3, 2:5])
  268. def test__index_as_string_IndexError(self):
  269. self.assertRaises(IndexError, self.signal1.__getitem__, 5.)
  270. def test__slice_both_dimensions_should_return_analogsignalarray(self):
  271. result = self.signal1[0:3, 0:3]
  272. self.assertIsInstance(result, AnalogSignal)
  273. assert_neo_object_is_compliant(result)
  274. self.assertEqual(result.name, 'spam')
  275. self.assertEqual(result.description, 'eggs')
  276. self.assertEqual(result.file_origin, 'testfile.txt')
  277. self.assertEqual(result.annotations, {'arg1': 'test'})
  278. targ = AnalogSignal([[0, 1, 2], [5, 6, 7], [10, 11, 12]],
  279. dtype=float, units="nA",
  280. sampling_rate=1*pq.kHz,
  281. name='spam', description='eggs',
  282. file_origin='testfile.txt', arg1='test')
  283. assert_neo_object_is_compliant(targ)
  284. self.assertEqual(result.t_stop, targ.t_stop)
  285. self.assertEqual(result.t_start, targ.t_start)
  286. self.assertEqual(result.sampling_rate, targ.sampling_rate)
  287. self.assertEqual(result.shape, targ.shape)
  288. assert_same_sub_schema(result, targ)
  289. assert_arrays_equal(result, self.data1[0:3, 0:3])
  290. def test__slice_only_first_dimension_should_return_analogsignalarray(self):
  291. result = self.signal1[2:7]
  292. self.assertIsInstance(result, AnalogSignal)
  293. assert_neo_object_is_compliant(result)
  294. self.assertEqual(result.name, 'spam')
  295. self.assertEqual(result.description, 'eggs')
  296. self.assertEqual(result.file_origin, 'testfile.txt')
  297. self.assertEqual(result.annotations, {'arg1': 'test'})
  298. self.assertEqual(result.shape, (5, 5))
  299. self.assertEqual(result.t_start,
  300. self.signal1.t_start+2*self.signal1.sampling_period)
  301. self.assertEqual(result.t_stop,
  302. self.signal1.t_start+7*self.signal1.sampling_period)
  303. self.assertEqual(result.sampling_rate, self.signal1.sampling_rate)
  304. assert_arrays_equal(result, self.data1[2:7])
  305. def test__getitem_should_return_single_quantity(self):
  306. # quantities drops the units in this case
  307. self.assertEqual(self.signal1[9, 3], 48000*pq.pA)
  308. self.assertEqual(self.signal1[9][3], self.signal1[9, 3])
  309. self.assertTrue(hasattr(self.signal1[9, 3], 'units'))
  310. self.assertRaises(IndexError, self.signal1.__getitem__, (99, 73))
  311. def test_comparison_operators(self):
  312. assert_arrays_equal(self.signal1[0:3, 0:3] >= 5*pq.nA,
  313. np.array([[False, False, False],
  314. [True, True, True],
  315. [True, True, True]]))
  316. assert_arrays_equal(self.signal1[0:3, 0:3] >= 5*pq.pA,
  317. np.array([[False, True, True],
  318. [True, True, True],
  319. [True, True, True]]))
  320. def test__comparison_with_inconsistent_units_should_raise_Exception(self):
  321. self.assertRaises(ValueError, self.signal1.__gt__, 5*pq.mV)
  322. def test__simple_statistics(self):
  323. self.assertEqual(self.signal1.max(), 54000*pq.pA)
  324. self.assertEqual(self.signal1.min(), 0*pq.nA)
  325. self.assertEqual(self.signal1.mean(), 27*pq.nA)
  326. self.assertEqual(self.signal1.std(), self.signal1.magnitude.std()*pq.nA)
  327. self.assertEqual(self.signal1.var(), self.signal1.magnitude.var()*pq.nA**2)
  328. def test__rescale_same(self):
  329. result = self.signal1.copy()
  330. result = result.rescale(pq.nA)
  331. self.assertIsInstance(result, AnalogSignal)
  332. assert_neo_object_is_compliant(result)
  333. self.assertEqual(result.name, 'spam')
  334. self.assertEqual(result.description, 'eggs')
  335. self.assertEqual(result.file_origin, 'testfile.txt')
  336. self.assertEqual(result.annotations, {'arg1': 'test'})
  337. self.assertEqual(result.units, 1*pq.nA)
  338. assert_arrays_equal(result, self.data1)
  339. assert_same_sub_schema(result, self.signal1)
  340. def test__rescale_new(self):
  341. result = self.signal1.copy()
  342. result = result.rescale(pq.pA)
  343. self.assertIsInstance(result, AnalogSignal)
  344. assert_neo_object_is_compliant(result)
  345. self.assertEqual(result.name, 'spam')
  346. self.assertEqual(result.description, 'eggs')
  347. self.assertEqual(result.file_origin, 'testfile.txt')
  348. self.assertEqual(result.annotations, {'arg1': 'test'})
  349. self.assertEqual(result.units, 1*pq.pA)
  350. assert_arrays_almost_equal(np.array(result), self.data1*1000., 1e-10)
  351. def test__time_slice(self):
  352. t_start = 2 * pq.s
  353. t_stop = 4 * pq.s
  354. result = self.signal2.time_slice(t_start, t_stop)
  355. self.assertIsInstance(result, AnalogSignal)
  356. assert_neo_object_is_compliant(result)
  357. self.assertEqual(result.name, 'spam')
  358. self.assertEqual(result.description, 'eggs')
  359. self.assertEqual(result.file_origin, 'testfile.txt')
  360. self.assertEqual(result.annotations, {'arg1': 'test'})
  361. targ = AnalogSignal(np.array([[2., 3.], [2., 3.]]).T,
  362. sampling_rate=1.0*pq.Hz, units='mV',
  363. t_start=t_start,
  364. name='spam', description='eggs',
  365. file_origin='testfile.txt', arg1='test')
  366. assert_neo_object_is_compliant(result)
  367. self.assertEqual(result.t_stop, t_stop)
  368. self.assertEqual(result.t_start, t_start)
  369. self.assertEqual(result.sampling_rate, targ.sampling_rate)
  370. assert_array_equal(result, targ)
  371. assert_same_sub_schema(result, targ)
  372. def test__time_slice__out_of_bounds_ValueError(self):
  373. t_start_good = 2 * pq.s
  374. t_stop_good = 4 * pq.s
  375. t_start_bad = -2 * pq.s
  376. t_stop_bad = 40 * pq.s
  377. self.assertRaises(ValueError, self.signal2.time_slice,
  378. t_start_good, t_stop_bad)
  379. self.assertRaises(ValueError, self.signal2.time_slice,
  380. t_start_bad, t_stop_good)
  381. self.assertRaises(ValueError, self.signal2.time_slice,
  382. t_start_bad, t_stop_bad)
  383. def test__time_equal(self):
  384. t_start = 0 * pq.s
  385. t_stop = 6 * pq.s
  386. result = self.signal2.time_slice(t_start, t_stop)
  387. self.assertIsInstance(result, AnalogSignal)
  388. assert_neo_object_is_compliant(result)
  389. self.assertEqual(result.name, 'spam')
  390. self.assertEqual(result.description, 'eggs')
  391. self.assertEqual(result.file_origin, 'testfile.txt')
  392. self.assertEqual(result.annotations, {'arg1': 'test'})
  393. self.assertEqual(result.t_stop, t_stop)
  394. self.assertEqual(result.t_start, t_start)
  395. assert_array_equal(result, self.signal2)
  396. assert_same_sub_schema(result, self.signal2)
  397. def test__time_slice__offset(self):
  398. self.signal2.t_start = 10.0 * pq.s
  399. assert_neo_object_is_compliant(self.signal2)
  400. t_start = 12 * pq.s
  401. t_stop = 14 * pq.s
  402. result = self.signal2.time_slice(t_start, t_stop)
  403. self.assertIsInstance(result, AnalogSignal)
  404. assert_neo_object_is_compliant(result)
  405. self.assertEqual(result.name, 'spam')
  406. self.assertEqual(result.description, 'eggs')
  407. self.assertEqual(result.file_origin, 'testfile.txt')
  408. self.assertEqual(result.annotations, {'arg1': 'test'})
  409. targ = AnalogSignal(np.array([[2., 3.], [2., 3.]]).T,
  410. t_start=12.0*pq.ms,
  411. sampling_rate=1.0*pq.Hz, units='mV',
  412. name='spam', description='eggs',
  413. file_origin='testfile.txt', arg1='test')
  414. assert_neo_object_is_compliant(result)
  415. self.assertEqual(self.signal2.t_start, 10.0 * pq.s)
  416. self.assertEqual(result.t_stop, t_stop)
  417. self.assertEqual(result.t_start, t_start)
  418. self.assertEqual(result.sampling_rate, targ.sampling_rate)
  419. assert_arrays_equal(result, targ)
  420. assert_same_sub_schema(result, targ)
  421. def test__time_slice__different_units(self):
  422. self.signal2.t_start = 10.0 * pq.ms
  423. assert_neo_object_is_compliant(self.signal2)
  424. t_start = 2 * pq.s + 10.0 * pq.ms
  425. t_stop = 4 * pq.s + 10.0 * pq.ms
  426. result = self.signal2.time_slice(t_start, t_stop)
  427. self.assertIsInstance(result, AnalogSignal)
  428. assert_neo_object_is_compliant(result)
  429. self.assertEqual(result.name, 'spam')
  430. self.assertEqual(result.description, 'eggs')
  431. self.assertEqual(result.file_origin, 'testfile.txt')
  432. self.assertEqual(result.annotations, {'arg1': 'test'})
  433. targ = AnalogSignal(np.array([[2., 3.], [2., 3.]]).T,
  434. t_start=t_start.rescale(pq.ms),
  435. sampling_rate=1.0*pq.Hz, units='mV',
  436. name='spam', description='eggs',
  437. file_origin='testfile.txt', arg1='test')
  438. assert_neo_object_is_compliant(result)
  439. assert_neo_object_is_compliant(self.signal2)
  440. self.assertEqual(self.signal2.t_start, 10.0 * pq.ms)
  441. self.assertAlmostEqual(result.t_stop, t_stop, delta=1e-12*pq.ms)
  442. self.assertAlmostEqual(result.t_start, t_start, delta=1e-12*pq.ms)
  443. assert_arrays_almost_equal(result.times, targ.times, 1e-12*pq.ms)
  444. self.assertEqual(result.sampling_rate, targ.sampling_rate)
  445. assert_arrays_equal(result, targ)
  446. assert_same_sub_schema(result, targ)
  447. def test__time_slice__no_explicit_time(self):
  448. self.signal2.t_start = 10.0 * pq.ms
  449. assert_neo_object_is_compliant(self.signal2)
  450. t1 = 2 * pq.s + 10.0 * pq.ms
  451. t2 = 4 * pq.s + 10.0 * pq.ms
  452. for t_start,t_stop in [(t1,None),(None,None),(None,t2)]:
  453. t_start_targ = t1 if t_start!=None else self.signal2.t_start
  454. t_stop_targ = t2 if t_stop!=None else self.signal2.t_stop
  455. result = self.signal2.time_slice(t_start, t_stop)
  456. self.assertIsInstance(result, AnalogSignal)
  457. assert_neo_object_is_compliant(result)
  458. self.assertEqual(result.name, 'spam')
  459. self.assertEqual(result.description, 'eggs')
  460. self.assertEqual(result.file_origin, 'testfile.txt')
  461. self.assertEqual(result.annotations, {'arg1': 'test'})
  462. targ_ind = np.where((self.signal2.times >= t_start_targ) &
  463. (self.signal2.times < t_stop_targ))
  464. targ_array = self.signal2.magnitude[targ_ind]
  465. targ = AnalogSignal(targ_array,
  466. t_start=t_start_targ.rescale(pq.ms),
  467. sampling_rate=1.0*pq.Hz, units='mV',
  468. name='spam', description='eggs',
  469. file_origin='testfile.txt', arg1='test')
  470. assert_neo_object_is_compliant(result)
  471. assert_neo_object_is_compliant(self.signal2)
  472. self.assertEqual(self.signal2.t_start, 10.0 * pq.ms)
  473. self.assertAlmostEqual(result.t_stop, t_stop_targ, delta=1e-12*pq.ms)
  474. self.assertAlmostEqual(result.t_start, t_start_targ, delta=1e-12*pq.ms)
  475. assert_arrays_almost_equal(result.times, targ.times, 1e-12*pq.ms)
  476. self.assertEqual(result.sampling_rate, targ.sampling_rate)
  477. assert_array_equal(result.magnitude, targ.magnitude)
  478. assert_same_sub_schema(result, targ)
  479. class TestAnalogSignalArrayEquality(unittest.TestCase):
  480. def test__signals_with_different_data_complement_should_be_not_equal(self):
  481. signal1 = AnalogSignal(np.arange(55.0).reshape((11, 5)),
  482. units="mV", sampling_rate=1*pq.kHz)
  483. signal2 = AnalogSignal(np.arange(55.0).reshape((11, 5)),
  484. units="mV", sampling_rate=2*pq.kHz)
  485. self.assertNotEqual(signal1, signal2)
  486. assert_neo_object_is_compliant(signal1)
  487. assert_neo_object_is_compliant(signal2)
  488. class TestAnalogSignalArrayCombination(unittest.TestCase):
  489. def setUp(self):
  490. self.data1 = np.arange(55.0).reshape((11, 5))
  491. self.data1quant = self.data1 * pq.mV
  492. self.signal1 = AnalogSignal(self.data1quant,
  493. sampling_rate=1*pq.kHz,
  494. name='spam', description='eggs',
  495. file_origin='testfile.txt',
  496. arg1='test')
  497. self.data2 = np.arange(100.0, 155.0).reshape((11, 5))
  498. self.data2quant = self.data2 * pq.mV
  499. self.signal2 = AnalogSignal(self.data2quant,
  500. sampling_rate=1*pq.kHz,
  501. name='spam', description='eggs',
  502. file_origin='testfile.txt',
  503. arg1='test')
  504. def test__compliant(self):
  505. assert_neo_object_is_compliant(self.signal1)
  506. self.assertEqual(self.signal1.name, 'spam')
  507. self.assertEqual(self.signal1.description, 'eggs')
  508. self.assertEqual(self.signal1.file_origin, 'testfile.txt')
  509. self.assertEqual(self.signal1.annotations, {'arg1': 'test'})
  510. assert_neo_object_is_compliant(self.signal2)
  511. self.assertEqual(self.signal2.name, 'spam')
  512. self.assertEqual(self.signal2.description, 'eggs')
  513. self.assertEqual(self.signal2.file_origin, 'testfile.txt')
  514. self.assertEqual(self.signal2.annotations, {'arg1': 'test'})
  515. def test__add_const_quantity_should_preserve_data_complement(self):
  516. result = self.signal1 + 0.065*pq.V
  517. self.assertIsInstance(result, AnalogSignal)
  518. assert_neo_object_is_compliant(result)
  519. self.assertEqual(result.name, 'spam')
  520. self.assertEqual(result.description, 'eggs')
  521. self.assertEqual(result.file_origin, 'testfile.txt')
  522. self.assertEqual(result.annotations, {'arg1': 'test'})
  523. # time zero, signal index 4
  524. assert_arrays_equal(result, self.data1 + 65)
  525. self.assertEqual(self.signal1[0, 4], 4*pq.mV)
  526. self.assertEqual(result[0, 4], 69000*pq.uV)
  527. self.assertEqual(self.signal1.t_start, result.t_start)
  528. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  529. def test__add_two_consistent_signals_should_preserve_data_complement(self):
  530. result = self.signal1 + self.signal2
  531. self.assertIsInstance(result, AnalogSignal)
  532. assert_neo_object_is_compliant(result)
  533. self.assertEqual(result.name, 'spam')
  534. self.assertEqual(result.description, 'eggs')
  535. self.assertEqual(result.file_origin, 'testfile.txt')
  536. self.assertEqual(result.annotations, {'arg1': 'test'})
  537. targdata = np.arange(100.0, 210.0, 2.0).reshape((11, 5))
  538. targ = AnalogSignal(targdata, units="mV",
  539. sampling_rate=1*pq.kHz,
  540. name='spam', description='eggs',
  541. file_origin='testfile.txt', arg1='test')
  542. assert_neo_object_is_compliant(targ)
  543. assert_arrays_equal(result, targdata)
  544. assert_same_sub_schema(result, targ)
  545. def test__add_signals_with_inconsistent_data_complement_ValueError(self):
  546. self.signal2.sampling_rate = 0.5*pq.kHz
  547. assert_neo_object_is_compliant(self.signal2)
  548. self.assertRaises(ValueError, self.signal1.__add__, self.signal2)
  549. def test__subtract_const_should_preserve_data_complement(self):
  550. result = self.signal1 - 65*pq.mV
  551. self.assertIsInstance(result, AnalogSignal)
  552. assert_neo_object_is_compliant(result)
  553. self.assertEqual(result.name, 'spam')
  554. self.assertEqual(result.description, 'eggs')
  555. self.assertEqual(result.file_origin, 'testfile.txt')
  556. self.assertEqual(result.annotations, {'arg1': 'test'})
  557. self.assertEqual(np.array(self.signal1[1, 4]), 9)
  558. self.assertEqual(np.array(result[1, 4]), -56)
  559. assert_arrays_equal(result, self.data1 - 65)
  560. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  561. def test__subtract_from_const_should_return_signal(self):
  562. result = 10*pq.mV - self.signal1
  563. self.assertIsInstance(result, AnalogSignal)
  564. assert_neo_object_is_compliant(result)
  565. self.assertEqual(result.name, 'spam')
  566. self.assertEqual(result.description, 'eggs')
  567. self.assertEqual(result.file_origin, 'testfile.txt')
  568. self.assertEqual(result.annotations, {'arg1': 'test'})
  569. self.assertEqual(np.array(self.signal1[1, 4]), 9)
  570. self.assertEqual(np.array(result[1, 4]), 1)
  571. assert_arrays_equal(result, 10 - self.data1)
  572. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  573. def test__mult_by_const_float_should_preserve_data_complement(self):
  574. result = self.signal1*2
  575. self.assertIsInstance(result, AnalogSignal)
  576. assert_neo_object_is_compliant(result)
  577. self.assertEqual(result.name, 'spam')
  578. self.assertEqual(result.description, 'eggs')
  579. self.assertEqual(result.file_origin, 'testfile.txt')
  580. self.assertEqual(result.annotations, {'arg1': 'test'})
  581. self.assertEqual(np.array(self.signal1[1, 4]), 9)
  582. self.assertEqual(np.array(result[1, 4]), 18)
  583. assert_arrays_equal(result, self.data1*2)
  584. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  585. def test__divide_by_const_should_preserve_data_complement(self):
  586. result = self.signal1/0.5
  587. self.assertIsInstance(result, AnalogSignal)
  588. assert_neo_object_is_compliant(result)
  589. self.assertEqual(result.name, 'spam')
  590. self.assertEqual(result.description, 'eggs')
  591. self.assertEqual(result.file_origin, 'testfile.txt')
  592. self.assertEqual(result.annotations, {'arg1': 'test'})
  593. self.assertEqual(np.array(self.signal1[1, 4]), 9)
  594. self.assertEqual(np.array(result[1, 4]), 18)
  595. assert_arrays_equal(result, self.data1/0.5)
  596. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  597. def test__merge(self):
  598. self.signal1.description = None
  599. self.signal1.file_origin = None
  600. assert_neo_object_is_compliant(self.signal1)
  601. data3 = np.arange(1000.0, 1066.0).reshape((11, 6)) * pq.uV
  602. data3scale = data3.rescale(self.data1quant.units)
  603. signal2 = AnalogSignal(self.data1quant,
  604. sampling_rate=1*pq.kHz,
  605. name='signal2',
  606. description='test signal',
  607. file_origin='testfile.txt')
  608. signal3 = AnalogSignal(data3,
  609. units="uV", sampling_rate=1*pq.kHz,
  610. name='signal3',
  611. description='test signal',
  612. file_origin='testfile.txt')
  613. signal4 = AnalogSignal(data3,
  614. units="uV", sampling_rate=1*pq.kHz,
  615. name='signal4',
  616. description='test signal',
  617. file_origin='testfile.txt')
  618. merged13 = self.signal1.merge(signal3)
  619. merged23 = signal2.merge(signal3)
  620. merged24 = signal2.merge(signal4)
  621. mergeddata13 = np.array(merged13)
  622. mergeddata23 = np.array(merged23)
  623. mergeddata24 = np.array(merged24)
  624. targdata13 = np.hstack([self.data1quant, data3scale])
  625. targdata23 = np.hstack([self.data1quant, data3scale])
  626. targdata24 = np.hstack([self.data1quant, data3scale])
  627. assert_neo_object_is_compliant(signal2)
  628. assert_neo_object_is_compliant(signal3)
  629. assert_neo_object_is_compliant(merged13)
  630. assert_neo_object_is_compliant(merged23)
  631. assert_neo_object_is_compliant(merged24)
  632. self.assertEqual(merged13[0, 4], 4*pq.mV)
  633. self.assertEqual(merged23[0, 4], 4*pq.mV)
  634. self.assertEqual(merged13[0, 5], 1*pq.mV)
  635. self.assertEqual(merged23[0, 5], 1*pq.mV)
  636. self.assertEqual(merged13[10, 10], 1.065*pq.mV)
  637. self.assertEqual(merged23[10, 10], 1.065*pq.mV)
  638. self.assertEqual(merged13.t_stop, self.signal1.t_stop)
  639. self.assertEqual(merged23.t_stop, self.signal1.t_stop)
  640. self.assertEqual(merged13.name, 'merge(spam, signal3)')
  641. self.assertEqual(merged23.name, 'merge(signal2, signal3)')
  642. self.assertEqual(merged13.description, 'merge(None, test signal)')
  643. self.assertEqual(merged23.description, 'test signal')
  644. self.assertEqual(merged13.file_origin, 'merge(None, testfile.txt)')
  645. self.assertEqual(merged23.file_origin, 'testfile.txt')
  646. assert_arrays_equal(mergeddata13, targdata13)
  647. assert_arrays_equal(mergeddata23, targdata23)
  648. assert_arrays_equal(mergeddata24, targdata24)
  649. class TestAnalogSignalArrayFunctions(unittest.TestCase):
  650. def test__pickle(self):
  651. signal1 = AnalogSignal(np.arange(55.0).reshape((11, 5)),
  652. units="mV", sampling_rate=1*pq.kHz)
  653. fobj = open('./pickle', 'wb')
  654. pickle.dump(signal1, fobj)
  655. fobj.close()
  656. fobj = open('./pickle', 'rb')
  657. try:
  658. signal2 = pickle.load(fobj)
  659. except ValueError:
  660. signal2 = None
  661. assert_array_equal(signal1, signal2)
  662. assert_neo_object_is_compliant(signal1)
  663. assert_neo_object_is_compliant(signal2)
  664. fobj.close()
  665. os.remove('./pickle')
  666. if __name__ == "__main__":
  667. unittest.main()