1
0

igorproio.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. # -*- coding: utf-8 -*-
  2. """
  3. Class for reading data created by IGOR Pro (WaveMetrics, Inc., Portland, OR, USA)
  4. Depends on: igor (https://pypi.python.org/pypi/igor/)
  5. Supported: Read
  6. Author: Andrew Davison
  7. """
  8. from __future__ import absolute_import
  9. from warnings import warn
  10. import numpy as np
  11. import quantities as pq
  12. from neo.io.baseio import BaseIO
  13. from neo.core import Block, Segment, AnalogSignal
  14. try:
  15. import igor.binarywave as bw
  16. HAVE_IGOR = True
  17. except ImportError:
  18. HAVE_IGOR = False
  19. class IgorIO(BaseIO):
  20. """
  21. Class for reading Igor Binary Waves (.ibw) written by WaveMetrics’ IGOR Pro software.
  22. Support for Packed Experiment (.pxp) files is planned.
  23. It requires the `igor` Python package by W. Trevor King.
  24. Usage:
  25. >>> from neo import io
  26. >>> r = io.IgorIO(filename='...ibw')
  27. """
  28. is_readable = True # This class can only read data
  29. is_writable = False # write is not supported
  30. supported_objects = [Block, Segment, AnalogSignal]
  31. readable_objects = [Block, Segment , AnalogSignal]
  32. writeable_objects = []
  33. has_header = False
  34. is_streameable = False
  35. name = 'igorpro'
  36. extensions = ['ibw'] #, 'pxp']
  37. mode = 'file'
  38. def __init__(self, filename=None, parse_notes=None) :
  39. """
  40. Arguments:
  41. filename: the filename
  42. parse_notes: (optional) A function which will parse the 'notes'
  43. field in the file header and return a dictionary which will be
  44. added to the object annotations.
  45. """
  46. BaseIO.__init__(self)
  47. self.filename = filename
  48. self.parse_notes = parse_notes
  49. def read_block(self, lazy=False, cascade=True):
  50. block = Block(file_origin=self.filename)
  51. if cascade:
  52. block.segments.append(self.read_segment(lazy=lazy, cascade=cascade))
  53. block.segments[-1].block = block
  54. return block
  55. def read_segment(self, lazy=False, cascade=True):
  56. segment = Segment(file_origin=self.filename)
  57. if cascade:
  58. segment.analogsignals.append(self.read_analogsignal(lazy=lazy, cascade=cascade))
  59. segment.analogsignals[-1].segment = segment
  60. return segment
  61. def read_analogsignal(self, lazy=False, cascade=True):
  62. if not HAVE_IGOR:
  63. raise Exception("igor package not installed. Try `pip install igor`")
  64. data = bw.load(self.filename)
  65. version = data['version']
  66. if version > 3:
  67. raise IOError("Igor binary wave file format version {0} is not supported.".format(version))
  68. content = data['wave']
  69. if "padding" in content:
  70. assert content['padding'].size == 0, "Cannot handle non-empty padding"
  71. if lazy:
  72. # not really lazy, since the `igor` module loads the data anyway
  73. signal = np.array((), dtype=content['wData'].dtype)
  74. else:
  75. signal = content['wData']
  76. note = content['note']
  77. header = content['wave_header']
  78. name = header['bname']
  79. assert header['botFullScale'] == 0
  80. assert header['topFullScale'] == 0
  81. units = "".join(header['dataUnits'])
  82. time_units = "".join(header['xUnits']) or "s"
  83. t_start = pq.Quantity(header['hsB'], time_units)
  84. sampling_period = pq.Quantity(header['hsA'], time_units)
  85. if self.parse_notes:
  86. try:
  87. annotations = self.parse_notes(note)
  88. except ValueError:
  89. warn("Couldn't parse notes field.")
  90. annotations = {'note': note}
  91. else:
  92. annotations = {'note': note}
  93. signal = AnalogSignal(signal, units=units, copy=False, t_start=t_start,
  94. sampling_period=sampling_period, name=name,
  95. file_origin=self.filename, **annotations)
  96. if lazy:
  97. signal.lazy_shape = content['wData'].shape
  98. return signal
  99. # the following function is to handle the annotations in the
  100. # Igor data files from the Blue Brain Project NMC Portal
  101. def key_value_string_parser(itemsep=";", kvsep=":"):
  102. """
  103. Parses a string into a dict.
  104. Arguments:
  105. itemsep - character which separates items
  106. kvsep - character which separates the key and value within an item
  107. Returns:
  108. a function which takes the string to be parsed as the sole argument and returns a dict.
  109. Example:
  110. >>> parse = key_value_string_parser(itemsep=";", kvsep=":")
  111. >>> parse("a:2;b:3")
  112. {'a': 2, 'b': 3}
  113. """
  114. def parser(s):
  115. items = s.split(itemsep)
  116. return dict(item.split(kvsep, 1) for item in items if item)
  117. return parser