I have a struct array created by matlab and stored in v7.3 format mat file:
struArray = struct('name', {'one', 'two', 'three'},
'id', {1,2,3},
'data', {[1:10], [3:9], [0]})
save('test.mat', 'struArray', '-v7.3')
Now I want to read this file via python using h5py:
data = h5py.File('test.mat')
struArray = data['/struArray']
I have no idea how to get the struct data one by one from struArray
:
for index in range(<the size of struArray>):
elem = <the index th struct in struArray>
name = <the name of elem>
id = <the id of elem>
data = <the data of elem>
How to Open an MAT File. MAT files that are Microsoft Access Shortcut files can be created by dragging a table out of Access and to the desktop or into another folder. Microsoft Access needs to be installed in order to use them. MATLAB from MathWorks can open MAT files that are used by that program.
In MATLAB, the save function has the option of saving as v7. 3, which uses HDF5 to allow the storage of variables larger than 2 GB. However, saving and loading take much longer with this option than with v7 (the default).
The h5py package is a Pythonic interface to the HDF5 binary data format. HDF5 lets you store huge amounts of numerical data, and easily manipulate that data from NumPy. For example, you can slice into multi-terabyte datasets stored on disk, as if they were real NumPy arrays.
Version 7.3 MAT-files use an HDF5-based format that stores data in compressed chunks.
Matlab 7.3 file format is not extremely easy to work with h5py. It relies on HDF5 reference, cf. h5py documentation on references.
>>> import h5py
>>> f = h5py.File('test.mat')
>>> list(f.keys())
['#refs#', 'struArray']
>>> struArray = f['struArray']
>>> struArray['name'][0, 0] # this is the HDF5 reference
<HDF5 object reference>
>>> f[struArray['name'][0, 0]].value # this is the actual data
array([[111],
[110],
[101]], dtype=uint16)
To read struArray(i).id
:
>>> f[struArray['id'][0, 0]][0, 0]
1.0
>>> f[struArray['id'][1, 0]][0, 0]
2.0
>>> f[struArray['id'][2, 0]][0, 0]
3.0
Notice that Matlab stores a number as an array of size (1, 1), hence the final [0, 0]
to get the number.
To read struArray(i).data
:
>>> f[struArray['data'][0, 0]].value
array([[ 1.],
[ 2.],
[ 3.],
[ 4.],
[ 5.],
[ 6.],
[ 7.],
[ 8.],
[ 9.],
[ 10.]])
To read struArray(i).name
, it is necessary to convert the array of integers to string:
>>> f[struArray['name'][0, 0]].value.tobytes()[::2].decode()
'one'
>>> f[struArray['name'][1, 0]].value.tobytes()[::2].decode()
'two'
>>> f[struArray['name'][2, 0]].value.tobytes()[::2].decode()
'three'
visit
or visititems
is quick way of seeing the overall structure of a h5py
file:
fs['struArray'].visititems(lambda n,o:print(n, o))
When I run this on a file produced by Octave save -hdf5
I get:
type <HDF5 dataset "type": shape (), type "|S7">
value <HDF5 group "/struArray/value" (3 members)>
value/data <HDF5 group "/struArray/value/data" (2 members)>
value/data/type <HDF5 dataset "type": shape (), type "|S5">
value/data/value <HDF5 group "/struArray/value/data/value" (4 members)>
value/data/value/_0 <HDF5 group "/struArray/value/data/value/_0" (2 members)>
value/data/value/_0/type <HDF5 dataset "type": shape (), type "|S7">
value/data/value/_0/value <HDF5 dataset "value": shape (10, 1), type "<f8">
value/data/value/_1 <HDF5 group "/struArray/value/data/value/_1" (2 members)>
...
value/data/value/dims <HDF5 dataset "dims": shape (2,), type "<i4">
value/id <HDF5 group "/struArray/value/id" (2 members)>
value/id/type <HDF5 dataset "type": shape (), type "|S5">
value/id/value <HDF5 group "/struArray/value/id/value" (4 members)>
value/id/value/_0 <HDF5 group "/struArray/value/id/value/_0" (2 members)>
...
value/id/value/_2/value <HDF5 dataset "value": shape (), type "<f8">
value/id/value/dims <HDF5 dataset "dims": shape (2,), type "<i4">
value/name <HDF5 group "/struArray/value/name" (2 members)>
...
value/name/value/dims <HDF5 dataset "dims": shape (2,), type "<i4">
This may not be the same what MATLAB 7.3 produces, but it gives an idea of a structure's complexity.
A more refined callback can display values, and could be the starting point for recreating a Python object (dictionary, lists, etc).
def callback(name, obj):
if name.endswith('type'):
print('type:', obj.value)
elif name.endswith('value'):
if type(obj).__name__=='Dataset':
print(obj.value.T) # http://stackoverflow.com/questions/21624653
elif name.endswith('dims'):
print('dims:', obj.value)
else:
print('name:', name)
fs.visititems(callback)
produces:
name: struArray
type: b'struct'
name: struArray/value/data
type: b'cell'
name: struArray/value/data/value/_0
type: b'matrix'
[[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]]
name: struArray/value/data/value/_1
type: b'matrix'
[[ 3. 4. 5. 6. 7. 8. 9.]]
name: struArray/value/data/value/_2
type: b'scalar'
0.0
dims: [3 1]
name: struArray/value/id
type: b'cell'
name: struArray/value/id/value/_0
type: b'scalar'
1.0
...
dims: [3 1]
name: struArray/value/name
type: b'cell'
name: struArray/value/name/value/_0
type: b'sq_string'
[[111 110 101]]
...
dims: [3 1]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With