Matlab: create objects with source information - matlab

I am loading a file ...
obj = load('foo1.txt');
% obj is a double array of size (NY,NX)
However, there are many such files and I wish to parse then save them in an array
asdf = zeros(1, numObjs);
for index = 1:numObjs
obj = load(sprintf(foo%d.txt,index));
asdf(index) = obj;
end
In this case, the procedure fails since the number of objects in asdf(i), namely the size of i ... which is one ~= the size of obj ... sizeof(obj).
I tried fooling around with a struct, but couldn't find a suitable solution.
Thanks.

You can use a cell array instead:
asdf{numObjs} = []; % intialises; does not preallocate memory for cell contents
for index = 1:numObjs
asdf{index} = load(sprintf(foo%d.txt,index));
end

Related

Matlab generate variable names when subdividing large data [duplicate]

This question already has answers here:
matlab iterative filenames for saving
(4 answers)
Closed 2 years ago.
I have a large data set (vector) I want to split up in to n smaller sets to look at later with other scripts. I.e.if n = 10 I want to turn one 1x80000000 double in to ten 1x8000000 doubles. My thoughts are turn the original in to a n by m matrix then save each row of the matrix in to it's own vector, as follows.
%data-n-splitter
n = 10 %number of sections
L = length(data);
Ls = L/n;
Ls = floor(Ls);
Counter = 1;
%converting vector to matrix
datamatrix = zeros(n,Ls);
for k = 1:n
datamatrix(k,:) = data(Counter:Counter+ Ls - 1);
Counter = Counter + Ls;
end
How do I make matlab loop this part of the code n times:
%save each row of matrix as seperate vector
P1 = datamatrix(1,:);
P2 = datamatrix(2,:);
P3 = datamatrix(3,:);
P4 = datamatrix(4,:);
P5 = datamatrix(5,:);
P6 = datamatrix(6,:);
P7 = datamatrix(7,:);
P8 = datamatrix(8,:);
P9 = datamatrix(9,:);
P10 = datamatrix(10,:);
Example answer that I'm hoping for:
for k = 1:n
P('n') = datamatrix(n,:);
end
I've seen some articles about using cell arrays but the scripts I'm passing the variables to aren't set up for this so I'd rather not go down that route if possible.
There are several options:
use a struct, which comes closest to what you are hoping for,
use a cell, more convenient looping but no access over meaningful names,
use a higher-dimension matrix (in your case it is only 2D, but the same applies for 3D or higher). This is the most memory-efficient option.
To round this off, you could also use a table, which is a hybrid of a struct and a cell as you can use both notations to access it. There is no other benefit.
Now, how to do this? The simplest (and best) solution first: create a 2D matrix with reshape
Ary = 1:10; % I shrank your 1x80000000 array to 1x10 but you'll get the idea
%% create new structure
Mat = reshape(Ary,5,2);
%% access new structure (looping over columns)
for i = 1:size(Ary,2)
% access columns through slicing
ary_sct = Mat(:,i);
% do something
end
Pro: memory efficient (requires the same amount of memory as the initial array); easy looping
Con: only works if you can slice the initial array evenly
Next: create a cell
Ary = 1:10;
n = 2; % number of sections
L = floor(length(Ary)/n);
% allocate memory
C = cell(1,n);
%% create new structure
for i = 1:n
% access the content of a cell with {}
C{i} = Ary((i-1)*L+1:i*L);
end
%% access new structure (looping over entries)
for i = 1:length(C)
% access the content of a cell with {}
ary_sct = C{i};
% do something
end
Pro: You can store anything in a cell. Every data type and -- what is often more important -- of any dimension
Con: The accessing the content (through {}) or accessing the element (through ()) is a bit annoying if your are a beginner; each element require a memory overhead of about 60 bytes as those are pointers, which need to store the information where and on what they are pointing.
Next: use a struct
Ary = 1:10;
n = 2; % number of sections
L = floor(length(Ary)/n);
% create empty struct
S = struct();
%% create new structure
for i = 1:n
% create fieldname (must start with a character!)
fld = num2str(i,'F%d');
% write to field (note the brackets)
S.(fld) = Ary((i-1)*L+1:i*L);
end
%% access new structure (looping over fieldnames)
% get all field names
FlNms = fieldnames(S);
for i = 1:length(FldNames)
% access field names (this is a cell!)
fld = FldNms{i};
% access struct
ary_sct = S.(fld);
% do something
end
Pro: Field names are convenient to keep the overview of your data
Con: accessing field names in a loop is a bit tedious; each element require a memory overhead of about 60 bytes as those are pointers, which need to store the information where and on what they are pointing.

