Extract structures in a loop - matlab

I have a structure ('data'), with 26 fields (A, B, C, D, etc.). Each field contains 1x30 cells (one for each participant), and each cell contains a structure.
I would like to extract all the structures (i.e., one structure per field) corresponding to each participant. That is, I would like to obtain 30 new ‘data’, each with 26 fields, and each field containing 1x1 structure, with the structure corresponding to the participant. I have tried the following code:
data = load('D:\filepath\mydata.mat'); %load file with data. 1x1 struct.
all_fields = fieldnames(data); %store the fields of the structure. 26x1 cell.
forStr = length(all_fields); %26
n_ppts = 30; %total number of participants.
%for each participant, extract the corresponding structure in each field.
for nn = 1:n_ppts
for idx_field = 1:forStr
name_field = all_fields{idx_field};
data2 = data;
data2.(name_field) = data.(name_field){nn};
end
%save the 'data' for each participant. The 'data' should include 26 fields, and 1 structure for each field.
name = ppt_fname(nn); %Generate the new name for saving
savename =string(regexprep(name,'_oldname.set','_newname.mat'));
save(savename, '-struct', 'data');
end
The code doesn’t give any error. However, it doesn’t run as I expected.
‘data2’ still contains 26 fields, but only the last field contains 1 structure corresponding to the participant. The other fields contain 1x30 cell.
I guess it is because every time I run the loop it overwrites the previous fields, leaving only the last field correct. So, I think I might need a temporary variable where to store each iteration of the loop.
I thought to create as the temporary storage for each field
structure = [];
namelist = {‘A’;’B’;’C’;’D’;’E’;’F’;’G’;’H’;’I’;’J’;’K’;’L’;’M’;’N’;’O’;’P’;’Q’;’R’;’S’;’T’;’U’;’V’;’W’;’X’;’Y’;’Z’};
for i = 1:length(namelist)
structure.(namelist{i})={};
end
But cannot figure out how to make it work.

You need to take the line data2 = data; out of the for loops.

Antoine T is right, you always copy the original structure data again to data2 in every loop. That is why it won't get changed (except for the very last step of the loop, where you add a single field name to it.)
Regarding your other problem:
% create empty struct:
S = struct();
% loop
for i = 1:25
% create field name
nm = char( double('A') +i );
% create new field with empty cell.
S.(nm) = {};
end
It is just nice to convert number to chars as fieldnames. Your primary error was that you used the wrong inverted comma to create chars.
A minor flaw though was that you allocated strucutre = [] as an empty matrix rather than as an empty struct

Related

Merge all data from xyz files in Matlab

I have a set of 501 XYZ files which I load in as
for k = 1:501
% AIS SEC data
AIS_SEC{k} = importdata(['AIS_SEC(' num2str(k) ').xyz']);
end
This generates an 1x501 cell array in which all data are stored (I uploaded this file as in attachment at https://nl.mathworks.com/matlabcentral/answers/486579-how-to-merge-multiple-xyz-files-into-1-large-array). How can I merge all these data to have 1 large XYZ file? The ultimate goal is the have a nx3 array where all of the data from the seperate xyz files are merged in to 1.
For example, to concentrate X data, I tried:
for k = 1:501
my_field = sprintf('X%d', k);
variable.(my_field) = ([AIS_SEC{1,k}.data(:,1)]);
end
BUT: Dot indexing is not supported for variables of this type.
Thanks!
There are several wrong things with your code:
First thing, the error Struct contents reference from a non-struct array object. shows up first at index k=33 because the structure imported has no data field (the import was probably empty or failed).
Checking for the presence of the field let the code run through to completion. You'll then notice that you have 8 rows which are empty.
load('AIS_SEC.mat')
n=numel(AIS_SEC) ;
EmptyRows = false(n,1) ;
for k = 1:n
my_field = sprintf('X%03d', k);
if isfield( AIS_SEC{1,k} , 'data')
variable.(my_field) = AIS_SEC{1,k}.data;
else
variable.(my_field) = [] ;
EmptyRows(k) = true ;
end
end
fprintf('Number of empty rows encountered: %u\n',sum(EmptyRows))
I took the liberty to also remove unnecessary parenthesis, added an empty row index counter, and adjusted the sprintf output format so all your field will have the same length (even the first field will have the leading zeros. 'X001' to 'X500' instead of 'X1' to 'X500').
Also, this was only retrieving the first column out of each structure, so I modified it to retrieve the 3 x,y,z columns. If you really wanted only the first column, just replace variable.(my_field) = AIS_SEC{1,k}.data by variable.(my_field) = AIS_SEC{1,k}.data(:,1).
Now this gives you a long structure with 500 fields (each representing one imported variable). Your question is not clear enough on that point but if you want to have a single array where all the values are merged, then you have 2 options:
1) Directly after the code above, convert your structure to a merged array:
vararray = cell2mat(struct2cell(variable)) ;
2) If the steps above (the final variable structure) is not something you need to keep, then you can avoid it in the first place:
load('AIS_SEC.mat')
n = numel(AIS_SEC) ; % number of field to import
% first pass we count how many data point (if any) each structure has
EmptyRows = false(n,1) ;
npts = zeros(n,1) ;
for k = 1:n
if isfield( AIS_SEC{1,k} , 'data')
npts(k) = size( AIS_SEC{1,k}.data , 1 ) ;
else
EmptyRows(k) = true ;
end
end
% fprintf('Number of empty rows encountered: %u\n',sum(EmptyRows))
% The above allows us to preallocate the output matrix at the right size
cumpts = cumsum(npts) ;
totalNumberOfPoints = cumpts(end) ;
vararray = zeros(totalNumberOfPoints,3) ;
% first field to import
vararray( 1:cumpts(1) , : ) = AIS_SEC{1,1}.data ;
% now all the remaining ones
for k = 2:n
idx = (cumpts(k-1)+1):cumpts(k) ;
if ~isempty(idx)
vararray(idx,:) = AIS_SEC{1,k}.data ;
end
end
In this version there are 2 passes of the loop accross the structure. Counter intuitively this is done for better performances. The first pass is only to count the number of data points in each structure (and also to flag the empty ones). Thanks to the number returned by the first pass, we can preallocate the output matrix before the second pass and assign each structure data to the merged array in the right place without having to resize the output array at each iteration.

