tools.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. """
  2. Tools for IO coder:
  3. * Creating RecordingChannel and making links with AnalogSignals and
  4. SPikeTrains
  5. """
  6. try:
  7. from collections.abc import MutableSequence
  8. except ImportError:
  9. from collections import MutableSequence
  10. import numpy as np
  11. from neo.core import (AnalogSignal, Block,
  12. Epoch, Event,
  13. IrregularlySampledSignal,
  14. ChannelIndex, Group, ChannelView,
  15. Segment, SpikeTrain, Unit)
  16. # def finalize_block(block):
  17. # populate_RecordingChannel(block)
  18. # block.create_many_to_one_relationship()
  19. # Special case this tricky many-to-many relationship
  20. # we still need links from recordingchannel to analogsignal
  21. # for chx in block.channel_indexes:
  22. # for rc in chx.recordingchannels:
  23. # rc.create_many_to_one_relationship()
  24. # def populate_RecordingChannel(bl, remove_from_annotation=True):
  25. # """
  26. # When a Block is
  27. # Block>Segment>AnalogSIgnal
  28. # this function auto create all RecordingChannel following these rules:
  29. # * when 'channel_index ' is in AnalogSIgnal the corresponding
  30. # RecordingChannel is created.
  31. # * 'channel_index ' is then set to None if remove_from_annotation
  32. # * only one ChannelIndex is created
  33. #
  34. # It is a utility at the end of creating a Block for IO.
  35. #
  36. # Usage:
  37. # >>> populate_RecordingChannel(a_block)
  38. # """
  39. # recordingchannels = {}
  40. # for seg in bl.segments:
  41. # for anasig in seg.analogsignals:
  42. # if getattr(anasig, 'channel_index', None) is not None:
  43. # ind = int(anasig.channel_index)
  44. # if ind not in recordingchannels:
  45. # recordingchannels[ind] = RecordingChannel(index=ind)
  46. # if 'channel_name' in anasig.annotations:
  47. # channel_name = anasig.annotations['channel_name']
  48. # recordingchannels[ind].name = channel_name
  49. # if remove_from_annotation:
  50. # anasig.annotations.pop('channel_name')
  51. # recordingchannels[ind].analogsignals.append(anasig)
  52. # anasig.recordingchannel = recordingchannels[ind]
  53. # if remove_from_annotation:
  54. # anasig.channel_index = None
  55. #
  56. # indexes = np.sort(list(recordingchannels.keys())).astype('i')
  57. # names = np.array([recordingchannels[idx].name for idx in indexes],
  58. # dtype='S')
  59. # chx = ChannelIndex(name='all channels',
  60. # index=indexes,
  61. # channel_names=names)
  62. # bl.channel_indexes.append(chx)
  63. # for ind in indexes:
  64. # # many to many relationship
  65. # chx.recordingchannels.append(recordingchannels[ind])
  66. # recordingchannels[ind].channel_indexes.append(chx)
  67. # def iteritems(D):
  68. # try:
  69. # return D.iteritems() # Python 2
  70. # except AttributeError:
  71. # return D.items() # Python 3
  72. class LazyList(MutableSequence):
  73. """ An enhanced list that can load its members on demand. Behaves exactly
  74. like a regular list for members that are Neo objects. Each item should
  75. contain the information that ``load_lazy_cascade`` needs to load the
  76. respective object.
  77. """
  78. _container_objects = {
  79. Block, Segment, ChannelIndex, Unit, Group}
  80. _neo_objects = _container_objects.union(
  81. [AnalogSignal, Epoch, Event, ChannelView,
  82. IrregularlySampledSignal, SpikeTrain])
  83. def __init__(self, io, lazy, items=None):
  84. """
  85. :param io: IO instance that can load items.
  86. :param lazy: Lazy parameter with which the container object
  87. using the list was loaded.
  88. :param items: Optional, initial list of items.
  89. """
  90. if items is None:
  91. self._data = []
  92. else:
  93. self._data = items
  94. self._lazy = lazy
  95. self._io = io
  96. def __getitem__(self, index):
  97. item = self._data.__getitem__(index)
  98. if isinstance(index, slice):
  99. return LazyList(self._io, item)
  100. if type(item) in self._neo_objects:
  101. return item
  102. loaded = self._io.load_lazy_cascade(item, self._lazy)
  103. self._data[index] = loaded
  104. return loaded
  105. def __delitem__(self, index):
  106. self._data.__delitem__(index)
  107. def __len__(self):
  108. return self._data.__len__()
  109. def __setitem__(self, index, value):
  110. self._data.__setitem__(index, value)
  111. def insert(self, index, value):
  112. self._data.insert(index, value)
  113. def append(self, value):
  114. self._data.append(value)
  115. def reverse(self):
  116. self._data.reverse()
  117. def extend(self, values):
  118. self._data.extend(values)
  119. def remove(self, value):
  120. self._data.remove(value)
  121. def __str__(self):
  122. return '<' + self.__class__.__name__ + '>' + self._data.__str__()
  123. def __repr__(self):
  124. return '<' + self.__class__.__name__ + '>' + self._data.__repr__()