5

A simple question, but one I can't seem to be able to wrap my head around. I'm using the scipy.io library to save Python dictionaries as a Matlab structs. Now, the documentation of the scipy.io library shows us how to do this for a single Python Dictionary to a single Matlab Struct:

>>> a_dict = {'field1': 0.5, 'field2': 'a string'}
>>> sio.savemat('saved_struct.mat', {'a_dict': a_dict})

This sounds fair enough, and works:

enter image description here

However, I now want to do the same for multiple Python Dictionaries. I want them to be translated to a Matlab struct in which the column names are equal to the keys of all the dictionaries (which are obviously all the same keys names) and I want each row to represent the values for those keys for one of the Dictionaries. If I see this correctly, this is called a 1 x K struct with 10 fields, with K being the amount of rows (Python Dictionaries) I want to map. fields An example shown below:

enter image description here

Although I myself am totally unaware of correct Matlab terminology, a good soul in the comments told me this is supposed to be called a structure array. I have tried simply creating a numpy array of Python dictionaries, putting that in the a_dict key value pair of the code example above and saving that, but with no succes. Doing that results in a list of all different structs, instead of the one big struct with the rows representing the values for every individual struct.

As such, I am still in search of an appropriate solution for this problem. If you need any additional details, feel free to ask in the comments. Thanks for helping!

1
  • In other SO I've recommended (and demonstrated) creating the desired structure in MATLAB/Octave, and then look at what loadmat produced. Or just a round trip within python can be instructive - a savemat followed by a loadmat. Commented May 1, 2020 at 15:27

2 Answers 2

4

Here's a solution:

In Python:

>>> a_dict = {'field1': 0.5, 'field2': 'a string'}
>>> b_dict = {'field1': 1, 'field2': 'another string'}
>>> sio.savemat('saved_struct.mat', {'dict_array':[a_dict,b_dict]})

In MATLAB:

s = load('saved_struct.mat');
struct_array = [s.dict_array{:}];

You will end up with a structure array in MATLAB as desired.

struct_array = 

  1×2 struct array with fields:

    field1
    field2
Sign up to request clarification or add additional context in comments.

2 Comments

So s.dict_array is a cell, and the [...{:}] converts it to a struct.
Is there any way to have the [s.dict_array{:}] completed from within python so the matlab script only needs the s = load('saved_struct.mat'); ?
1

@UnbearableLightness has the simplest solution, but to clarify the structured array suggestion, I'll give an example.

Define a structured array:

In [192]: arr = np.array([(0.5,'one'),(0.6,'two'),(0.8,'three')], dtype=[('field1',float),('field2','U10')])                                                                                        

and a list of dictionaries with the same fields and data:

In [194]: dicts = [{'field1':0.5, 'field2':'one'},{'field1':0.6, 'field2':'two'},{'field1':0.8,'field2':'three'}]

In [195]: arr                                                                                          
Out[195]: 
array([(0.5, 'one'), (0.6, 'two'), (0.8, 'three')],
      dtype=[('field1', '<f8'), ('field2', '<U10')])

In [196]: dicts                                                                                        
Out[196]: 
[{'field1': 0.5, 'field2': 'one'},
 {'field1': 0.6, 'field2': 'two'},
 {'field1': 0.8, 'field2': 'three'}]

save and load:

In [197]: io.savemat('ones.mat', {'arr':arr, 'dicts':dicts})                                           
In [198]: io.loadmat('ones.mat')                                                                       
Out[198]: 
{'__header__': b'MATLAB 5.0 MAT-file Platform: posix, Created on: Fri May  1 09:06:19 2020',
 '__version__': '1.0',
 '__globals__': [],
 'arr': array([[(array([[0.5]]), array(['one'], dtype='<U3')),
         (array([[0.6]]), array(['two'], dtype='<U3')),
         (array([[0.8]]), array(['three'], dtype='<U5'))]],
       dtype=[('field1', 'O'), ('field2', 'O')]),
 'dicts': array([[array([[(array([[0.5]]), array(['one'], dtype='<U3'))]],
       dtype=[('field1', 'O'), ('field2', 'O')]),
         array([[(array([[0.6]]), array(['two'], dtype='<U3'))]],
       dtype=[('field1', 'O'), ('field2', 'O')]),
         array([[(array([[0.8]]), array(['three'], dtype='<U5'))]],
       dtype=[('field1', 'O'), ('field2', 'O')])]], dtype=object)}

savemat has created some object dtype arrays (and fields) and 2d MATLAB like arrays.

In an Octave session:

>> load ones.mat

The arr is a struct array with 2 fields:

>> arr
arr =

  1x3 struct array containing the fields:

    field1
    field2

>> arr.field1
ans =  0.50000
ans =  0.60000
ans =  0.80000
>> arr.field2
ans = one
ans = two
ans = three

dicts is a cell with scalar structures:

>> dicts
dicts =
{
  [1,1] =

    scalar structure containing the fields:

      field1 =  0.50000
      field2 = one

  [1,2] =

    scalar structure containing the fields:

      field1 =  0.60000
      field2 = two

  [1,3] =

    scalar structure containing the fields:

      field1 =  0.80000
      field2 = three

}

which can be converted to the same struct array as @Unbearable showed:

>> [dicts{:}]
ans =

  1x3 struct array containing the fields:

    field1
    field2

>> _.field1
error: '_' undefined near line 1 column 1
>> [dicts{:}].field1
ans =  0.50000
ans =  0.60000
ans =  0.80000
>> [dicts{:}].field2
ans = one
ans = two
ans = three

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.