core.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. ********
  2. Neo core
  3. ********
  4. .. currentmodule:: neo.core
  5. This figure shows the main data types in Neo, with the exception of the newly added ImageSequence and RegionOfInterest classes:
  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. * :py:class:`ImageSequence`: A three dimensional array representing a sequence of images.
  21. Container objects
  22. -----------------
  23. There is a simple hierarchy of containers:
  24. * :py:class:`Segment`: A container for heterogeneous discrete or continous data sharing a common
  25. clock (time basis) but not necessarily the same sampling rate, start time or end time.
  26. A :py:class:`Segment` can be considered as equivalent to a "trial", "episode", "run",
  27. "recording", etc., depending on the experimental context.
  28. May contain any of the data objects.
  29. * :py:class:`Block`: The top-level container gathering all of the data, discrete and continuous,
  30. for a given recording session.
  31. Contains :class:`Segment` and :class:`Group` objects.
  32. Grouping/linking objects
  33. ------------------------
  34. These objects express the relationships between data items, such as which signals
  35. were recorded on which electrodes, which spike trains were obtained from which
  36. membrane potential signals, etc. They contain references to data objects that
  37. cut across the simple container hierarchy.
  38. * :py:class:`ChannelView`: A set of indices into :py:class:`AnalogSignal` objects,
  39. representing logical and/or physical recording channels.
  40. For spike sorting of extracellular signals, where spikes may be recorded on more than one
  41. recording channel, the :py:class:`ChannelView` can be used to reference the group of recording channels
  42. from which the spikes were obtained.
  43. * :py:class:`Group`: Can contain any of the data objects, views, or other groups,
  44. outside the hierarchy of the segment and block containers.
  45. A common use is to link the :class:`SpikeTrain` objects within a :class:`Block`,
  46. possibly across multiple Segments, that were emitted by the same neuron.
  47. * :py:class:`CircularRegionOfInterest`, :py:class:`RectangularRegionOfInterest` and :py:class:`PolygonRegionOfInterest`
  48. are three subclasses that link :class:`ImageSequence` objects to signals (:class:`AnalogSignal` objects)
  49. extracted from them.
  50. For more details, see :doc:`grouping`.
  51. NumPy compatibility
  52. ===================
  53. Neo data objects inherit from :py:class:`Quantity`, which in turn inherits from NumPy
  54. :py:class:`ndarray`. This means that a Neo :py:class:`AnalogSignal` is also a :py:class:`Quantity`
  55. and an array, giving you access to all of the methods available for those objects.
  56. For example, you can pass a :py:class:`SpikeTrain` directly to the :py:func:`numpy.histogram`
  57. function, or an :py:class:`AnalogSignal` directly to the :py:func:`numpy.std` function.
  58. If you want to get a numpy.ndarray you use magnitude and rescale from quantities::
  59. >>> np_sig = neo_analogsignal.rescale('mV').magnitude
  60. >>> np_times = neo_analogsignal.times.rescale('s').magnitude
  61. Relationships between objects
  62. =============================
  63. Container objects like :py:class:`Block` or :py:class:`Segment` are gateways to
  64. access other objects. For example, a :class:`Block` can access a :class:`Segment`
  65. with::
  66. >>> bl = Block()
  67. >>> bl.segments
  68. # gives a list of segments
  69. A :class:`Segment` can access the :class:`AnalogSignal` objects that it contains with::
  70. >>> seg = Segment()
  71. >>> seg.analogsignals
  72. # gives a list of AnalogSignals
  73. In the :ref:`neo_diagram` below, these *one to many* relationships are represented by cyan arrows.
  74. In general, an object can access its children with an attribute *childname+s* in lower case, e.g.
  75. * :attr:`Block.segments`
  76. * :attr:`Segments.analogsignals`
  77. * :attr:`Segments.spiketrains`
  78. * :attr:`Block.groups`
  79. These relationships are bi-directional, i.e. a child object can access its parent:
  80. * :attr:`Segment.block`
  81. * :attr:`AnalogSignal.segment`
  82. * :attr:`SpikeTrain.segment`
  83. * :attr:`Group.block`
  84. Here is an example showing these relationships in use::
  85. from neo.io import AxonIO
  86. import urllib.request
  87. url = "https://web.gin.g-node.org/NeuralEnsemble/ephy_testing_data/raw/master/axon/File_axon_3.abf"
  88. filename = './test.abf'
  89. urllib.request.urlretrieve(url, filename)
  90. r = AxonIO(filename=filename)
  91. blocks = r.read() # read the entire file > a list of Blocks
  92. bl = blocks[0]
  93. print(bl)
  94. print(bl.segments) # child access
  95. for seg in bl.segments:
  96. print(seg)
  97. print(seg.block) # parent access
  98. 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.::
  99. from neo import Block, Group
  100. bl = Block()
  101. # the four tetrodes
  102. for i in range(4):
  103. group = Group(name='Tetrode %d' % i)
  104. bl.groups.append(group)
  105. # now we load the data and associate it with the created channels
  106. # ...
  107. 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.
  108. We create a group for each neuron to hold the spiketrains for each spike sorting group together with
  109. the channels on which that neuron spiked::
  110. bl = Block(name='probe data')
  111. # one group for each neuron
  112. view0 = ChannelView(recorded_signals, index=[0, 1, 2])
  113. unit0 = Group(view0, name='Group 0')
  114. bl.groups.append(unit0)
  115. view1 = ChannelView(recorded_signals, index=[1, 2, 3])
  116. unit1 = Group(view1, name='Group 1')
  117. bl.groups.append(unit1)
  118. # now we add the spiketrains from Unit 0 to unit0
  119. # and add the spiketrains from Unit 1 to unit1
  120. # ...
  121. Now each putative neuron is represented by a :class:`Group` containing the spiktrains of that neuron
  122. and a view of the signal selecting only those channels from which the spikes were obtained.
  123. See :doc:`usecases` for more examples of how the different objects may be used.
  124. .. _neo_diagram:
  125. Neo diagram
  126. ===========
  127. Object:
  128. * With a star = inherits from :class:`Quantity`
  129. Attributes:
  130. * In red = required
  131. * In white = recommended
  132. Relationship:
  133. * In cyan = one to many
  134. * In yellow = properties (deduced from other relationships)
  135. .. image:: images/simple_generated_diagram.png
  136. :width: 750 px
  137. :download:`Click here for a better quality SVG diagram <./images/simple_generated_diagram.svg>`
  138. .. note:: This figure has not yet been updated to include :class:`ImageSequence` and :class:`RegionOfInterest`.
  139. For more details, see the :doc:`api_reference`.
  140. Initialization
  141. ==============
  142. Neo objects are initialized with "required", "recommended", and "additional" arguments.
  143. - Required arguments MUST be provided at the time of initialization. They are used in the construction of the object.
  144. - 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.
  145. - 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`.
  146. Note : Neo annotations are not the same as the *__annotations__* attribute introduced in Python 3.6.
  147. Example: SpikeTrain
  148. -------------------
  149. :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.
  150. Here is how you initialize a :py:class:`SpikeTrain` with required arguments::
  151. >>> import neo
  152. >>> st = neo.SpikeTrain([3, 4, 5], units='sec', t_stop=10.0)
  153. >>> print(st)
  154. [ 3. 4. 5.] s
  155. You will see the spike times printed in a nice format including the units.
  156. 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::
  157. >>> st = neo.SpikeTrain(times=[3, 4, 5], units='sec', t_stop=10.0)
  158. The spike times could also be in a NumPy array.
  159. If it is not specified, :attr:`t_start` is assumed to be zero, but another value can easily be specified::
  160. >>> st = neo.SpikeTrain(times=[3, 4, 5], units='sec', t_start=1.0, t_stop=10.0)
  161. >>> st.t_start
  162. array(1.0) * s
  163. Recommended attributes must be specified as keyword arguments, not positional arguments.
  164. Finally, let's consider "additional arguments". These are the ones you define for your experiment::
  165. >>> st = neo.SpikeTrain(times=[3, 4, 5], units='sec', t_stop=10.0, rat_name='Fred')
  166. >>> print(st.annotations)
  167. {'rat_name': 'Fred'}
  168. 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.
  169. Annotations
  170. -----------
  171. As well as adding annotations as "additional" arguments when an object is
  172. constructed, objects may be annotated using the :meth:`annotate` method
  173. possessed by all Neo core objects, e.g.::
  174. >>> seg = Segment()
  175. >>> seg.annotate(stimulus="step pulse", amplitude=10*nA)
  176. >>> print(seg.annotations)
  177. {'amplitude': array(10.0) * nA, 'stimulus': 'step pulse'}
  178. Since annotations may be written to a file or database, there are some
  179. limitations on the data types of annotations: they must be "simple" types or
  180. containers (lists, dicts, tuples, NumPy arrays) of simple types, where the simple types
  181. are ``integer``, ``float``, ``complex``, ``Quantity``, ``string``, ``date``, ``time`` and
  182. ``datetime``.
  183. Array Annotations
  184. -----------------
  185. Next to "regular" annotations there is also a way to annotate arrays of values
  186. in order to create annotations with one value per data point. Using this feature,
  187. called Array Annotations, the consistency of those annotations with the actual data
  188. is ensured.
  189. Apart from adding those on object construction, Array Annotations can also be added
  190. using the :meth:`array_annotate` method provided by all Neo data objects, e.g.::
  191. >>> sptr = SpikeTrain(times=[1, 2, 3]*pq.s, t_stop=3*pq.s)
  192. >>> sptr.array_annotate(index=[0, 1, 2], relevant=[True, False, True])
  193. >>> print(sptr.array_annotations)
  194. {'index': array([0, 1, 2]), 'relevant': array([ True, False, True])}
  195. Since Array Annotations may be written to a file or database, there are some
  196. limitations on the data types of arrays: they must be 1-dimensional (i.e. not nested)
  197. and contain the same types as annotations:
  198. ``integer``, ``float``, ``complex``, ``Quantity``, ``string``, ``date``, ``time`` and ``datetime``.