Put several values into 1 cell (e.g. array{1} = [1,2,3]) for multiple condition SPM analysis; All I get is array{1} = [1] [2] [3]

I'm working to get a 1st level analysis completed on some fMRI data, and as it's my first time using SPM in this way, it seems as though there is no end to my frustrations. SPM includes these specific instructions:
"This *.mat file must include the following cell arrays (each 1 x n): names, onsets, and durations. eg. names=cell(1,5), onsets=cell(1,5), durations=cell(1,5), then names{2}="Second condition", onsets{2}=[3,5,19,22],durations{2}=[0,0,0,0], contain the required details of the second condition."
The code I'm using grabs the data I need from the various excel files the behavioral data is stored in, and adds them to these cell arrays.
sessionFiles = dir('*.xlsx');
allNames = {sessionFiles.name}';
conditions = 36;
% go through excel files to grab relevant column information for SPM
for i=1:length(sessionFiles)
[~,fileName,~] = fileparts(allNames{i});
% initialize cells SPM needs
names = cell(1,conditions);
onsets = cell(1,conditions);
durations = {1.75};
durations = repmat(durations,1,conditions);
% read in excel file
[num,~,~] = xlsread(sessionFiles(i).name);
trialType = num(:,6);
% grab condition information from columns: seconds=9, name=6
for j=1:conditions
index = find(trialType==j);
trialOnsets = cell(1,length(index));
names{1,j} = j;
for k=1:length(index)
trialOnsets{1,k}=double(num(index(k),9));
end
onsets{1,j} = trialOnsets;
end
% save new data for SPM
save(fileName,'names','onsets','durations');
clear names onsets durations fileName num raw text
end
I found an example which shows each cell should look like this:
I just can't figure out how to grab the numbers automatically and put them in cells like that.
I know this isn't the SPM forums, but I've seen a few questions posted and I thought I would try my luck.
With the line trialOnsets = cell(1,length(index));, trialOnsets is specified as a cell array of size 1xlength(index). Then, trialOnsets is assigned to onsets{1,j}. With this workflow, each cell of onsets will be of size 1xlength(index).
Instead, each cell of onsets should be of size 1x1 and each 1x1 cell in onsets should have a matrix of size 1xlength(index). To do this, do the following.
Specify trialOnsets as a matrix, instead of as a cell array. To do this, replace trialOnsets = cell(1,length(index)); with trialOnsets = zeros(1,length(index));.
Assign the values from num to trialOnsets, which is now a matrix (previously was a cell array). To do this, replace trialOnsets{1,k}=double(num(index(k),9)); with trialOnsets(1,k)=double(num(index(k),9));.
The edited code should be as follows:
sessionFiles = dir('*.xlsx');
allNames = {sessionFiles.name}';
conditions = 36;
% go through excel files to grab relevant column information for SPM
for i=1:length(sessionFiles)
[~,fileName,~] = fileparts(allNames{i});
% initialize cells SPM needs
names = cell(1,conditions);
onsets = cell(1,conditions);
durations = {1.75};
durations = repmat(durations,1,conditions);
% read in excel file
[num,~,~] = xlsread(sessionFiles(i).name);
trialType = num(:,6);
% grab condition information from columns: seconds=9, name=6
for j=1:conditions
index = find(trialType==j);
trialOnsets = zeros(1,length(index));
names{1,j} = j;
for k=1:length(index)
trialOnsets(1,k)=double(num(index(k),9));
end
onsets{1,j} = trialOnsets;
end
% save new data for SPM
save(fileName,'names','onsets','durations');
clear names onsets durations fileName num raw text
end
I could not test this code, since there was no sample data. Let me know if this works for you.

Canonical Way to Aggregate Structures into a Vector

