Matlab : cannot get the values of a field in a struct - matlab

I am encountering a rather weird problem. I have a big struct imported from a .mat file (it's an EEG recording):
Now let's assume I want to plot one field, I need to get the values in this field.
However, when I do this:
fieldE1 = EEG.('00 E1');
fieldE1 only becomes the last value of the field : .
If I just write in the console EEG.('00 E1'), it returns this :
ans =
-12.5850
ans =
-12.5790
ans =
-12.5760
ans =
-12.5820
ans =
-12.5890
ans =
-12.5880
ans =
-12.5880
ans =
-12.5860
On and on and on for all the values. Which explains why fieldE1 only returned the last value. I have the same behaviour when I use getfield(EEG, '00 E1') .
Any help would be appreciated.

Subscript references to a field in a struct array will return a comma-separated list. The list must be captured in array delimiters upon assignment to be used as an array:
fieldE1 = [EEG.('00 E1')];

Related

Change string values to number in Matlab table

I am using Matlab2015b. And I would like to read a simple csv file to a table and change its string values to corresponding numeric values.
I have following example data.
Var1, VarClass
1 , attack
2 , normal
1, attack
I would like to change this string values to number. for example attack = 1, normal = -1.
My first try.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T(:,2),'attack');
T(rows_attack,2) = 1
rows_normal = strcmp(T(:,2),'normal');
T(rows_normal,2) = -1
I get following error:
Undefined function 'eq' for input arguments of type 'cell'.
What? Which undefined function? What is 'eq'?
Well. After reading some about table, I understood that supposedly higher level matlab does not override '=='. That is 'eq' which means equality. But error message certainly is not informative.
Then my second try.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T.VarClass,'attack');
T(rows_attack,2) = 1
This time, I get
Right hand side of an assignment into a table must be another table or a cell
array.
Well. Okay. It wants table. I will give it one.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T.VarClass,'attack');
rows_attack_size = sum(rows_attack);
data_to_fill = ones(rows_attack_size,1) ;
T(rows_attack,2) = array2table(data_to_fill);
Well. This time error message is.
Conversion to cell from double is not possible.
I thought that this matlab table is similar to R data-frame or python pandas DataFrame. Well, certainly it is not. Can someone guide me about how to solve this problem?
My Matlab gives different error message to your code.
>> rows_attack = strcmp(T(:,2),'attack')
rows_attack =
0
>> T(rows_attack,2) = 1
Right hand side of an assignment into a table must be another table or a cell array.
>> T(rows_attack,2)
ans =
empty 0-by-1 table
The error is multi-fold. Applying strcmp on a table does not give a vector; instead it's a scalar 0. When indexing T with zero index it gives an empty table. If neither of these is a problem, then storing a scalar double into a table is a type-not-match.
I didn't get your error message Undefined function 'eq' for input arguments of type 'cell'. from any of my trial. Maybe your matlab environment or version has a different strcmp that has a different overload for tables.
Your second try is
>> rows_attack = strcmp(T.VarClass,'attack')
rows_attack =
1
0
1
>> T(rows_attack,2) = 1
Right hand side of an assignment into a table must be another table or a cell array.
>> T(rows_attack,2)
ans =
VarClass
________
'attack'
'attack'
So this time the error is straightforward. Anyway, it looks like the desired is changing the first row to 1, since those are numbers. However, I got error
>> T(rows_attack,1) =2
Right hand side of an assignment into a table must be another table or a cell array.
Your last try works if respecting the above glitch in addressing the correct column.
>> rows_attack = strcmp(T.VarClass,'attack');
>> rows_attack_size = sum(rows_attack);
>> data_to_fill = ones(rows_attack_size,1) ;
>> T(rows_attack,2) = array2table(data_to_fill);
Conversion to cell from double is not possible.
>> data_to_fill
data_to_fill =
1
1
>> whos ans
Name Size Bytes Class Attributes
ans 2x1 1502 table
>> T(rows_attack,1) = array2table(data_to_fill);
>> T
T =
Var1 VarClass
____ ________
1 'attack'
2 'normal'
1 'attack'
>>
Also, the following also works
>> rows_attack = strcmp(T.VarClass,'attack'); T.Var1(rows_attack) = -1
T =
Var1 VarClass
____ ________
-1 'attack'
2 'normal'
-1 'attack'
Well. Thanks to #Yvon, I found my mistake and solved my problem. Following code works.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T.VarClass,'attack');
T.VarClass(rows_attack) = {-1};
rows_normal = strcmp(T.VarClass,'normal');
T.VarClass(rows_normal) = {1};
T.VarClass = cell2mat(T.VarClass);

