Concatenate subfields from Matlab structure into one data array

Don't you just hate when you have an [cci]MxN[/cci] struct array in Matlab, where each element contains some [cci]PxK[/cci] data field, and you just really want to have all that data in a single [cci]PxKxMxN[/cci] array? OK, maybe this doesn't happen to you very frequently, but it has happened to me. In fact, it has happened so often that I decided to write a (very simple) general solution to this problem.

Let me motivate the problem with an example. I was dealing with Granger causality spectra that are stored in FieldTrip structures as follows:
[cc lang="matlab"]>> allconns(1)

ans =

struct with fields:

label: {7×1 cell}
dimord: 'chan_chan_freq'
grangerspctrm: [7×7×101 double]
freq: [1×101 double]
cfg: [1×1 struct][/cc]
and I had one of these structures per participant, per condition of my experiment, and per time-direction (forward or reverse; details don't really matter here). The structures were all tucked into one structure variable [cci]allconns[/cci] such that
[cc lang="matlab"]>> size(allconns)

ans =

36 7 2
[/cc]
To get out the data into one big 6-dimensional array, I first concatenated along the fourth dimension:
[cc lang="matlab"]catdat = cat(4, allconns.grangerspctrm);[/cc]
which unfortunately flattens all those [cci]36x7x2[/cci] dimensions such that
[cc lang="matlab"]>> size(catdat)

ans =

7 7 101 504
[/cc]
However, it's easy to just get those back by one final [cci]reshape[/cci]:
[cc lang="matlab"]catdat = reshape(catdat, [7 7 101 36 7 2]);[/cc]
The above works because Matlab stores data in column-major order.

It's very straightforward to embed this into a simple function (also available on GitHub):
[cc lang="matlab"]function x = structcat(y, param)
% STRUCTCAT takes a structure y of arbitrary dimensionality Mx...xN, each
% element of which contains a field named of dimensionality
% Px...xK, and returns the data in those fields concatenated into a
% Px...XKxMx...N array.
%
% Author: Eelke Spaak, 2018.

siz1 = size(y);
siz2 = size(y(1).(param));

x = cat(numel(siz2)+1, y.(param));
x = reshape(x, [siz2 siz1]);

end[/cc]

I hope this is useful to someone who's encountered the same!

Leave a Reply

Your email address will not be published. Required fields are marked *