How can I unpack a Matlab structure into function arguments? - matlab

Using a combination of this question and this Mathworks help thing on comma sep. lists I came up with this ugly way to make my formatting arguments a little prettier:
formatting{1,1} = 'color'; formatting{2,1} = 'black';
formatting{1,2} = 'fontweight'; formatting{2,2} = 'bold';
formatting{1,3} = 'fontsize'; formatting{2,3} = 24;
xlabel('Distance', formatting{:});
But it's still kinda ugly...is there a way to unpack a structure into a bunch of arguments a la a Python dictionary to **kwargs?
For instance, if I had the (IMHO) cleaner structure:
formatting = struct()
formatting.color = 'black';
formatting.fontweight = 'bold';
formatting.fontsize = 24;
Can I just pass that in somehow? If I try directly (xlabel('blah', formatting), or formatting{:}, it craps out saying "Wrong number of arguments".

You are very close. Just switch to a 1-D cell array.
formatting = {'Color', 'Red', 'LineWidth', 10};
figure
plot(rand(1,10), formatting{:})
If you really want to use a struct for formatting arguments, you can unpack it to a cell array and use it like above.
formattingStruct = struct();
formattingStruct.color = 'black';
formattingStruct.fontweight = 'bold';
formattingStruct.fontsize = 24;
fn = fieldnames(formattingStruct);
formattingCell = {};
for i = 1:length(fn)
formattingCell = {formattingCell{:}, fn{i}, formattingStruct.(fn{i})};
end
plot(rand(1,10), formatting{:})
It's probably a good idea to do the struct unpacking a separate little function so you can reuse it easily.

You can convert your structure to cell array with this function:
function c = struct2opt(s)
fname = fieldnames(s);
fval = struct2cell(s);
c = [fname, fval]';
c = c(:);
Then
formatting = struct2opt(formattingStructure);
xlabel('Distance', formatting{:});

Related

concatenation of the arrayfun output

Assuming that
outputTemp =
2×1 cell array
{122×1 string}
{220×1 string}
finalOutput is a string array (342x1 string).
is there any way to do the following
outputTemp = arrayfun(#(x)someFunc(x), someInput, 'UniformOutput', false)';
finalOutput= [outputTemp{1}; outputTemp{2}];
in one line?
for the minimal example, someFunc can be a function that provides the names of the files in folders provided in someInput.
Short answer: yes. Here is a MWE:
str1 = ["Test";"Test1";"42"]
str2 = ["new test";"pi = 3"]
C = {str1;str2}
ConCatStr = [C{1};C{2}];
This should answer the question regarding concatnation of string-arrays. Note that this is only possible with real strings (not with char-arrays). It is hard to tell, what you are doing beforehand as there are not details about getFilesFilt() and mainFolderCUBX.
EDIT MVE for the updated question
% function that returns a matrix
fnc = #(x)[x,1];
% anonymous function that returns a vector
fnc2 = #(x)reshape(fnc(x),2,1)
tmp = arrayfun(#(x)fnc(x), rand(10,1),'UniformOutput',false)
Answer: there is no proper way. However, you can do a little bit of fiddling and force everything into a single line (making the code ugly and less efficient)
tmp = arrayfun(#(x)fnc(x), rand(10,1),'UniformOutput',false);
out = reshape(cell2mat(tmp),numel(cell2mat(tmp)),1);
just replace the tmp with what is written with it.
You can try the following code using cat() + subsref(), i.e.,
finalOutput= cat(1,subsref(arrayfun(#(x)someFunc(x), someInput, 'UniformOutput', false),struct('type', '{}', 'subs', {{:}})));
Example
S(1).f1 = rand(3,5);
S(2).f1 = rand(6,10);
S(3).f1 = rand(4,2);
cat(1,subsref(arrayfun(#(x) mean(x.f1)',S,'UniformOutput',false),struct('type', '{}', 'subs', {{:}})))
such that
ans =
0.89762
0.53776
0.42440
0.25272
0.58197
0.34503
0.40259
0.41792
0.43527
0.53974
0.49976
0.63342
0.36539
0.58541
0.57042
0.60914
0.60851

MATLAB: How to dynamically access variables

I declared some variables comprising of simple row vectors which represents input parameters for another function. Within a loop these variables should be used and the result will be assigned to a structure.
Now, my question is how to best access the content of the predefined variables. I found a solution using eval. However, I often read that the usage of eval should be avoided. Apparently it's not best practice. So, what's best practice for my problem?
varABC = [1,2,3];
varDEF = [4,5,6];
varGHI = [7,8,9];
names = {'ABC','DEF','GHI'};
result = {'result1','result2','result3'};
for i = 1 : 3
varString = strcat('var',names{i});
test.(result{i}) = sum(eval(varString));
end
I would suggest rewriting your code a little bit
names = {'ABC','DEF','GHI'};
result = {'result1','result2','result3'};
option 1
% Use struct instead of a simple variable
var.ABC = [1,2,3];
var.DEF = [4,5,6];
var.GHI = [7,8,9];
for i = 1 : 3
test.(result{i}) = sum(var.(names{i}));
end
option 2
% Use dictionary
c = containers.Map;
c('ABC') = [1,2,3];
c('DEF') = [4,5,6];
c('GHI') = [7,8,9];
for i = 1 : 3
test.(result{i}) = sum(c(names{i}));
end

Convert struct fields from string to number

I have a struct with several fields, some that should be numeric, and some that should be char. However, after my use of regexp I have chars in the fields that I want to use as numbers.
For example:
foo.str = 'one';
foo.data = '1';
foo(2).str = 'two';
foo(2).data = '2';
In my dreams I could do: foo.data = str2double(foo.data), but this does not work.
I could iterate through the struct, but that's only an ok option.
It's a long struct (100,000) with about 20 files.
for i = 1:length(foo)
foo(i).data = str2double(foo(i).data);
end
Any ideas?
Collect all elements from the subfield and call str2double once:
str2double({foo.data})
Here is a fairly compact solution that deals numerical values back into each foo.data:
fdnc = num2cell(str2double({foo.data}));
[foo.data] = deal(fdnc{:});
Remember to clear and redefine foo when testing.
EDIT: Fixed vertcat problem with multiple digits. Thanks, nispio.
A little cumbersome, but this works; no loops:
N = length(foo);
[aux_str{1:N}] = deal(foo.str);
[aux_data{1:N}] = deal(foo.data);
aux_data = mat2cell(str2double(aux_data),1,ones(1,N));
foo = cell2struct([aux_str; aux_data],{'str','data'},1);

MATLAB: Conversion to char from cell is not possible

So I've got a struct, settings, which contains three fields, averageValue, heightLabels and heights.
settings.averageValue = 7.5121 7.2742 7.4602
settings.heights = 105.1000 105.2000 105.3000
I'm looping through these with the following code:
for m = 1:length(settings.averageValue)
settings.heightLabels(m) = {sprintf{'%.1f %s', settings.heights(m), 'm')};
end
However, I get the error "Conversion to char from cell is not possible.". Any ideas?
Well, I get your question now. Let's say you have variables A,B,C,D which you want to club together in a struct variable. Here's how you do it:
settings.A = A;
settings.B = B;
settings.C = C;
settings.D = D;
settings is a struct variable now, and if you want to access A, you refer to it as:
disp(settings.A) %display A
settings.A = 10; %edit A
newA = settings.A; %assign A to a new variable
Pass settings to a function, do whatever.
Okay guys I figured it out. It was a datatype question; my struct field was supposed to be a cell but it was a string. Rather embarrassing.
I resolved the problem with the following code when creating the struct fields:
settings.averageValue = {};
settings.heightLabels = {};
Thanks for your help!

How do I rename a field in a structure array in MATLAB?

Given a structure array, how do I rename a field? For example, given the following, how do I change "bar" to "baz".
clear
a(1).foo = 1;
a(1).bar = 'one';
a(2).foo = 2;
a(2).bar = 'two';
a(3).foo = 3;
a(3).bar = 'three';
disp(a)
What is the best method, where "best" is a balance of performance, clarity, and generality?
Expanding on this solution from Matthew, you can also use dynamic field names if the new and old field names are stored as strings:
newName = 'baz';
oldName = 'bar';
[a.(newName)] = a.(oldName);
a = rmfield(a,oldName);
Here's a way to do it with list expansion/rmfield:
[a.baz] = a.bar;
a = rmfield(a,'bar');
disp(a)
The first line was originally written [a(:).baz] = deal(a(:).bar);, but SCFrench pointed out that the deal was unnecessary.
Here's a a way to do it with struct2cell/cell2struct:
f = fieldnames(a);
f{strmatch('bar',f,'exact')} = 'baz';
c = struct2cell(a);
a = cell2struct(c,f);
disp(a)