MATLAB extract field from struct in a vector array

I got the following Problem: I got a struct Array and want to extract one field from that struct in a vector.
The struct has 5 fields, one which is called "name". How can I get These in a vector?
The answer by dfri works but requires MATLAB Mapping Toolbox. You can use
{yourStruct.name} to get them as a cell array or [yourStruct.name] to get them as an array:
>> A(1).name='a';
>> A(2).name='b';
>> A(3).name='c';
>> {A.name}
ans =
'a' 'b' 'c'
or,
>> A(1).num=10;
>> A(2).num=5;
>> A(3).num=25;
>> [A.num]
ans =
10 5 25
You can make use of the extractfield method:
yourNameFieldsAsArray = extractfield(yourStruct, 'name')
Where yourNameFieldsAsArray will be a cell array if the name field holds e.g. character/string values, or a regular value array if name field just hold, say, integers.

Iterating through struct fieldnames in MATLAB

My question is easily summarized as: "Why does the following not work?"
teststruct = struct('a',3,'b',5,'c',9)
fields = fieldnames(teststruct)
for i=1:numel(fields)
fields(i)
teststruct.(fields(i))
end
output:
ans = 'a'
??? Argument to dynamic structure reference must evaluate to a valid field name.
Especially since teststruct.('a') does work. And fields(i) prints out ans = 'a'.
I can't get my head around it.
You have to use curly braces ({}) to access fields, since the fieldnames function returns a cell array of strings:
for i = 1:numel(fields)
teststruct.(fields{i})
end
Using parentheses to access data in your cell array will just return another cell array, which is displayed differently from a character array:
>> fields(1) % Get the first cell of the cell array
ans =
'a' % This is how the 1-element cell array is displayed
>> fields{1} % Get the contents of the first cell of the cell array
ans =
a % This is how the single character is displayed
Since fields or fns are cell arrays, you have to index with curly brackets {} in order to access the contents of the cell, i.e. the string.
Note that instead of looping over a number, you can also loop over fields directly, making use of a neat Matlab features that lets you loop through any array. The iteration variable takes on the value of each column of the array.
teststruct = struct('a',3,'b',5,'c',9)
fields = fieldnames(teststruct)
for fn=fields'
fn
%# since fn is a 1-by-1 cell array, you still need to index into it, unfortunately
teststruct.(fn{1})
end
Your fns is a cellstr array. You need to index in to it with {} instead of () to get the single string out as char.
fns{i}
teststruct.(fns{i})
Indexing in to it with () returns a 1-long cellstr array, which isn't the same format as the char array that the ".(name)" dynamic field reference wants. The formatting, especially in the display output, can be confusing. To see the difference, try this.
name_as_char = 'a'
name_as_cellstr = {'a'}
You can use the for each toolbox from http://www.mathworks.com/matlabcentral/fileexchange/48729-for-each.
>> signal
signal =
sin: {{1x1x25 cell} {1x1x25 cell}}
cos: {{1x1x25 cell} {1x1x25 cell}}
>> each(fieldnames(signal))
ans =
CellIterator with properties:
NumberOfIterations: 2.0000e+000
Usage:
for bridge = each(fieldnames(signal))
signal.(bridge) = rand(10);
end
I like it very much. Credit of course go to Jeremy Hughes who developed the toolbox.

MATLAB "bug" (or really weird behavior) with structs and empty cell arrays

