When loading data from a .Mat file directly into a variable, it stores an struct instead of the variable itself.
Example:
myData.mat contains var1, var2, var3
if I do:
load myData.mat
it will create the variables var1, var2 and var3 in my workspace. OK.
If I assign what load returns to a variable, it stores an struct. This is normal since I'm loading several variables.
foo = load('myData.mat')
foo =
struct with fields:
var1
var2
var3
However suppose that I'm only interested in var1 and I want to directly store into a variable foo.
Load has an option of loading only specific variables from a .mat file, however it still stores an struct
foo = load('myData.mat', 'var1')
foo =
struct with fields:
var1
I want var1 to be directly assigned to foo.
Of course I can do:
foo = load('myData.mat', 'var1')
foo = foo.var1;
But it should be a way of doing this automatically in one line right?
If the MAT-file contains one variable, use
x = importdata(mat_file_name)
load does not behave this way otherwise load would behave inconsistently depending upon the number of variables that you have requested which would lead to an extremely confusing behavior.
To illustrate this, imagine that you wrote a general program that wanted to load all variables from a .mat file, make some modification to them, and then save them again. You want this program to work with any file so some files may have one variable and some may have multiple variables stored in them.
If load used the behavior you've specified, then you'd have to add in all sorts of logic to check how many variables were stored in a file before loading and modifying it.
Here is what this program would look like with the current behavior of load
function modifymyfile(filename)
data = load(filename);
fields = fieldnames(data);
for k = 1:numel(fields)
data.(fields{k}) = modify(data.(fields{k}));
end
save(filename, '-struct', 'data')
end
If the behavior was the way that you think you want
function modifymyfile(filename)
% Use a matfile to determine the number of variables
vars = whos(matfile(filename));
% If there is only one variable
if numel(vars) == 1
% Assign that variable (have to use eval)
tmp = load(filename, vars(1).name);
tmp = modify(tmp);
% Now to save it again, you have to use eval to reassign
eval([vars(1).name, '= tmp;']);
% Now resave
save(filename, vars(1).name);
else
data = load(filename);
fields = fieldnames(data);
for k = 1:numel(fields)
data.(fields{k}) = modify(data.(fields{k}));
end
save(filename, '-struct', 'data');
end
end
I'll leave it to the reader to decide which of these is more legible and robust.
The best way to do what you're trying to do is exactly what you've shown in your question. Simply reassign the value after loading
data = load('myfile.mat', 'var1');
data = data.var1;
Update
Even if you only wanted the variable to not be assigned to a struct when a variable was explicitly specified, you'd still end up with inconsistent behavior which would make it difficult if my program accepted a list of variables to change as a cell array
variables = {'var1', 'var2'}
data = load(filename, variables{:}); % Would yield a struct
variables = {'var1'};
data = load(filename, variables{:}); % Would not yield a struct
#Suever is right, but in case you wish for a one-line workaround this will do it:
foo = getfield(load('myData.mat'), 'var1');
It looks ugly but does what you want:
foo = subsref(matfile('myData.mat'),struct('type','.','subs','var1'))
Use matfile allows partial loading of variables into memory i.e. it only loads what is necessary. The function subsref does the job of the indexing operator "." in this case.
Related
I'm new to MATLAB, and I can't manage to make my function work in order to save my data into a .mat file.
The input:
A structure, with 5 fields:
data: 3D matrix of 19x1000x143
labels: 1x143 matrix with 1 or -1 in it
subject_number: an integer
sampling_rate: an integer, 500 Hz
channel_names: 1x19 matrix with text in it
name: a string for the name of the file
clean: a matrix 1x143 with 1 or 0 in it.
The idea is to save only the clean data, marked as 1 in the clean matrix.
If clean(i) is equal to 1:
save data(:,:,i) and labels(:,i)
This is the code I've tried to implement in the saving.m file:
function saving(EEG_struct, clean, name)
subject_number = EEG_struct.subject_number;
fs = EEG_struct.sampling_rate;
chan_names = EEG_struct.channel_names;
nb_epoch = size(EEG_struct.data, 3);
for j=1:nb_epoch
if clean(j) == 1
% Keep the epoch and label
data = cat(3, data, EEG_struct.data(:,:,j));
labels = cat(2, labels, EEG_struct.labels(:,j));
end
end
save(name, data, labels, subject_number, fs, chan_names)
As you can see, I would like to save the data as a structure with the same shape as the EEG_struct input.
Moreover, I would like to use a parfor instead of a for, but it raised me an error I didn't quite get:
An UndefinedFunction error was thrown on the workers for 'data'. This might be because the file containing 'data' is not accessible on the workers. Use addAttachedFiles(pool, files) to specify the required files to be attached. See the documentation for 'parallel.Pool/addAttachedFiles' for more details. Caused by: Undefined function or variable 'data'.
Thanks for the help !
You can use your clean variable as a logical index and parse out your data and labels at once. So there is no need for a loop.
Also the save command needs the "names" of the vars to save not the variables themselves. So I just put ' ' around each one.
function saving(EEG_struct, clean, name)
subject_number = EEG_struct.subject_number;
fs = EEG_struct.sampling_rate;
chan_names = EEG_struct.channel_names;
nb_epoch = size(EEG_struct.data, 3);
%No need for a loop at all
data = EEG_struct.data(:,:,logical(clean));
labels = EEG_struct.labels(logical(clean)); %This is a 1xN so I removed the extra colon operator
save(name, 'data', 'labels', 'subject_number', 'fs', 'chan_names');
EDIT:
Per you comment if you want to just leave everything in the structure. I gave you 2 options for how to save it.
function saving(EEG_struct, clean, name)
%Crop out ~clead data
EEG_struct.data = EEG_struct.data(:,:,logical(clean));
EEG_struct.labels = EEG_struct.labels(logical(clean)); %This is a 1xN so I removed the extra colon operator
% Option 1
save(name, 'EEG_struct');
% Option2
save(name, '-struct', 'EEG_struct');
Option 1 will directly save the struct to the MAT file. So if you were to load the data back like this:
test = load(name);
test =
EEG_struct: [1x1 struct]
You would get your structure placed inside another structure ... which might not be ideal or require an extra line to de-nest it. On the other hand just loading the MAT file with no outputs load(name) would put EEG_struct into your current workspace. But if in a function then it sort of springs into existence without every being declared which makes code a bit harder to follow.
Option 2 uses the '-struct' option which breaks out each field automatically into separate vars in the MAT file. So loading like this:
EEG_struct = load(name);
Will put all the fields back together again. To me at least this looks cleaner when done within a function but is probably just my preference
So comment out which ever you prefer. Also, not I did not include clean in the save. You could either append it to the MAT or add it to your structure.
To get a structure the same as EEG_struct but with only the data/labels corresponding with the clean variable, you can simply make a copy of the existing structure and remove the rows where clean=0
function saving(EEG_struct, clean, name)
newstruct = EEG_struct;
newstruct.data(:,:,logical(~clean)) = '';
newstruct.labels(logical(~clean)) = '';
save(name,'newstruct');
I am trying to assign the field values of structure in loop.
Structure declaration with empty values:
result_struct = struct('a',{},'b',{},'c',{},'d',{})
I am assigning values in loop like that:
% assume a, b, c, d are variables in my workspace
% field names match with the variable names
for index=1:n
% some computation and store results in variables (a-d)
result_struct(index).a = a;
result_struct(index).b = b;
result_struct(index).c = c;
result_struct(index).d = d;
end
How can I assign the values to the fields using another loop? Like that:
for fname = fieldnames(result_struct)'
result_struct(index).fname = fname; % field names and variable names match
end
You need to use dynamic field names to assign to the struct (the leff-hand side). For the right hand side you could use eval but that is dangerous, so it's better to save your variable fname to a file and then load it back in as a struct prior to accessing fname, again using dynamic field names.
names = fieldnames(result_struct);
for k = 1:numel(names)
% Save variable to a file
save('tmp.mat', names{k});
% Load it back into a struct
tmp = load('tmp.mat', names{k});
result_struct(index).(names{k}) = tmp.(names{k});
end
Alternately, you can use the save and load to just transform the entire thing into a struct without having to loop through the fields.
fields = fieldnames(result_struct);
% Save all relevant variables to a file
save('tmp.mat', fields{:});
% Load it back into the result_struct
result_struct(index) = orderfields(load('tmp.mat'), fields);
I have a long list of variables in my workspace.
First, I'm finding the potential variables I could be interested in using the who function. Next, I'd like to loop through this list to find the size of each variable, however who outputs only the name of the variables as a string.
How could I use this list to refer to the values of the variables, rather than just the name?
Thank you,
list = who('*time*')
list =
'time'
'time_1'
'time_2'
for i = 1:size(list,1);
len(i,1) = length(list(i))
end
len =
1
1
1
If you want details about the variables, you can use whos instead which will return a struct that contains (among other things) the dimensions (size) and storage size (bytes).
As far as getting the value, you could use eval but this is not recommended and you should instead consider using cell arrays or structs with dynamic field names rather than dynamic variable names.
S = whos('*time*');
for k = 1:numel(S)
disp(S(k).name)
disp(S(k).bytes)
disp(S(k).size)
% The number of elements
len(k) = prod(S(k).size);
% You CAN get the value this way (not recommended)
value = eval(S(k).name);
end
#Suever nicely explained the straightforward way to get this information. As I noted in a comment, I suggest that you take a step back, and don't generate those dynamically named variables to begin with.
You can access structs dynamically, without having to resort to the slow and unsafe eval:
timestruc.field = time;
timestruc.('field1') = time_1;
fname = 'field2';
timestruc.(fname) = time_2;
The above three assignments are all valid for a struct, and so you can address the fields of a single data struct by generating the field strings dynamically. The only constraint is that field names have to be valid variable names, so the first character of the field has to be a letter.
But here's a quick way out of the trap you got yourself into: save your workspace (well, the relevant part) in a .mat file, and read it back in. You can do this in a way that will give you a struct with fields that are exactly your variable names:
time = 1;
time_1 = 2;
time_2 = rand(4);
save('tmp.mat','time*'); % or just save('tmp.mat')
S = load('tmp.mat');
afterwards S will be a struct, each field will correspond to a variable you saved into 'tmp.mat':
>> S
S =
time: 1
time_1: 2
time_2: [4x4 double]
An example writing variables from workspace to csv files:
clear;
% Writing variables of myfile.mat to csv files
load('myfile.mat');
allvars = who;
for i=1:length(allvars)
varname = strjoin(allvars(i));
evalstr = strcat('csvwrite(', char(39), varname, '.csv', char(39), ', ', varname, ')');
eval(evalstr);
end
I need to output .mat files for the below data. I need one file to have cell (1,1) to be Mean_RPM_list1, cell (2,1) to be Mean_RPM_list2 etc. And then I need another file to have cell(1,1) to be Mean_Torque_list1 to have cell(1,1).....and so on.
Can anybody shed any light on this for me?
Also if someone knows how to automate me calling the matrices A and B so I could have A = [Mean_rpm1:Mean_rpmMAX], that would also be very helpful.
TIA for any help.
A = [Mean_rpm1 Mean_rpm2 Mean_rpm3 Mean_rpm4 Mean_rpm5 Mean_rpm6 Mean_rpm7 Mean_rpm8 Mean_rpm9 Mean_rpm10 Mean_rpm11 Mean_rpm12];
B = [Mean_torque1 Mean_torque2 Mean_torque3 Mean_torque4 Mean_torque5 Mean_torque6 Mean_torque7 Mean_torque8 Mean_torque9 Mean_torque10 Mean_torque11 Mean_torque12];
plot(A,B,'*')
for i = 1:num_bins;
bin = first + ((i-1)/10);
eval(sprintf('Mean_RPM_list%0.f = A;',bin*10));
eval(sprintf('Mean_Torque_list%0.f = B;',bin*10));
end
First of all this is really bad idea to create a set of variables with names different by numbers. As you can see it's very difficult to deal with such variables, you always have to use eval (or other related) statements.
It's much easier to create a cell array Mean_rpm and access its elements as Mean_rpm{1}, etc.
If the vectors are numeric and have the same size you can also make a 2D/3D array. Then access as Mean_rpm(:,:,1) etc.
Next, to store a cell array to a mat-file you have to create this array in MATLAB. No options (at least for now) to do it by parts in a loop. (But you can do it for numeric vectors and matrices using matfile object.) So why do you need this intermediate Mean_RPM_list variable? Just do Mean_RPM_list{bin*10} = A in your loop.
For your first question, if you already have those variables you have to use eval in a loop. Something like
A = [];
for k=1:K
eval(sprintf('A{k} = [A, Mean_rpm%d];',k));
end
You can also get names for all similar variables and combine them.
varlist = who('Mean_rpm*');
A = cell(1,numel(varlist);
for k = 1:numel(varlist)
eval('A{k} = varlist{k};');
end
Here is one without loop using CELL2FUN:
A=cellfun(#(x)evalin('base',x),varlist,'UniformOutput',0);
You should avoid having all these individual variables around in the first place. Data types like arrays, cell arrays and structure arrays exist to help you with this. If you want each variable to be associated with a name, you can use a structure array. I've made an example below. Instead of assigning a value to Mean_rpm1 like you are doing now, assign it to meanStruct.Mean_rpm1 then save the entire structure.
% as you generate values for each variable, assign them to the
% appropriate field.
meanStruct.Mean_rpm1 = [10:10];
meanStruct.Mean_rpm2 = [12:15];
meanStruct.Mean_rpm3 = [13:20];
meanStruct.Mean_rpm4 = [14];
meanStruct.Mean_rpm5 = [15:18];
meanStruct.Mean_rpm6 = [16:20];
meanStruct.Mean_rpm7 = [17:22];
meanStruct.Mean_rpm8 = [18:22];
meanStruct.Mean_rpm9 = [19:22];
meanStruct.Mean_rpm10 = [20:22];
meanStruct.Mean_rpm11 = [21:22];
meanStruct.Mean_rpm12 = [22:23];
% save the structure array
save('meanValues.mat','meanStruct')
% load and access the structure array
clear all
load('meanValues.mat')
temp = meanStruct.Mean_rpm3
Due to legacy function calls I'm sometimes forced to write ugly wrappers like this
function return = someWrapper(someField)
a = someField.a;
b = someField.b;
% and so on, realistically it's more like ten variables that
% could actually be grouped in a struct
save('params.mat', 'a', 'b'); %etc.
% then, on another machine, a function loads params.mat, does the calculations
% and saves the result in result.mat containing the variables c,d,...
load('result.mat', 'c', 'd');
return.c = c;
return.d = d;
% again, it's more than just two return values
So the basic idea is to create variables with the same names as someField's fieldnames, run a function and create a return structure using someFunction's return variable's names as fieldnames.
Is there some way simplify this using some loop e.g. over fieldnames(someField)?
Or should I actually use some different approach? Since some further processing is done with someField and result I'd like to keep using structs, but maybe a second question would be
Can save and load redirect varibale names? I.e. could e.g. the variable a in params.mat be stored using someField.a as value instead of having to assign a = someField.a first?
Why not something like this?
if this is s:
s.a=1
s.b=2
s.c=3
Then this command creates a matfile named "arguments" with variables a, b, c:
save arguments.mat -struct s
And this command loads a matfiles variables into a structure
r = load('arguments.mat')
How about using ASSIGNIN and dynamic fieldnames to loop over the structure fields and create the appropriate variables in the workspace:
function struct2base(s)
for f = fieldnames(s)'
assignin('base', f{:}, s.(f{:}))
end
Have a look at the deal() function.