tools.py 4.8 KB

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