grouping.rst 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. *************************
  2. Grouping and linking data
  3. *************************
  4. Migrating from ChannelIndex/Unit to ChannelView/Group
  5. =====================================================
  6. While the basic hierarchical :class:`Block` - :class:`Segment` structure of Neo has remained
  7. unchanged since the inception of Neo, the structures used to cross-link objects
  8. (for example to link a signal to the spike trains derived from it) have undergone changes,
  9. in an effort to find an easily understandable and usable approach.
  10. Below we give some examples of how to migrate from :class:`ChannelIndex` and :class:`Unit`,
  11. as used in Neo 0.8, to the new classes :class:`Group` and :class:`ChannelView`
  12. introduced in Neo 0.9.
  13. Note that Neo 0.9 supports the new and old API in parallel, to facilitate migration.
  14. IO classes in Neo 0.9 can read :class:`ChannelIndex` and :class:`Unit` objects,
  15. but do not write them.
  16. :class:`ChannelIndex` and :class:`Unit` will be removed in Neo 0.10.0.
  17. Examples
  18. --------
  19. A simple example with two tetrodes. Here the :class:`ChannelIndex` was not being
  20. used for grouping, simply to associate a name with each channel.
  21. Using :class:`ChannelIndex`::
  22. import numpy as np
  23. from quantities import kHz, mV
  24. from neo import Block, Segment, ChannelIndex, AnalogSignal
  25. block = Block()
  26. segment = Segment()
  27. segment.block = block
  28. block.segments.append(segment)
  29. for i in (0, 1):
  30. signal = AnalogSignal(np.random.rand(1000, 4) * mV,
  31. sampling_rate=1 * kHz,)
  32. segment.analogsignals.append(signal)
  33. chx = ChannelIndex(name=f"Tetrode #{i + 1}",
  34. index=[0, 1, 2, 3],
  35. channel_names=["A", "B", "C", "D"])
  36. chx.analogsignals.append(signal)
  37. block.channel_indexes.append(chx)
  38. Using array annotations, we annotate the channels of the :class:`AnalogSignal` directly::
  39. import numpy as np
  40. from quantities import kHz, mV
  41. from neo import Block, Segment, AnalogSignal
  42. block = Block()
  43. segment = Segment()
  44. segment.block = block
  45. block.segments.append(segment)
  46. for i in (0, 1):
  47. signal = AnalogSignal(np.random.rand(1000, 4) * mV,
  48. sampling_rate=1 * kHz,
  49. channel_names=["A", "B", "C", "D"])
  50. segment.analogsignals.append(signal)
  51. Now a more complex example: a 1x4 silicon probe, with a neuron on channels 0,1,2 and another neuron on channels 1,2,3.
  52. We create a :class:`ChannelIndex` for each neuron to hold the :class:`Unit` object associated with this spike sorting group.
  53. Each :class:`ChannelIndex` also contains the list of channels on which that neuron spiked.
  54. ::
  55. import numpy as np
  56. from quantities import ms, mV, kHz
  57. from neo import Block, Segment, ChannelIndex, Unit, SpikeTrain, AnalogSignal
  58. block = Block(name="probe data")
  59. segment = Segment()
  60. segment.block = block
  61. block.segments.append(segment)
  62. # create 4-channel AnalogSignal with dummy data
  63. signal = AnalogSignal(np.random.rand(1000, 4) * mV,
  64. sampling_rate=10 * kHz)
  65. # create spike trains with dummy data
  66. # we will pretend the spikes have been extracted from the dummy signal
  67. spiketrains = [
  68. SpikeTrain(np.arange(5, 100) * ms, t_stop=100 * ms),
  69. SpikeTrain(np.arange(7, 100) * ms, t_stop=100 * ms)
  70. ]
  71. segment.analogsignals.append(signal)
  72. segment.spiketrains.extend(spiketrains)
  73. # assign each spiketrain to a neuron (Unit)
  74. units = []
  75. for i, spiketrain in enumerate(spiketrains):
  76. unit = Unit(name=f"Neuron #{i + 1}")
  77. unit.spiketrains.append(spiketrain)
  78. units.append(unit)
  79. # create a ChannelIndex for each unit, to show which channels the spikes come from
  80. chx0 = ChannelIndex(name="Channel Group 1", index=[0, 1, 2])
  81. chx0.units.append(units[0])
  82. chx0.analogsignals.append(signal)
  83. units[0].channel_index = chx0
  84. chx1 = ChannelIndex(name="Channel Group 2", index=[1, 2, 3])
  85. chx1.units.append(units[1])
  86. chx1.analogsignals.append(signal)
  87. units[1].channel_index = chx1
  88. block.channel_indexes.extend((chx0, chx1))
  89. Using :class:`ChannelView` and :class`Group`::
  90. import numpy as np
  91. from quantities import ms, mV, kHz
  92. from neo import Block, Segment, ChannelView, Group, SpikeTrain, AnalogSignal
  93. block = Block(name="probe data")
  94. segment = Segment()
  95. segment.block = block
  96. block.segments.append(segment)
  97. # create 4-channel AnalogSignal with dummy data
  98. signal = AnalogSignal(np.random.rand(1000, 4) * mV,
  99. sampling_rate=10 * kHz)
  100. # create spike trains with dummy data
  101. # we will pretend the spikes have been extracted from the dummy signal
  102. spiketrains = [
  103. SpikeTrain(np.arange(5, 100) * ms, t_stop=100 * ms),
  104. SpikeTrain(np.arange(7, 100) * ms, t_stop=100 * ms)
  105. ]
  106. segment.analogsignals.append(signal)
  107. segment.spiketrains.extend(spiketrains)
  108. # assign each spiketrain to a neuron (now using Group)
  109. units = []
  110. for i, spiketrain in enumerate(spiketrains):
  111. unit = Group(spiketrain, name=f"Neuron #{i + 1}")
  112. units.append(unit)
  113. # create a ChannelView of the signal for each unit, to show which channels the spikes come from
  114. # and add it to the relevant Group
  115. view0 = ChannelView(signal, index=[0, 1, 2], name="Channel Group 1")
  116. units[0].add(view0)
  117. view1 = ChannelView(signal, index=[1, 2, 3], name="Channel Group 2")
  118. units[1].add(view1)
  119. block.groups.extend(units)
  120. Now each putative neuron is represented by a :class:`Group` containing the spiktrains of that neuron
  121. and a view of the signal selecting only those channels from which the spikes were obtained.