I feel dumb even having to ask this, it really should be dead simple, but being new to MatLab I'd like to know how a more experienced person would do it.
Simple problem; I need to find some regions in multiple images, correlate them by position, save those regions of interest, and use them later. One way to do that would be to store the regions in a vector.
%% pseudo code
regions = [];
for i = some_vector_of_images
% segment, get mask
% find regions
cc = bwconncomp(mask);
stats = regionprops(cc, 'all');
% correlate against known x/y
% save for later
regions[index++] = stats;
end
% use 'regions'
However, the array declaration is problematic. Its default type is double, so that won't work (can't assign a struct to an element). I've tried struct.empty, but the array is not resizable. I've tried a cell array, but I get a similar error (Conversion to cell from struct is not possible.)
Really, I just need a way to have some collection declared prior to the loop that will hold instances of these structures. Again, pretty noobish question and slightly embarrassed here... please take pity.
See if using struct2cell helps you with this. Give this pseudo-code a try -
regions = cell(num_of_images,1) %// This will be before the loop starts
...
regions[index++] = {struct2cell(stats)} %// Inside the loop
Please not that this a pseudo-code, so square brackets and ++ won't work.
Thus, the complete version of pseudo-code would be -
%%// --- pseudo code
%// Without this pre-allocation you would get the error -
%%// "Conversion to cell from struct is not possible"
regions = cell(numel(some_vector_of_images),1)
for i = some_vector_of_images
% segment, get mask
% find regions
cc = bwconncomp(mask);
stats = regionprops(cc, 'all');
% correlate against known x/y
% save for later
regions(i) = {struct2cell(stats)}
end
You can cast your empty array to a structure array by appending a structure. Replace regions[index++] = stats; with
regions = [regions, stats];
This line will continue to build the array within the loop. This idiom is generally frowned on in MATLAB because a new array needs to be created each loop.
Another method is to preallocate the array with a template structure, using repmat.
stats = some_operations_on(some_vector_of_images(1));
regions = repmat(stats, numel(some_vector_of_images), 1);
and within the loop, assign with
regions(i) = stats;
In this scenario, typically I just don't preallocate at all, or use a cell-cat pattern.
Not initializing
This one doesn't initialize the struct array, but works fine. Make sure i is an index of each element in this case.
for i = 1:numel(some_vector_of_images)
% mask = outcome of some_vector_of_images(i)
cc = bwconncomp(mask);
regions(i) = regionprops(cc, 'all');
end
cell-cat pattern
This one catches results in a cell array, and concatenates all elements at the end.
regions = cell(numel(some_vector_of_images), 1);
index = 1;
for i = some_vector_of_images
% mask = outcome of i
cc = bwconncomp(mask);
regions{index} = regionprops(cc, 'all');
index = index + 1;
end
regions = cat(1, regions{:});

Loading multiple datasets without overwriting variable

I have a folder containing a number of files, named:
filename_1.mat
filename_2.mat
.
.
.
filename_n.mat
Each file contains a dataset named Var, with identical columns. I want to load all these datasets into the workspace and use vertcat() to vertically concatenate them, but when I load them in a for loop I only get the last dataset since the variable Var is overwritten. These datasets were created in a for loop:
% generate filenames
tss = arrayfun(#(x){sprintf('filename_%d',x)},1:(length(1:3)))';
namerr = cell((length(1:3)),1);
namerr(:,1) = {'E:\FILES\'};
file_names = strcat(namerr,tss,'.mat');
% create datasets and save them to E:\FILES
for ii = 1:3
a = rand(1,5)';
b = rand(1,5)';
Var = dataset({[a,b],'a_name','b_name'});
save(file_names{(ii)},'Var','-v6')
end
% Now read these datasets into workspace and concatenate vertically??
% Is there a way for me to name the datasets `Var_1...Var_n`
% so they are not overwritten?
Sure. You can load the data into a variable, and then access the contents of a file as fields in the variable. Starting with your example, this would look something like this:
loadedData_1 = load(file_names{1})
loadedData_2 = load(file_names{2})
loadedData_3 = load(file_names{3})
mergedData = [...
loadedData_1.Var; ...
loadedData_2.Var; ...
loadedData_3.Var ];
You can clean this up by using a loop:
for ix = 3:-1:1 %Load all data, backwards to force preallocation
loadedData(ix) = load(file_names{ix});
end
mergedData = cat(1,loadedData.Var);
Or if you really want to go over the top I think you can do it in one long line using arrayfun, but that's probably going over the top.
It would be far easier to just do it directly in the loop:
...
Varcat = [];
for ii = 1:3
a = rand(1,5)';
b = rand(1,5)';
Var = dataset({[a,b],'a_name','b_name'});
Varcat = [Varcat; Var];
save(file_names{(ii)},'Var','-v6')
end
Var = Varcat;
In case you actually want to do it much later or in another part of the program, hopefully it's clear how to adapt the same approach for a similar loop with load().

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