conversion.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. # -*- coding: utf-8 -*-
  2. """
  3. This module allows to convert standard data representations
  4. (e.g., a spike train stored as Neo SpikeTrain object)
  5. into other representations useful to perform calculations on the data.
  6. An example is the representation of a spike train as a sequence of 0-1 values
  7. (binned spike train).
  8. :copyright: Copyright 2014-2016 by the Elephant team, see AUTHORS.txt.
  9. :license: BSD, see LICENSE.txt for details.
  10. """
  11. from __future__ import division, print_function
  12. import neo
  13. import scipy
  14. import scipy.sparse as sps
  15. import numpy as np
  16. import quantities as pq
  17. def binarize(spiketrain, sampling_rate=None, t_start=None, t_stop=None,
  18. return_times=None):
  19. """
  20. Return an array indicating if spikes occured at individual time points.
  21. The array contains boolean values identifying whether one or more spikes
  22. happened in the corresponding time bin. Time bins start at `t_start`
  23. and end at `t_stop`, spaced in `1/sampling_rate` intervals.
  24. Accepts either a Neo SpikeTrain, a Quantity array, or a plain NumPy array.
  25. Returns a boolean array with each element being the presence or absence of
  26. a spike in that time bin. The number of spikes in a time bin is not
  27. considered.
  28. Optionally also returns an array of time points corresponding to the
  29. elements of the boolean array. The units of this array will be the same as
  30. the units of the SpikeTrain, if any.
  31. Parameters
  32. ----------
  33. spiketrain : Neo SpikeTrain or Quantity array or NumPy array
  34. The spike times. Does not have to be sorted.
  35. sampling_rate : float or Quantity scalar, optional
  36. The sampling rate to use for the time points.
  37. If not specified, retrieved from the `sampling_rate`
  38. attribute of `spiketrain`.
  39. t_start : float or Quantity scalar, optional
  40. The start time to use for the time points.
  41. If not specified, retrieved from the `t_start`
  42. attribute of `spiketrain`. If that is not present, default to
  43. `0`. Any value from `spiketrain` below this value is
  44. ignored.
  45. t_stop : float or Quantity scalar, optional
  46. The start time to use for the time points.
  47. If not specified, retrieved from the `t_stop`
  48. attribute of `spiketrain`. If that is not present, default to
  49. the maximum value of `sspiketrain`. Any value from
  50. `spiketrain` above this value is ignored.
  51. return_times : bool
  52. If True, also return the corresponding time points.
  53. Returns
  54. -------
  55. values : NumPy array of bools
  56. A ``True`` value at a particular index indicates the presence of
  57. one or more spikes at the corresponding time point.
  58. times : NumPy array or Quantity array, optional
  59. The time points. This will have the same units as `spiketrain`.
  60. If `spiketrain` has no units, this will be an NumPy array.
  61. Notes
  62. -----
  63. Spike times are placed in the bin of the closest time point, going to the
  64. higher bin if exactly between two bins.
  65. So in the case where the bins are `5.5` and `6.5`, with the spike time
  66. being `6.0`, the spike will be placed in the `6.5` bin.
  67. The upper edge of the last bin, equal to `t_stop`, is inclusive. That is,
  68. a spike time exactly equal to `t_stop` will be included.
  69. If `spiketrain` is a Quantity or Neo SpikeTrain and
  70. `t_start`, `t_stop` or `sampling_rate` is not, then the arguments that
  71. are not quantities will be assumed to have the same units as `spiketrain`.
  72. Raises
  73. ------
  74. TypeError
  75. If `spiketrain` is a NumPy array and `t_start`, `t_stop`, or
  76. `sampling_rate` is a Quantity..
  77. ValueError
  78. `t_start` and `t_stop` can be inferred from `spiketrain` if
  79. not explicitly defined and not an attribute of `spiketrain`.
  80. `sampling_rate` cannot, so an exception is raised if it is not
  81. explicitly defined and not present as an attribute of `spiketrain`.
  82. """
  83. # get the values from spiketrain if they are not specified.
  84. if sampling_rate is None:
  85. sampling_rate = getattr(spiketrain, 'sampling_rate', None)
  86. if sampling_rate is None:
  87. raise ValueError('sampling_rate must either be explicitly defined '
  88. 'or must be an attribute of spiketrain')
  89. if t_start is None:
  90. t_start = getattr(spiketrain, 't_start', 0)
  91. if t_stop is None:
  92. t_stop = getattr(spiketrain, 't_stop', np.max(spiketrain))
  93. # we don't actually want the sampling rate, we want the sampling period
  94. sampling_period = 1. / sampling_rate
  95. # figure out what units, if any, we are dealing with
  96. if hasattr(spiketrain, 'units'):
  97. units = spiketrain.units
  98. spiketrain = spiketrain.magnitude
  99. else:
  100. units = None
  101. # convert everything to the same units, then get the magnitude
  102. if hasattr(sampling_period, 'units'):
  103. if units is None:
  104. raise TypeError('sampling_period cannot be a Quantity if '
  105. 'spiketrain is not a quantity')
  106. sampling_period = sampling_period.rescale(units).magnitude
  107. if hasattr(t_start, 'units'):
  108. if units is None:
  109. raise TypeError('t_start cannot be a Quantity if '
  110. 'spiketrain is not a quantity')
  111. t_start = t_start.rescale(units).magnitude
  112. if hasattr(t_stop, 'units'):
  113. if units is None:
  114. raise TypeError('t_stop cannot be a Quantity if '
  115. 'spiketrain is not a quantity')
  116. t_stop = t_stop.rescale(units).magnitude
  117. # figure out the bin edges
  118. edges = np.arange(t_start - sampling_period / 2, t_stop + sampling_period * 3 / 2,
  119. sampling_period)
  120. # we don't want to count any spikes before t_start or after t_stop
  121. if edges[-2] > t_stop:
  122. edges = edges[:-1]
  123. if edges[1] < t_start:
  124. edges = edges[1:]
  125. edges[0] = t_start
  126. edges[-1] = t_stop
  127. # this is where we actually get the binarized spike train
  128. res = np.histogram(spiketrain, edges)[0].astype('bool')
  129. # figure out what to output
  130. if not return_times:
  131. return res
  132. elif units is None:
  133. return res, np.arange(t_start, t_stop + sampling_period, sampling_period)
  134. else:
  135. return res, pq.Quantity(np.arange(t_start, t_stop + sampling_period,
  136. sampling_period), units=units)
  137. ###########################################################################
  138. #
  139. # Methods to calculate parameters, t_start, t_stop, bin size,
  140. # number of bins
  141. #
  142. ###########################################################################
  143. def _calc_tstart(num_bins, binsize, t_stop):
  144. """
  145. Calculates the start point from given parameter.
  146. Calculates the start point :attr:`t_start` from the three parameter
  147. :attr:`t_stop`, :attr:`num_bins` and :attr`binsize`.
  148. Parameters
  149. ----------
  150. num_bins: int
  151. Number of bins
  152. binsize: quantities.Quantity
  153. Size of Bins
  154. t_stop: quantities.Quantity
  155. Stop time
  156. Returns
  157. -------
  158. t_start : quantities.Quantity
  159. Starting point calculated from given parameter.
  160. """
  161. if num_bins is not None and binsize is not None and t_stop is not None:
  162. return t_stop.rescale(binsize.units) - num_bins * binsize
  163. def _calc_tstop(num_bins, binsize, t_start):
  164. """
  165. Calculates the stop point from given parameter.
  166. Calculates the stop point :attr:`t_stop` from the three parameter
  167. :attr:`t_start`, :attr:`num_bins` and :attr`binsize`.
  168. Parameters
  169. ----------
  170. num_bins: int
  171. Number of bins
  172. binsize: quantities.Quantity
  173. Size of bins
  174. t_start: quantities.Quantity
  175. Start time
  176. Returns
  177. -------
  178. t_stop : quantities.Quantity
  179. Stoping point calculated from given parameter.
  180. """
  181. if num_bins is not None and binsize is not None and t_start is not None:
  182. return t_start.rescale(binsize.units) + num_bins * binsize
  183. def _calc_num_bins(binsize, t_start, t_stop):
  184. """
  185. Calculates the number of bins from given parameter.
  186. Calculates the number of bins :attr:`num_bins` from the three parameter
  187. :attr:`t_start`, :attr:`t_stop` and :attr`binsize`.
  188. Parameters
  189. ----------
  190. binsize: quantities.Quantity
  191. Size of Bins
  192. t_start : quantities.Quantity
  193. Start time
  194. t_stop: quantities.Quantity
  195. Stop time
  196. Returns
  197. -------
  198. num_bins : int
  199. Number of bins calculated from given parameter.
  200. Raises
  201. ------
  202. ValueError :
  203. Raised when :attr:`t_stop` is smaller than :attr:`t_start`".
  204. """
  205. if binsize is not None and t_start is not None and t_stop is not None:
  206. if t_stop < t_start:
  207. raise ValueError("t_stop (%s) is smaller than t_start (%s)"
  208. % (t_stop, t_start))
  209. return int(((t_stop - t_start).rescale(
  210. binsize.units) / binsize).magnitude)
  211. def _calc_binsize(num_bins, t_start, t_stop):
  212. """
  213. Calculates the stop point from given parameter.
  214. Calculates the size of bins :attr:`binsize` from the three parameter
  215. :attr:`num_bins`, :attr:`t_start` and :attr`t_stop`.
  216. Parameters
  217. ----------
  218. num_bins: int
  219. Number of bins
  220. t_start: quantities.Quantity
  221. Start time
  222. t_stop
  223. Stop time
  224. Returns
  225. -------
  226. binsize : quantities.Quantity
  227. Size of bins calculated from given parameter.
  228. Raises
  229. ------
  230. ValueError :
  231. Raised when :attr:`t_stop` is smaller than :attr:`t_start`".
  232. """
  233. if num_bins is not None and t_start is not None and t_stop is not None:
  234. if t_stop < t_start:
  235. raise ValueError("t_stop (%s) is smaller than t_start (%s)"
  236. % (t_stop, t_start))
  237. return (t_stop - t_start) / num_bins
  238. def _get_start_stop_from_input(spiketrains):
  239. """
  240. Returns the start :attr:`t_start`and stop :attr:`t_stop` point
  241. from given input.
  242. If one neo.SpikeTrain objects is given the start :attr:`t_stop `and stop
  243. :attr:`t_stop` of the spike train is returned.
  244. Otherwise the aligned times are returned, which are the maximal start point
  245. and minimal stop point.
  246. Parameters
  247. ----------
  248. spiketrains: neo.SpikeTrain object, list or array of neo.core.SpikeTrain
  249. objects
  250. List of neo.core SpikeTrain objects to extract `t_start` and
  251. `t_stop` from.
  252. Returns
  253. -------
  254. start : quantities.Quantity
  255. Start point extracted from input :attr:`spiketrains`
  256. stop : quantities.Quantity
  257. Stop point extracted from input :attr:`spiketrains`
  258. """
  259. if isinstance(spiketrains, neo.SpikeTrain):
  260. return spiketrains.t_start, spiketrains.t_stop
  261. else:
  262. start = max([elem.t_start for elem in spiketrains])
  263. stop = min([elem.t_stop for elem in spiketrains])
  264. return start, stop
  265. class BinnedSpikeTrain(object):
  266. """
  267. Class which calculates a binned spike train and provides methods to
  268. transform the binned spike train to a boolean matrix or a matrix with
  269. counted time points.
  270. A binned spike train represents the occurrence of spikes in a certain time
  271. frame.
  272. I.e., a time series like [0.5, 0.7, 1.2, 3.1, 4.3, 5.5, 6.7] is
  273. represented as [0, 0, 1, 3, 4, 5, 6]. The outcome is dependent on given
  274. parameter such as size of bins, number of bins, start and stop points.
  275. A boolean matrix represents the binned spike train in a binary (True/False)
  276. manner.
  277. Its rows represent the number of spike trains
  278. and the columns represent the binned index position of a spike in a
  279. spike train.
  280. The calculated matrix columns contains **Trues**, which indicate
  281. a spike.
  282. A matrix with counted time points is calculated the same way, but its
  283. columns contain the number of spikes that occurred in the spike train(s).
  284. It counts the occurrence of the timing of a spike in its respective
  285. spike train.
  286. Parameters
  287. ----------
  288. spiketrains : List of `neo.SpikeTrain` or a `neo.SpikeTrain` object
  289. Spiketrain(s)to be binned.
  290. binsize : quantities.Quantity
  291. Width of each time bin.
  292. Default is `None`
  293. num_bins : int
  294. Number of bins of the binned spike train.
  295. Default is `None`
  296. t_start : quantities.Quantity
  297. Time of the first bin (left extreme; included).
  298. Default is `None`
  299. t_stop : quantities.Quantity
  300. Stopping time of the last bin (right extreme; excluded).
  301. Default is `None`
  302. See also
  303. --------
  304. _convert_to_binned
  305. spike_indices
  306. to_bool_array
  307. to_array
  308. Notes
  309. -----
  310. There are four cases the given parameters must fulfill.
  311. Each parameter must be a combination of following order or it will raise
  312. a value error:
  313. * t_start, num_bins, binsize
  314. * t_start, num_bins, t_stop
  315. * t_start, bin_size, t_stop
  316. * t_stop, num_bins, binsize
  317. It is possible to give the SpikeTrain objects and one parameter
  318. (:attr:`num_bins` or :attr:`binsize`). The start and stop time will be
  319. calculated from given SpikeTrain objects (max start and min stop point).
  320. Missing parameter will also be calculated automatically.
  321. All parameters will be checked for consistency. A corresponding error will
  322. be raised, if one of the four parameters does not match the consistency
  323. requirements.
  324. """
  325. def __init__(self, spiketrains, binsize=None, num_bins=None, t_start=None,
  326. t_stop=None):
  327. """
  328. Defines a binned spike train class
  329. """
  330. # Converting spiketrains to a list, if spiketrains is one
  331. # SpikeTrain object
  332. if isinstance(spiketrains, neo.SpikeTrain):
  333. spiketrains = [spiketrains]
  334. # Check that spiketrains is a list of neo Spike trains.
  335. if not all([type(elem) == neo.core.SpikeTrain for elem in spiketrains]):
  336. raise TypeError(
  337. "All elements of the input list must be neo.core.SpikeTrain "
  338. "objects ")
  339. # Link to input
  340. self.lst_input = spiketrains
  341. # Set given parameter
  342. self.t_start = t_start
  343. self.t_stop = t_stop
  344. self.num_bins = num_bins
  345. self.binsize = binsize
  346. self.matrix_columns = num_bins
  347. self.matrix_rows = len(spiketrains)
  348. # Empty matrix for storage, time points matrix
  349. self._mat_u = None
  350. # Check all parameter, set also missing values
  351. self._calc_start_stop(spiketrains)
  352. self._check_init_params(binsize, num_bins, self.t_start, self.t_stop)
  353. self._check_consistency(spiketrains, self.binsize, self.num_bins,
  354. self.t_start, self.t_stop)
  355. # Variables to store the sparse matrix
  356. self._sparse_mat_u = None
  357. # Now create sparse matrix
  358. self._convert_to_binned(spiketrains)
  359. # =========================================================================
  360. # There are four cases the given parameters must fulfill
  361. # Each parameter must be a combination of following order or it will raise
  362. # a value error:
  363. # t_start, num_bins, binsize
  364. # t_start, num_bins, t_stop
  365. # t_start, bin_size, t_stop
  366. # t_stop, num_bins, binsize
  367. # ==========================================================================
  368. def _check_init_params(self, binsize, num_bins, t_start, t_stop):
  369. """
  370. Checks given parameter.
  371. Calculates also missing parameter.
  372. Parameters
  373. ----------
  374. binsize : quantity.Quantity
  375. Size of Bins
  376. num_bins : int
  377. Number of Bins
  378. t_start: quantity.Quantity
  379. Start time of the spike
  380. t_stop: quantity.Quantity
  381. Stop time of the spike
  382. Raises
  383. ------
  384. ValueError :
  385. If all parameters are `None`, a ValueError is raised.
  386. TypeError:
  387. If type of :attr:`num_bins` is not an Integer.
  388. """
  389. # Check if num_bins is an integer (special case)
  390. if num_bins is not None:
  391. if not isinstance(num_bins, int):
  392. raise TypeError("num_bins is not an integer!")
  393. # Check if all parameters can be calculated, otherwise raise ValueError
  394. if t_start is None:
  395. self.t_start = _calc_tstart(num_bins, binsize, t_stop)
  396. elif t_stop is None:
  397. self.t_stop = _calc_tstop(num_bins, binsize, t_start)
  398. elif num_bins is None:
  399. self.num_bins = _calc_num_bins(binsize, t_start, t_stop)
  400. if self.matrix_columns is None:
  401. self.matrix_columns = self.num_bins
  402. elif binsize is None:
  403. self.binsize = _calc_binsize(num_bins, t_start, t_stop)
  404. def _calc_start_stop(self, spiketrains):
  405. """
  406. Calculates start, stop from given spike trains.
  407. The start and stop points are calculated from given spike trains, only
  408. if they are not calculable from given parameter or the number of
  409. parameters is less than three.
  410. """
  411. if self._count_params() is False:
  412. start, stop = _get_start_stop_from_input(spiketrains)
  413. if self.t_start is None:
  414. self.t_start = start
  415. if self.t_stop is None:
  416. self.t_stop = stop
  417. def _count_params(self):
  418. """
  419. Counts up if one parameter is not `None` and returns **True** if the
  420. count is greater or equal `3`.
  421. The calculation of the binned matrix is only possible if there are at
  422. least three parameter (fourth parameter will be calculated out of
  423. them).
  424. This method checks if the necessary parameter are not `None` and
  425. returns **True** if the count is greater or equal to `3`.
  426. Returns
  427. -------
  428. bool :
  429. True, if the count is greater or equal to `3`.
  430. False, otherwise.
  431. """
  432. return sum(x is not None for x in
  433. [self.t_start, self.t_stop, self.binsize,
  434. self.num_bins]) >= 3
  435. def _check_consistency(self, spiketrains, binsize, num_bins, t_start,
  436. t_stop):
  437. """
  438. Checks the given parameters for consistency
  439. Raises
  440. ------
  441. ValueError :
  442. A ValueError is raised if an inconsistency regarding the parameter
  443. appears.
  444. AttributeError :
  445. An AttributeError is raised if there is an insufficient number of
  446. parameters.
  447. """
  448. if self._count_params() is False:
  449. raise AttributeError("Too less parameter given. Please provide "
  450. "at least one of the parameter which are "
  451. "None.\n"
  452. "t_start: %s, t_stop: %s, binsize: %s, "
  453. "numb_bins: %s" % (
  454. self.t_start,
  455. self.t_stop,
  456. self.binsize,
  457. self.num_bins))
  458. t_starts = [elem.t_start for elem in spiketrains]
  459. t_stops = [elem.t_stop for elem in spiketrains]
  460. max_tstart = max(t_starts)
  461. min_tstop = min(t_stops)
  462. if max_tstart >= min_tstop:
  463. raise ValueError(
  464. "Starting time of each spike train must be smaller than each "
  465. "stopping time")
  466. elif t_start < max_tstart or t_start > min_tstop:
  467. raise ValueError(
  468. 'some spike trains are not defined in the time given '
  469. 'by t_start')
  470. elif num_bins != int((
  471. (t_stop - t_start).rescale(binsize.units) / binsize).magnitude):
  472. raise ValueError(
  473. "Inconsistent arguments t_start (%s), " % t_start +
  474. "t_stop (%s), binsize (%d) " % (t_stop, binsize) +
  475. "and num_bins (%d)" % num_bins)
  476. elif not (t_start < t_stop <= min_tstop):
  477. raise ValueError(
  478. 'too many / too large time bins. Some spike trains are '
  479. 'not defined in the ending time')
  480. elif num_bins - int(num_bins) != 0 or num_bins < 0:
  481. raise TypeError(
  482. "Number of bins (num_bins) is not an integer or < 0: " + str(
  483. num_bins))
  484. @property
  485. def bin_edges(self):
  486. """
  487. Returns all time edges with :attr:`num_bins` bins as a quantity array.
  488. The borders of all time steps between start and stop [start, stop]
  489. with:attr:`num_bins` bins are regarded as edges.
  490. The border of the last bin is included.
  491. Returns
  492. -------
  493. bin_edges : quantities.Quantity array
  494. All edges in interval [start, stop] with :attr:`num_bins` bins
  495. are returned as a quantity array.
  496. """
  497. return pq.Quantity(np.linspace(self.t_start.magnitude,
  498. self.t_stop.magnitude,
  499. self.num_bins + 1, endpoint=True),
  500. units=self.binsize.units)
  501. @property
  502. def bin_centers(self):
  503. """
  504. Returns each center time point of all bins between start and stop
  505. points.
  506. The center of each bin of all time steps between start and stop
  507. (start, stop).
  508. Returns
  509. -------
  510. bin_edges : quantities.Quantity array
  511. All center edges in interval (start, stop) are returned as
  512. a quantity array.
  513. """
  514. return self.bin_edges[:-1] + self.binsize / 2
  515. def to_sparse_array(self):
  516. """
  517. Getter for sparse matrix with time points.
  518. Returns
  519. -------
  520. matrix: scipy.sparse.csr_matrix
  521. Sparse matrix, counted version.
  522. See also
  523. --------
  524. scipy.sparse.csr_matrix
  525. to_array
  526. """
  527. return self._sparse_mat_u
  528. def to_sparse_bool_array(self):
  529. """
  530. Getter for **boolean** version of the sparse matrix, calculated from
  531. sparse matrix with counted time points.
  532. Returns
  533. -------
  534. matrix: scipy.sparse.csr_matrix
  535. Sparse matrix, binary, boolean version.
  536. See also
  537. --------
  538. scipy.sparse.csr_matrix
  539. to_bool_array
  540. """
  541. # Return sparse Matrix as a copy
  542. tmp_mat = self._sparse_mat_u.copy()
  543. tmp_mat[tmp_mat.nonzero()] = 1
  544. return tmp_mat.astype(bool)
  545. @property
  546. def spike_indices(self):
  547. """
  548. A list of lists for each spike train (i.e., rows of the binned matrix),
  549. that in turn contains for each spike the index into the binned matrix
  550. where this spike enters.
  551. In contrast to `to_sparse_array().nonzero()`, this function will report
  552. two spikes falling in the same bin as two entries.
  553. Examples
  554. --------
  555. >>> import elephant.conversion as conv
  556. >>> import neo as n
  557. >>> import quantities as pq
  558. >>> st = n.SpikeTrain([0.5, 0.7, 1.2, 3.1, 4.3, 5.5, 6.7] * pq.s, t_stop=10.0 * pq.s)
  559. >>> x = conv.BinnedSpikeTrain(st, num_bins=10, binsize=1 * pq.s, t_start=0 * pq.s)
  560. >>> print(x.spike_indices)
  561. [[0, 0, 1, 3, 4, 5, 6]]
  562. >>> print(x.to_sparse_array().nonzero()[1])
  563. [0 1 3 4 5 6]
  564. """
  565. spike_idx = []
  566. for row in self._sparse_mat_u:
  567. l = []
  568. # Extract each non-zeros column index and how often it exists,
  569. # i.e., how many spikes fall in this column
  570. for col, count in zip(row.nonzero()[1], row.data):
  571. # Append the column index for each spike
  572. l.extend([col] * count)
  573. spike_idx.append(l)
  574. return spike_idx
  575. def to_bool_array(self):
  576. """
  577. Returns a dense matrix (`scipy.sparse.csr_matrix`), which rows
  578. represent the number of spike trains and the columns represent the
  579. binned index position of a spike in a spike train.
  580. The matrix columns contain **True**, which indicate a spike and
  581. **False** for non spike.
  582. Returns
  583. -------
  584. bool matrix : numpy.ndarray
  585. Returns a dense matrix representation of the sparse matrix,
  586. with **True** indicating a spike and **False*** for
  587. non spike.
  588. The **Trues** in the columns represent the index
  589. position of the spike in the spike train and rows represent the
  590. number of spike trains.
  591. Examples
  592. --------
  593. >>> import elephant.conversion as conv
  594. >>> import neo as n
  595. >>> import quantities as pq
  596. >>> a = n.SpikeTrain([0.5, 0.7, 1.2, 3.1, 4.3, 5.5, 6.7] * pq.s, t_stop=10.0 * pq.s)
  597. >>> x = conv.BinnedSpikeTrain(a, num_bins=10, binsize=1 * pq.s, t_start=0 * pq.s)
  598. >>> print(x.to_bool_array())
  599. [[ True True False True True True True False False False]]
  600. See also
  601. --------
  602. scipy.sparse.csr_matrix
  603. scipy.sparse.csr_matrix.toarray
  604. """
  605. return abs(scipy.sign(self.to_array())).astype(bool)
  606. def to_array(self, store_array=False):
  607. """
  608. Returns a dense matrix, calculated from the sparse matrix with counted
  609. time points, which rows represents the number of spike trains and the
  610. columns represents the binned index position of a spike in a
  611. spike train.
  612. The matrix columns contain the number of spikes that
  613. occurred in the spike train(s).
  614. If the **boolean** :attr:`store_array` is set to **True** the matrix
  615. will be stored in memory.
  616. Returns
  617. -------
  618. matrix : numpy.ndarray
  619. Matrix with spike times. Columns represent the index position of
  620. the binned spike and rows represent the number of spike trains.
  621. Examples
  622. --------
  623. >>> import elephant.conversion as conv
  624. >>> import neo as n
  625. >>> a = n.SpikeTrain([0.5, 0.7, 1.2, 3.1, 4.3, 5.5, 6.7] * pq.s, t_stop=10.0 * pq.s)
  626. >>> x = conv.BinnedSpikeTrain(a, num_bins=10, binsize=1 * pq.s, t_start=0 * pq.s)
  627. >>> print(x.to_array())
  628. [[2 1 0 1 1 1 1 0 0 0]]
  629. See also
  630. --------
  631. scipy.sparse.csr_matrix
  632. scipy.sparse.csr_matrix.toarray
  633. """
  634. if self._mat_u is not None:
  635. return self._mat_u
  636. if store_array:
  637. self._store_array()
  638. return self._mat_u
  639. # Matrix on demand
  640. else:
  641. return self._sparse_mat_u.toarray()
  642. def _store_array(self):
  643. """
  644. Stores the matrix with counted time points in memory.
  645. """
  646. if self._mat_u is None:
  647. self._mat_u = self.to_sparse_array().toarray()
  648. def remove_stored_array(self):
  649. """
  650. Removes the matrix with counted time points from memory.
  651. """
  652. if self._mat_u is not None:
  653. del self._mat_u
  654. self._mat_u = None
  655. def _convert_to_binned(self, spiketrains):
  656. """
  657. Converts neo.core.SpikeTrain objects to a sparse matrix
  658. (`scipy.sparse.csr_matrix`), which contains the binned times.
  659. Parameters
  660. ----------
  661. spiketrains : neo.SpikeTrain object or list of SpikeTrain objects
  662. The binned time array :attr:`spike_indices` is calculated from a
  663. SpikeTrain object or from a list of SpikeTrain objects.
  664. """
  665. from distutils.version import StrictVersion
  666. # column
  667. filled = []
  668. # row
  669. indices = []
  670. # data
  671. counts = []
  672. # to be downwards compatible compare numpy versions, if the used
  673. # version is smaller than v1.9 use different functions
  674. smaller_version = StrictVersion(np.__version__) < '1.9.0'
  675. for idx, elem in enumerate(spiketrains):
  676. ev = elem.view(pq.Quantity)
  677. scale = np.array(((ev - self.t_start).rescale(
  678. self.binsize.units) / self.binsize).magnitude, dtype=int)
  679. l = np.logical_and(ev >= self.t_start.rescale(self.binsize.units),
  680. ev <= self.t_stop.rescale(self.binsize.units))
  681. filled_tmp = scale[l]
  682. filled_tmp = filled_tmp[filled_tmp < self.num_bins]
  683. if smaller_version:
  684. f = np.unique(filled_tmp)
  685. c = np.bincount(f.searchsorted(filled_tmp))
  686. else:
  687. f, c = np.unique(filled_tmp, return_counts=True)
  688. filled.extend(f)
  689. counts.extend(c)
  690. indices.extend([idx] * len(f))
  691. csr_matrix = sps.csr_matrix((counts, (indices, filled)),
  692. shape=(self.matrix_rows,
  693. self.matrix_columns),
  694. dtype=int)
  695. self._sparse_mat_u = csr_matrix