I have no idea what's going on here. I'm using R2006b. Any chance someone out there with a newer version could test to see if they get the same behavior, before I file a bug report?
code: (bug1.m)
function bug1
S = struct('nothing',{},'something',{});
add_something(S, 'boing'); % does what I expect
add_something(S.something,'test'); % weird behavior
end
function add_something(X,str)
disp('X=');
disp(X);
disp('str=');
disp(str);
end
output:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test');
It looks like the emptiness/nothingness of S.something allows it to shift the arguments for a function call. This seems like Very Bad Behavior. In the short term I want to find away around it (I'm trying to make a function that adds items to an initially empty cell array that's a member of a structure).
Edit:
Corollary question: so there's no way to construct a struct literal containing any empty cell arrays?
As you already discovered yourself, this isn't a bug but a "feature". In other words, it is the normal behavior of the STRUCT function. If you pass empty cell arrays as field values to STRUCT, it assumes you want an empty structure array with the given field names.
>> s=struct('a',{},'b',{})
s =
0x0 struct array with fields:
a
b
To pass an empty cell array as an actual field value, you would do the following:
>> s = struct('a',{{}},'b',{{}})
s =
a: {}
b: {}
Incidentally, any time you want to set a field value to a cell array using STRUCT requires that you encompass it in another cell array. For example, this creates a single structure element with fields that contain a cell array and a vector:
>> s = struct('strings',{{'hello','yes'}},'lengths',[5 3])
s =
strings: {'hello' 'yes'}
lengths: [5 3]
But this creates an array of two structure elements, distributing the cell array but replicating the vector:
>> s = struct('strings',{'hello','yes'},'lengths',[5 3])
s =
1x2 struct array with fields:
strings
lengths
>> s(1)
ans =
strings: 'hello'
lengths: [5 3]
>> s(2)
ans =
strings: 'yes'
lengths: [5 3]
ARGH... I think I found the answer. struct() has multiple behaviors, including:
Note If any of the values fields is
an empty cell array {}, the MATLAB
software creates an empty structure
array in which all fields are also
empty.
and apparently if you pass a member of a 0x0 structure as an argument, it's like some kind of empty phantom that doesn't really show up in the argument list. (that's still probably a bug)
bug2.m:
function bug2(arg1, arg2)
disp(sprintf('number of arguments = %d\narg1 = ', nargin));
disp(arg1);
test case:
>> nothing = struct('something',{})
nothing =
0x0 struct array with fields:
something
>> bug2(nothing,'there')
number of arguments = 2
arg1 =
>> bug2(nothing.something,'there')
number of arguments = 1
arg1 =
there
This behaviour persists in 2008b, and is in fact not really a bug (although i wouldn't say the designers intended for it):
When you step into add_something(S,'boing') and watch the first argument (say by selecting it and pressing F9), you'd get some output relating to the empty structure S.
Step into add_something(S.something,'test') and watch the first argument, and you'd see it's in fact interpreted as 'test' !
The syntax struct.fieldname is designed to return an object of type 'comma separated list'. Functions in matlab are designed to receive an object of this exact type: the argument names are given to the values in the list, in the order they are passed. In your case, since the first argument is an empty list, the comma-separated-list the function receives starts really at the second value you pass - namely, 'test'.
Output is identical in R2008b:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test'); % weird behavior

How can I count the number of properties in a structure in MATLAB?

I have a function that returns one or more variables, but as it changes (depending on whether the function is successful or not), the following does NOT work:
[resultA, resultB, resultC, resultD, resultE, resultF] = func(somevars);
This will sometimes return an error, varargout{2} not defined, since only the first variable resultA is actually given a value when the function fails. Instead I put all the output in one variable:
output = func(somevars);
However, the variables are defined as properties of a struct, meaning I have to access them with output.A. This is not a problem in itself, but I need to count the number of properties to determine if I got the proper result.
I tried length(output), numel(output) and size(output) to no avail, so if anyone has a clever way of doing this I would be very grateful.
length(fieldnames(output))
There's probably a better way, but I can't think of it.
It looks like Matthews answer is the best for your problem:
nFields = numel(fieldnames(output));
There's one caveat which probably doesn't apply for your situation but may be interesting to know nonetheless: even if a structure field is empty, FIELDNAMES will still return the name of that field. For example:
>> s.a = 5;
>> s.b = [1 2 3];
>> s.c = [];
>> fieldnames(s)
ans =
'a'
'b'
'c'
If you are interested in knowing the number of fields that are not empty, you could use either STRUCTFUN:
nFields = sum(~structfun(#isempty,s));
or a combination of STRUCT2CELL and CELLFUN:
nFields = sum(~cellfun('isempty',struct2cell(s)));
Both of the above return an answer of 2, whereas:
nFields = numel(fieldnames(s));
returns 3.