Constructing a structure in matlab

Could someone please help me in constructing this structure?
As one can see, I have to import this file from excel and convert it into a structure as shown. I have been able to develop a code which can create structures by manually entering Id numbers. For instance if I enter 150 it gives a structure for 150 as shown.
However I have to automate the process, i.e. I want matlab to identify the unique Ids and create the entire structure with all its data and timing in each of its ID.
Here's my code
function [ DynData ] = myfunction( filename )
[dat1, dat2, dat3] = xlsread(filename);
flds = dat3(1,:);
InputData = cell2struct(dat3(2:end,:),flds,2);
uIDs = unique( cell2mat(dat3(2:end, 2))) ;
for j = 1:length(dat3)
uIDs = dat3(j);
i=1;
for k = 2:length(dat3(:,1))
if dat3{k,2} == {uIDs}
IDnumber = ['ID',num2str(uIDs)];
DynData.(IDnumber).time(1,i) = dat3{k,1};
DynData.(IDnumber).ID(1,i) = dat3{k,2};
DynData.(IDnumber).data(1,i) = dat3(k,3);
i=i+1;
end
end
end
end
Any help will be really appreciated!
I prefer to load my .xlsx into tables for easier access.
Try this function:
UPDATE
if id is a number, you cannot use it directly as a field name in your structure. The first character in a field name must be a letter. You can fix this by using a prefix:
function dynData=tableImport(file)
% Imports data from .xls file with columns 'Time' 'Id' 'Data' into
% structure dynData with fieldnames=unique(id) each of which is in turn a
% struct array with fields Time and Data.
% Get data
tab=readtable(file);
% Group by id
G=findgroups(tab.Id);
% Extract id and structure
[id, st]=splitapply(#groupTable,tab,G);
% Build dynData
fieldNames=strsplit(sprintf('id%i\n',id));
for i=1:length(id)
dynData.(fieldNames{i})=st{i};
end
end
function [ID, struc]=groupTable(time,id,data)
% Function for finding id-name and splitting time and data into a struct.
ID=id(1);
struc={struct('Time',num2cell(time),'Data',data)}; % stored in cell
end
Although if I were you I'd rather store my data in a structure array with fieldnames
id (string)
time (array)
data (array/cellarray)
for easier access in for-loops
UPDATE 2
This is what I tried to suggest as a better structure:
function dynData=tableImport2(file)
% Imports data from .xls file with columns 'Time' 'Id' 'Data' into
% structure dynData with fieldnames=unique(id) each of which is in turn a
% struct array with fields Time and Data.
% Get data
tab=readtable(file);
% Group by id
G=findgroups(tab.Id);
% Extract id and structure
dynData=splitapply(#(time,id,data)struct('Id',id(1),'Time',time,'Data',{data}),tab,G);
end

Naming Image using index of for loop in each iteration

I am working in MATLAB for my image processing project.
I am using a for loop to generate some kind of image data (size of image varies) with each loop iteration. My problem is how do stop it from overwriting the image in next iteration.
Img(i,j)=data
Ideally I would like it to have
Img_1 = data (for 1st iteration)
Img_2 = data (for 2nd iteration)
Img_3 = data (for 3rd iteration)
and so on...
Is there any way, it can be acheived?
Yes, you can use dynamic field names with structures. I wouldn't recommend using separate variable names because your workspace will become unwieldy. Do something like this:
img_struct = struct(); %// Create empty structure
for ii = 1 : num_iterations
%// Do your processing on data
%...
%...
img_struct.(['Img_' num2str(ii)]) = data; %// After iteration
end
This will create a structure called img_struct where it will have fields that are named Img_1, Img_2, etc. To access a particular data from an iteration... say... iteration 1, do:
data = img_struct.Img_1;
Change the _1 to whatever iteration you choose.
Alternatively, you can use cell arrays... same line of thinking:
%// Create empty cell array
img_cell = cell(num_iterations, 1);
for ii = 1 : num_iterations
%// Do your processing on data
%...
%...
img_cell{ii} = data; %// After iteration
end
Cell arrays are arrays that take on any type per element - or they're non-homogeneous arrays. This means that each element can be whatever you want. As such, because your image data varies in size at each iteration, this will do very nicely. To access data at any iteration, simply do:
data = img_cell{ii};
ii is the index of the iteration you want to access.
If you want to literally obtain what you are asking for, you can use the eval() function, which takes a string as input that it will evaluate as if it were a line of code. Example:
for i=1:3
data=ones(i); % assign data, 'ones(i)' used as dummy for test
eval(['Img_' num2str(i) '=data;'])
end
However, I would recommend using cell arrays {}, or alternatively the struct function that rayryeng both suggested.

Matlab: Iterating over large groups of stored data

I am looking at storing my multiple variables into the one array or cell matrix.
The data I currently have is
seaLevel <339x1 double>
tideLevel <201x1 double>
height <55x1 double>
I want to have all of these in the one class so I can iterate through each group.
So varGroup will contain all three of the above variables with their name
Hope someone can help
Just define structure in matlab such as
z = struct('seaLevel', zeros(1,339),
'tideLevel', zeros(1,201),
'height', zeros(1,55));
And you can create an array of structure as well
data(n) = z;
To expand on the other answer and your comments, you can use a struct and still be able to access all of them within a loop by utilizing fieldnames and dynamic field references. Depending on what you're doing with the variables, structfun might also be an option.
For example:
% Dummy data!
seaLevel = rand(339, 1);
tideLevel = rand(201, 1);
height = rand(55, 1);
% Generate our data structure
mydata_struct = struct( ...
'seaLevel', seaLevel, ...
'tideLevel', tideLevel, ...
'height', height ...
);
datafields = fieldnames(mydata_struct);
nvariables = length(datafields);
for ii = 1:nvariables
fprintf('Looping over ''%s'' data, %u data entries\n', datafields{ii}, length(mydata_struct.(datafields{ii})))
end
Which prints the following to the console:
Looping over 'seaLevel' data, 339 data entries
Looping over 'tideLevel' data, 201 data entries
Looping over 'height' data, 55 data entries
As you can see, you can loop over all of your data with a simple loop.
Alternatively, you can utilize a cell array:
% Dummy data!
seaLevel = rand(339, 1);
tideLevel = rand(201, 1);
height = rand(55, 1);
% Generate a cell array
mydata_cell = {seaLevel, tideLevel, height};
nvariables = length(mydata_cell);
for ii = 1:nvariables
fprintf('Looping over data column %u, %u data entries\n', ii, length(mydata_cell{ii}))
end
Which prints the following to the console:
Looping over data column 1, 339 data entries
Looping over data column 2, 201 data entries
Looping over data column 3, 55 data entries
A cell array is slightly simpler, though you lose the ability to reference your data by name like you can with the struct array above. Both approaches allow you to store and access dissimilar data in the same array.

How to get all data from a struct?

I've got a result from a web service and MatLab gladly notifies that it is a 1x1 struct. However, when I try to display it (by typing receivedData and pressing enter) I get to see this:
ResponseData: [5x1 struct]
Equally gladly, I entered the following, in my attempt to get the data viewed to me:
struct2array(responseData)
I get only a bunch (not five, more than five) of strings that might be names headers of columns of the data provided.
How do I get all the data from such structure?
You may use fieldnames to get the data from the struct and then iteratively display the data using getfield function. For example:
structvariable = struct('a',123,'b',456,'c',789);
dataout = zeros(1,length(structvariable)) % Preallocating data for structure
field = fieldnames(a);
for i = 1:length(structvariable)
getfield(structvariable,field{i})
end
Remember, getfield gives data in form of cell, not matrix.
or you can use cellfun function:
% STRUCT - your structure
% tmp_nam - structure field names
% tmp_val - values for structure field names
tmp_nam = fieldnames(STRUCT);
tmp_val = cellfun(#(x)(STRUCT.(x)),tmp_nam,'UniformOutput',false);
In order to display all elements and subelements of a structure there is a custom function that you can download here:
http://www.mathworks.com/matlabcentral/fileexchange/13831-structure-display
Some useful access syntax:
someVar = ResponseData(1) %Displays the first element
someVar = ResponseData(4) %Displays the 4th element
To display them all, one after the next
for ix = 1:length(ResponseData)
tmp = ResponseData(ix);
end
To get all the fieldnames
names = fieldnames(ResponseData)
To get all 5 data elements from the structure with the first field names, and put them into a cell array
ixFieldName = 1;
someCellArray = { ResponseData.(ixFieldName{1}) }
A small correction to Sahinsu's answer:
structvariable = struct('a',123,'b',456,'c',789);
dataout = zeros(1,length(structvariable)) % Preallocating data for structure
field = fieldnames(structvariable);
for i = 1:length(field)
getfield(structvariable,field{i})
end