#!/usr/bin/python
#
-# igorbinarywave provides pure Python interface between IGOR Binary
-# Wave files and Numpy arrays.
-#
# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
#
# This file is part of Hooke.
#
-# Hooke is free software: you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation, either
-# version 3 of the License, or (at your option) any later version.
+# Hooke is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
#
-# Hooke is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
+# Hooke is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+# Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with Hooke. If not, see
# <http://www.gnu.org/licenses/>.
+"""igorbinarywave provides pure Python interface between IGOR Binary
+Wave files and Numpy arrays.
+
+This is basically a stand-alone package that we bundle into Hooke for
+convenience. It is used by the mfp*d drivers, whose data is saved in
+IBW files.
+"""
+
# Based on WaveMetric's Technical Note 003, "Igor Binary Format"
# ftp://ftp.wavemetrics.net/IgorPro/Technical_Notes/TN003.zip
# From ftp://ftp.wavemetrics.net/IgorPro/Technical_Notes/TN000.txt
('%d, %d, %d, %s' % (waveDataSize, wave_info['npnts'], t.itemsize, t))
tail_data = array.array('f', b[-tail:])
data_b = buffer(buffer(tail_data) + f.read(waveDataSize-tail))
+ if version == 5:
+ shape = [n for n in wave_info['nDim'] if n > 0]
+ else:
+ shape = (wave_info['npnts'],)
data = numpy.ndarray(
- wave_info['npnts'],
+ shape=shape,
dtype=t.newbyteorder(byteOrder),
- buffer=data_b
+ buffer=data_b,
+ order='F',
)
+
+ if version == 1:
+ pass # No post-data information
+ elif version == 2:
+ # Post-data info:
+ # * 16 bytes of padding
+ # * Optional wave note data
+ pad_b = buffer(f.read(16)) # skip the padding
+ assert max(pad_b) == 0, pad_b
+ bin_info['note'] = str(f.read(bin_info['noteSize'])).strip()
+ elif version == 3:
+ # Post-data info:
+ # * 16 bytes of padding
+ # * Optional wave note data
+ # * Optional wave dependency formula
+ """Excerpted from TN003:
+
+ A wave has a dependency formula if it has been bound by a
+ statement such as "wave0 := sin(x)". In this example, the
+ dependency formula is "sin(x)". The formula is stored with
+ no trailing null byte.
+ """
+ pad_b = buffer(f.read(16)) # skip the padding
+ assert max(pad_b) == 0, pad_b
+ bin_info['note'] = str(f.read(bin_info['noteSize'])).strip()
+ bin_info['formula'] = str(f.read(bin_info['formulaSize'])).strip()
+ elif version == 5:
+ # Post-data info:
+ # * Optional wave dependency formula
+ # * Optional wave note data
+ # * Optional extended data units data
+ # * Optional extended dimension units data
+ # * Optional dimension label data
+ # * String indices used for text waves only
+ """Excerpted from TN003:
+
+ dataUnits - Present in versions 1, 2, 3, 5. The dataUnits
+ field stores the units for the data represented by the
+ wave. It is a C string terminated with a null
+ character. This field supports units of 0 to 3 bytes. In
+ version 1, 2 and 3 files, longer units can not be
+ represented. In version 5 files, longer units can be
+ stored using the optional extended data units section of
+ the file.
+
+ xUnits - Present in versions 1, 2, 3. The xUnits field
+ stores the X units for a wave. It is a C string
+ terminated with a null character. This field supports
+ units of 0 to 3 bytes. In version 1, 2 and 3 files,
+ longer units can not be represented.
+
+ dimUnits - Present in version 5 only. This field is an
+ array of 4 strings, one for each possible wave
+ dimension. Each string supports units of 0 to 3
+ bytes. Longer units can be stored using the optional
+ extended dimension units section of the file.
+ """
+ bin_info['formula'] = str(f.read(bin_info['formulaSize'])).strip()
+ bin_info['note'] = str(f.read(bin_info['noteSize'])).strip()
+ bin_info['dataEUnits'] = str(f.read(bin_info['dataEUnitsSize'])).strip()
+ bin_info['dimEUnits'] = [
+ str(f.read(size)).strip() for size in bin_info['dimEUnitsSize']]
+ bin_info['dimLabels'] = []
+ for size in bin_info['dimLabelsSize']:
+ labels = str(f.read(size)).split(chr(0)) # split null-delimited strings
+ bin_info['dimLabels'].append([L for L in labels if len(L) > 0])
+ if wave_info['type'] == 0: # text wave
+ bin_info['sIndices'] = f.read(bin_info['sIndicesSize'])
+
finally:
if not hasattr(filename, 'read'):
f.close()
options.outfile = sys.stdout
data,bin_info,wave_info = loadibw(options.infile)
- numpy.savetxt(options.outfile, data, fmt='%g', delimiter='\n')
+ numpy.savetxt(options.outfile, data, fmt='%g', delimiter='\t')
if options.verbose > 0:
import pprint
pprint.pprint(bin_info)