core.rst 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. ********
  2. Neo core
  3. ********
  4. .. currentmodule:: neo.core
  5. This figure shows the main data types in Neo:
  6. .. image:: images/base_schematic.png
  7. :height: 500 px
  8. :alt: Illustration of the main Neo data types
  9. :align: center
  10. Neo objects fall into three categories: data objects, container objects and grouping objects.
  11. Data objects
  12. ------------
  13. These objects directly represent data as arrays of numerical values with
  14. associated metadata (units, sampling frequency, etc.).
  15. * :py:class:`AnalogSignal`: A regular sampling of a single- or multi-channel continuous analog signal.
  16. * :py:class:`IrregularlySampledSignal`: A non-regular sampling of a single- or multi-channel continuous analog signal.
  17. * :py:class:`SpikeTrain`: A set of action potentials (spikes) emitted by the same unit in a period of time (with optional waveforms).
  18. * :py:class:`Event`: An array of time points representing one or more events in the data.
  19. * :py:class:`Epoch`: An array of time intervals representing one or more periods of time in the data.
  20. Container objects
  21. -----------------
  22. There is a simple hierarchy of containers:
  23. * :py:class:`Segment`: A container for heterogeneous discrete or continous data sharing a common
  24. clock (time basis) but not necessarily the same sampling rate, start time or end time.
  25. A :py:class:`Segment` can be considered as equivalent to a "trial", "episode", "run",
  26. "recording", etc., depending on the experimental context.
  27. May contain any of the data objects.
  28. * :py:class:`Block`: The top-level container gathering all of the data, discrete and continuous,
  29. for a given recording session.
  30. Contains :class:`Segment`, :class:`Unit` and :class:`ChannelIndex` objects.
  31. Grouping objects
  32. ----------------
  33. These objects express the relationships between data items, such as which signals
  34. were recorded on which electrodes, which spike trains were obtained from which
  35. membrane potential signals, etc. They contain references to data objects that
  36. cut across the simple container hierarchy.
  37. * :py:class:`ChannelIndex`: A set of indices into :py:class:`AnalogSignal` objects,
  38. representing logical and/or physical recording channels. This has two uses:
  39. 1. for linking :py:class:`AnalogSignal` objects recorded from the same (multi)electrode
  40. across several :py:class:`Segment`\s.
  41. 2. for spike sorting of extracellular signals, where spikes may be recorded on more than one
  42. recording channel, and the :py:class:`ChannelIndex` can be used to associate each
  43. :py:class:`Unit` with the group of recording channels from which it was obtained.
  44. * :py:class:`Unit`: links the :class:`SpikeTrain` objects within a :class:`Block`,
  45. possibly across multiple Segments, that were emitted by the same cell.
  46. A :class:`Unit` is linked to the :class:`ChannelIndex` object from which the spikes were detected.
  47. NumPy compatibility
  48. ===================
  49. Neo data objects inherit from :py:class:`Quantity`, which in turn inherits from NumPy
  50. :py:class:`ndarray`. This means that a Neo :py:class:`AnalogSignal` is also a :py:class:`Quantity`
  51. and an array, giving you access to all of the methods available for those objects.
  52. For example, you can pass a :py:class:`SpikeTrain` directly to the :py:func:`numpy.histogram`
  53. function, or an :py:class:`AnalogSignal` directly to the :py:func:`numpy.std` function.
  54. Relationships between objects
  55. =============================
  56. Container objects like :py:class:`Block` or :py:class:`Segment` are gateways to
  57. access other objects. For example, a :class:`Block` can access a :class:`Segment`
  58. with::
  59. >>> bl = Block()
  60. >>> bl.segments
  61. # gives a list of segments
  62. A :class:`Segment` can access the :class:`AnalogSignal` objects that it contains with::
  63. >>> seg = Segment()
  64. >>> seg.analogsignals
  65. # gives a list of AnalogSignals
  66. In the :ref:`neo_diagram` below, these *one to many* relationships are represented by cyan arrows.
  67. In general, an object can access its children with an attribute *childname+s* in lower case, e.g.
  68. * :attr:`Block.segments`
  69. * :attr:`Segments.analogsignals`
  70. * :attr:`Segments.spiketrains`
  71. * :attr:`Block.channel_indexes`
  72. These relationships are bi-directional, i.e. a child object can access its parent:
  73. * :attr:`Segment.block`
  74. * :attr:`AnalogSignal.segment`
  75. * :attr:`SpikeTrain.segment`
  76. * :attr:`ChannelIndex.block`
  77. Here is an example showing these relationships in use::
  78. from neo.io import AxonIO
  79. import urllib
  80. url = "https://portal.g-node.org/neo/axon/File_axon_3.abf"
  81. filename = './test.abf'
  82. urllib.urlretrieve(url, filename)
  83. r = AxonIO(filename=filename)
  84. bl = r.read() # read the entire file > a Block
  85. print(bl)
  86. print(bl.segments) # child access
  87. for seg in bl.segments:
  88. print(seg)
  89. print(seg.block) # parent access
  90. In some cases, a one-to-many relationship is sufficient. Here is a simple example with tetrodes, in which each tetrode has its own group.::
  91. from neo import Block, ChannelIndex
  92. bl = Block()
  93. # the four tetrodes
  94. for i in range(4):
  95. chx = ChannelIndex(name='Tetrode %d' % i,
  96. index=[0, 1, 2, 3])
  97. bl.channelindexes.append(chx)
  98. # now we load the data and associate it with the created channels
  99. # ...
  100. Now consider a more complex example: a 1x4 silicon probe, with a neuron on channels 0,1,2 and another neuron on channels 1,2,3. We create a group for each neuron to hold the :class:`Unit` object associated with this spike sorting group. Each group also contains the channels on which that neuron spiked. The relationship is many-to-many because channels 1 and 2 occur in multiple groups.::
  101. bl = Block(name='probe data')
  102. # one group for each neuron
  103. chx0 = ChannelIndex(name='Group 0',
  104. index=[0, 1, 2])
  105. bl.channelindexes.append(chx0)
  106. chx1 = ChannelIndex(name='Group 1',
  107. index=[1, 2, 3])
  108. bl.channelindexes.append(chx1)
  109. # now we add the spiketrain from Unit 0 to chx0
  110. # and add the spiketrain from Unit 1 to chx1
  111. # ...
  112. Note that because neurons are sorted from groups of channels in this situation, it is natural that the :py:class:`ChannelIndex` contains a reference to the :py:class:`Unit` object.
  113. That unit then contains references to its spiketrains. Also note that recording channels can be
  114. identified by names/labels as well as, or instead of, integer indices.
  115. See :doc:`usecases` for more examples of how the different objects may be used.
  116. .. _neo_diagram:
  117. Neo diagram
  118. ===========
  119. Object:
  120. * With a star = inherits from :class:`Quantity`
  121. Attributes:
  122. * In red = required
  123. * In white = recommended
  124. Relationship:
  125. * In cyan = one to many
  126. * In yellow = properties (deduced from other relationships)
  127. .. image:: images/simple_generated_diagram.png
  128. :width: 750 px
  129. :download:`Click here for a better quality SVG diagram <./images/simple_generated_diagram.svg>`
  130. For more details, see the :doc:`api_reference`.
  131. Initialization
  132. ==============
  133. Neo objects are initialized with "required", "recommended", and "additional" arguments.
  134. - Required arguments MUST be provided at the time of initialization. They are used in the construction of the object.
  135. - Recommended arguments may be provided at the time of initialization. They are accessible as Python attributes. They can also be set or modified after initialization.
  136. - Additional arguments are defined by the user and are not part of the Neo object model. A primary goal of the Neo project is extensibility. These additional arguments are entries in an attribute of the object: a Python dict called :py:attr:`annotations`.
  137. Example: SpikeTrain
  138. -------------------
  139. :py:class:`SpikeTrain` is a :py:class:`Quantity`, which is a NumPy array containing values with physical dimensions. The spike times are a required attribute, because the dimensionality of the spike times determines the way in which the :py:class:`Quantity` is constructed.
  140. Here is how you initialize a :py:class:`SpikeTrain` with required arguments::
  141. >>> import neo
  142. >>> st = neo.SpikeTrain([3, 4, 5], units='sec', t_stop=10.0)
  143. >>> print(st)
  144. [ 3. 4. 5.] s
  145. You will see the spike times printed in a nice format including the units.
  146. Because `st` "is a" :py:class:`Quantity` array with units of seconds, it absolutely must have this information at the time of initialization. You can specify the spike times with a keyword argument too::
  147. >>> st = neo.SpikeTrain(times=[3, 4, 5], units='sec', t_stop=10.0)
  148. The spike times could also be in a NumPy array.
  149. If it is not specified, :attr:`t_start` is assumed to be zero, but another value can easily be specified::
  150. >>> st = neo.SpikeTrain(times=[3, 4, 5], units='sec', t_start=1.0, t_stop=10.0)
  151. >>> st.t_start
  152. array(1.0) * s
  153. Recommended attributes must be specified as keyword arguments, not positional arguments.
  154. Finally, let's consider "additional arguments". These are the ones you define for your experiment::
  155. >>> st = neo.SpikeTrain(times=[3, 4, 5], units='sec', t_stop=10.0, rat_name='Fred')
  156. >>> print(st.annotations)
  157. {'rat_name': 'Fred'}
  158. Because ``rat_name`` is not part of the Neo object model, it is placed in the dict :py:attr:`annotations`. This dict can be modified as necessary by your code.
  159. Annotations
  160. -----------
  161. As well as adding annotations as "additional" arguments when an object is
  162. constructed, objects may be annotated using the :meth:`annotate` method
  163. possessed by all Neo core objects, e.g.::
  164. >>> seg = Segment()
  165. >>> seg.annotate(stimulus="step pulse", amplitude=10*nA)
  166. >>> print(seg.annotations)
  167. {'amplitude': array(10.0) * nA, 'stimulus': 'step pulse'}
  168. Since annotations may be written to a file or database, there are some
  169. limitations on the data types of annotations: they must be "simple" types or
  170. containers (lists, dicts, NumPy arrays) of simple types, where the simple types
  171. are ``integer``, ``float``, ``complex``, ``Quantity``, ``string``, ``date``, ``time`` and
  172. ``datetime``.
  173. See :ref:`specific_annotations`