Create structure fieldnames from array of numbers - matlab

I have a dataset that I would like to categorise and store in a structure based on the value in one column of the dataset. For example, the data can be categorised into element 'label_100', 'label_200' or 'label_300' as I attempt below:
%The labels I would like are based on the dataset
example_data = [repmat(100,1,100),repmat(200,1,100),repmat(300,1,100)];
data_names = unique(example_data);
%create a cell array of strings for the structure fieldnames
for i = 1:length(data_names)
cell_data_names{i}=sprintf('label_%d', data_names(i));
end
%create a cell array of data (just 0's for now)
others = num2cell(zeros(size(cell_data_names)));
%try and create the structure
data = struct(cell_data_names{:},others{:})
This fails and I get the following error message:
"Error using struct
Field names must be strings."
(Also, is there a more direct method to achieve what I am trying to do above?)

According to the documentation of struct,
S = struct('field1',VALUES1,'field2',VALUES2,...) creates a
structure array with the specified fields and values.
So you need to have each value right after its field name. The way you are calling struct now is
S = struct('field1','field2',VALUES1,VALUES2,...)
instead of the correct
S = struct('field1',VALUES1,'field2',VALUES2,...).
You can solve that by concatenating cell_data_names and others vertically and then using {:} to produce a comma-separated list. This will give the cells' contents in column-major order, so each field name fill be immediately followed by the corresponding value:
cell_data_names_others = [cell_data_names; others]
data = struct(cell_data_names_others{:})

Related

MATLAB: Pass part of structure field name to function

I need to pass a part of a structure's name into a function.
Examples of a available structs:
systems.system1.stats.equityCurve.relative.exFee
systems.system1.stats.equityCurve.relative.inFee
systems.system2.stats.equityCurve.relative.exFee
systems.system2.stats.equityCurve.relative.inFee
systems.system1.returns.aggregated.exFee
systems.system1.returns.aggregated.inFee
systems.system2.returns.aggregated.exFee
systems.system2.returns.aggregated.inFee
... This goes on...
Within a function, I loop through the structure as follows:
function mat = test(fNames)
feeString = {'exFee', 'inFee'};
sysNames = {'system1', 'system2'};
for n = 1 : 2
mat{n} = systems.(sysNames{n}).stats.equityCurve.relative.(feeString{n});
end
end
What I like to handle in a flexible way within the loop is the middle part, i.e. the part after systems.(sysNames{n}) and before .(feeString{n}) (compare examples).
I am now looking for a way to pass the middle part as an input argument fNames into the function. The loop should than contain something like
mat{n} = systems.(sysNames{n}).(fName).(feeString{n});
How about using a helper function such as
function rec_stru = recSA(stru, field_names)
if numel(field_names) == 1
rec_stru = stru.(field_names{1});
else
rec_stru = recSA(stru.(field_names{1}), field_names(2:end));
end
This function takes the intermediate field names as a cell array.
This would turn this statement:
mat{n} = systems.(sysNames{n}).stats.equityCurve.relative.(feeString{n});
into
mat{n} = recSA(systems.(sysNames{n}), {'stats', 'equityCurve', 'relative', feeString{n}});
The first part of the cell array could then be passed as an argument to the function.
This is one of those cases where matlab is a bit unhelpful in the documentation. There is a way to use the fieldnames function in matlab to get the list of all the fields and iterate over that using dynamic fields.
systems.system1.stats.equityCurve.relative.exFee='T'
systems.system1.stats.equityCurve.relative.inFee='E'
systems.system2.stats.equityCurve.relative.exFee='S'
systems.system2.stats.equityCurve.relative.inFee='T'
systems.system1.returns.aggregated.exFee='D'
systems.system1.returns.aggregated.inFee='A'
systems.system2.returns.aggregated.exFee='T'
systems.system2.returns.aggregated.inFee='A'
dynamicvariable=fieldnames(systems.system1)
This will return a cell matrix of the field names which you can use to iterate over.
systems.system1.(dynamicvariable{1})
ans =
equityCurve: [1x1 struct]
Ideally you would have your data structure fixed in such a way that you know how many levels of depth are in your data structure.

MATLAB: removing non-unique numbers from a field within a structure

I have a structure in Matlab, each field contains elements with varying numbers of variables. I would like to remove duplicates of numbers that appear within the same field: I know the unique() function and know how to use it to scan through fields one at a time but not an entire field.
I think I want something like:
structure(1:length(structure)).field=unique(structure(1:length(structure)).field
and get
original
field=[1,2,3] [1,4,5] [2,5,8]
to turn into
field=[1,2,3] [4,5] [8]
Maybe a complicated for loop similar to below (isn't working) which would grab the values from the first element in the field, search through each additional element, and if that value is present set it equal to =[];, and iterate through that way?
for n=1:length(RESULTS)
for m=1:length(RESULTS(n).Volumes)
for l=1:length(RESULTS)
for o=1:length(RESULTS(l).Volumes)
if RESULTS(n).Volumes(m)==RESULTS(l).Volumes(o)
RESULTS(l).Volumes(o)=[];
end
end
end
end
end
Thanks!
This is a quick-and-dirty attempt, but you might be able to improve on it. Assume your struct array and field are sa(:).v. I'm also assuming that the field contains a 1xn array of numbers, as in your example. First, make a "joint" array with the concatenation of all field values and filter the non-unique values:
joint = cell2mat({sa.v});
[uniqJoint,~,backIdx] = unique(joint);
The "uniqJoint" array has also been sorted, but the "backIdx" array contains the indices that, if applied to uniqJoint, will rebuild the original "joint" array. We need to somehow connect those to the original indices (i,j) into the struct array and within the field value sa(i).v(j). To do that, I tried creating an array of the same size as "joint" that contains the indices of the struct that originally had the corresponding element in the "joint" array:
saIdx = cell2mat(arrayfun(#(i) i * ones(1,length(sa(i).v)), ...
1:length(sa), 'UniformOutput', false));
Then you can edit (or, in my case, copy and modify the copy of) the struct array to set the field to the values that have not appeared before. To do that, I keep a logical array to mark the indices of "backIdx" as "already used", in which case I skip those values when rebuilding the fields of each struct:
sb = sa;
used = false(length(backIdx));
for i = 1:length(sa)
origInd = find(saIdx == i); % Which indices into backIdx correspond to this struct?
newInd = []; % Which indices will be used?
for curI = backIdx(origInd)
if ~used(curI)
% Mark as used and add to the "to copy" list
used(curI) = true;
newInd(end+1) = curI;
end
end
% Rewrite the field with only the indices that were not used before
sb(i).v = uniqJoint(newInd);
end
In the end, the data in sb(i).v contains the same numbers as sa(i).v without repeats, and removing those that appeared in any previous elements of the struct.

Save a string, double and table Matlab

I have a loop which runs 100 times. In each iteration there is a string, double and a table assigned, and in the next iteration new values are assigned for them. What I want to do is to accumulate these values and after the loop finishes save the total result as result.mat using the matlab save function. I've tried putting them in cell-array but its not working so far, so if anyone could please advise how this can be done.
This is what I did:
results_cell=(100,3);
.
.
.
results_cell(i,1)=stringA;
results_cell(i,2)=TableA;
results_cell(i,3)=DoubleA;
But it gives this error Coversion to Cell from Table is not possible. So I've tried converting TableA to array of Doubles using table2array but I still get this Coversion to Cell from Double is not possible
I think using a structure would be a good way to store your data, since they are of different types and you can assign it meaningful field names for easy reference.
For example, let's call the structure Results. You can initialize it like so.
Results = struct('StringData',[],'TableData',[],'DoubleData',[])
Since you know its dimensions, you can even do this:
N = 100;
Results(N).StringData = [];
Results(N).TableData = [];
Results(N).DoubleData = [];
This automatically create a 1xN structure with 3 fields.
Then in your loop you can assign each field with its associated data like so:
for k = 1:N
Results(k).StringData = String(k);
Results(k).TableData = Table(k);
Results(k).DoubleData = Double(k);
end
where String(k), Table(k) and Double(k) are just generic names for your actual data.
When you're done with the loop you can access any type of data using a single index and the right field name.
In order to save a .mat file, use something like this:
save SomeFileName.mat Results
Which you can load into the workspace as you would with any .mat file:
Eg:
S = load('SomeFileName.mat')
R = S.Results
Hope that helps!

still stuck trying to update rows name of uitable in matlab gui

I am still trying to update the row names of a uitable in a matlab gui. I previously asked you about this (https://stackoverflow.com/questions/21585453/update-rows-name-of-uitable-in-matlab-gui). However, I am writing you again in order to let you know that I am not able to solve this problem.
This is the part of my code where I am stuck:
function SavePushButton_Callback(~,~)
%%##
data{1,1}= get(h5Out,'string');
data{1,2}= get(h6Out,'string');
data{1,3}= get(h7Out,'string');
data{1,4}= get(h8Out,'string');
===============================
% Update the data %
oldData = get(t,'Data');
newRow = cat(0,data,cell(0,size(data,2)));
newData2 = [oldData; newRow];
set(t,'Data',newData2);
===============================
% this part of the code should Update the name of the rows %
rowname = get(h1Out,'string');
NewRowName = cat(0,rowname,cell(0,size(rowname,1)));
rowname2= [rowname; NewRowName];
set(t,'Rowname',rowname2);
end
It looks like the function to set the Rowname is expecting a cell array of strings, however you're giving it a cell array of cells, which themselves contain strings. This is because the get function (for example data{1,1}= get(h5Out,'string'); ) is already returning a cell array containing a string, and you're storing it within another cell array ( data ). Use () instead of {} on the data matrix in order to concatenate the individual cells into one single cell matrix. In other words, change:
data{1,1}= get(h5Out,'string');
data{1,2}= get(h6Out,'string');
data{1,3}= get(h7Out,'string');
data{1,4}= get(h8Out,'string');
to:
data(1,1)= get(h5Out,'string');
data(1,2)= get(h6Out,'string');
data(1,3)= get(h7Out,'string');
data(1,4)= get(h8Out,'string');

Simultaneously assign values to multiple structure fields

I have a matlab structure that follows the following pattern:
S.field1.data1
...
.field1.dataN
...
.fieldM.data1
...
.fieldM.dataN
I would like to assign values to one data field (say, data3) from all fields simultaneously. That would be semantically similar to:
S.*.data3 = value
Where the wildcard "*" represents all fields (field1,...,fieldM) in the structure. Is this something that can be done without a loop in matlab?
Since field1 .. fieldM are structure arrays with identical fields, why not make a struct array for "field"? Then you can easily set all "data" members to a specific value using deal.
field(1).data1 = 1;
field(1).data2 = 2;
field(2).data1 = 3;
field(2).data2 = 4;
[field.data1] = deal(5);
disp([field.data1]);
A loop-based solution can be flexible and easily readable:
names = strtrim(cellstr( num2str((1:5)','field%d') )); %'# field1,field2,...
values = num2cell(1:5); %# any values you want
S = struct();
for i=1:numel(names)
S.(names{i}).data3 = values{i};
end
In simple cases, you could do that by converting your struct into a cell array using struct2cell(). As you have a nested structure, I don't think that will work here.
On the other side, is there any reason why your data is structured like this. Your description gives the impression that a simple MxN array or cell array would be more suitable.