How to Concatenate multiples variables with different size using Matlab ? - matlab

I have a multiple variables of different size : A1xB1 , A2xB2, A3xB3, ...
I would like to put them all in one VOLUME something like AxBxC.
Let's suppose I can take values of size AixBi.
I found that the following loop :
for ...
Volume = cat(3,Volume,I)
endfor
can concatenate I and produce VOLUME in case I are of the same size.
But What can I do when I can take different sizes ?

You can only use cat to concatenate arrays of the same size, since the resulting array has to be a proper array of size n1 x n2 x n3. Since in comments you told us that padding your variables is not an option, you have to use a cell array, each element of which will correspond to one of your matrices.
You can use a loop,
C = cell(1,nmats); %nmats number of arrays to concatenate
for n=1:nmats
C{n} = ...; %your n-th array goes here
end
Or for a pre-defined small number of arrays you can also call
%C = cell(1,nmats);
%[C{:}] = deal(arr_1,arr_2,...*add variables here*...,arr_nmats);
C = {arr_1,arr_2,...*add variables here*...,arr_nmats};
I commented out my original version, which works, but is needlessly complicated. However, the approach of deal would be useful for reversing your concatenation:
[arr_1,arr_2,...*add variables here*...,arr_nmats] = deal(C{:});
to the same effect.

Related

In an assignment A(I) = B, the number of elements in B and I must be the same

This is my code in Matlab: How could I get all values of all 5 images saved? This code only returns the last image! I tried using IM(l) but it gives me an error: In an assignment A(I) = B, the number of elements in B and I must be the same.
Amount_measurements = 5;
IM=zeros(2097152,1);
l=1;
for l=(1:Amount_measurements)
if l < 9
%index = double(0)+double(0)+double(l+1);
index = strcat(num2str(double(0)),num2str(double(0)),num2str(double(l+1)));
elseif l < 99
index = double(0)+double(l+1);
else
index = double(l+1);
end
file_name1='trial.nii.gz';
%disp(file_name1);
jesu=load_nii(file_name1);
[x,y,z] = meshgrid(1:256,1:256,1:256);
[lx,ly,lz] = meshgrid(1:2:256,1:2:256,1:2:256);
newImage = interp3(x,y,z,jesu.img,lx,ly,lz);
IM= newImage(:);
end
I want the values newImage(:) to be stored as IM1=newImage(:) IM2=newImage(:) IM3=newImage(:) IM4=newImage(:) so on... How could I go about with it?
Since you mentioned wanting a variable-length version of IM1=newImage(:) IM2=newImage(:) IM3=newImage(:) IM4=newImage(:), you're looking for a cell array. Try
IM{l} = newImage;
instead of
IM(l) = newImage(:);
The important difference is the use of braces rather than parentheses. Use a right-hand side ofnewImage(:) if you want to reshape into a vector, just newImage if you want to preserve it as a matrix.
By using IM(l) you're trying to add an entire column vector (newImage(:)) to a single element (the l-th element) in the array IM, that's why Matlab throws the error.
You should consider concatenation: since newImage(:) is a column-vector, replace
IM= newImage(:);
with
IM=[IM newImage(:)];
but at the top of the script you should also initialize IM as
IM=[];
At the end of the loop, the resulting IM will have Amount_measurements columns where 1 column = 1 newImage(:).
Note #1: this will only work if newImage(:) always has the same length.
Note #2: if you know a priori how long the vector newImage(:) is and, again, by assuming that its length never changes, you should consider preallocating the IM matrix by replacing IM=[]; with IM=zeros(X,Amount_measurements); where X is the number of elements in newImage(:). Finally, regarding the concatenation stage, you should replace IM=[IM newImage(:)]; with IM(:,l)=newImage(:).
Note #3: as instead, if the size of newImage(:) can change you cannot rely on preallocation and matrices, but you must use cell arrays: the last instruction in your loop should be IM{l}=newImage(:);.

Storing each iteration of a loop in Matlab

I have a 2d matrix (A=80,42), I am trying to split it into (80,1) 42 times and save it with a different name. i.e.
M_n1, M_n2, M_n3, … etc (representing the number of column)
I tried
for i= 1:42
M_n(i)=A(:,i)
end
it didn't work
How can I do that without overwrite the result and save each iteration in a file (.txt) ?
You can use eval
for ii = 1:size(A,2)
eval( sprintf( 'M_n%d = A(:,%d);', ii, ii ) );
% now you have M_n? var for you to process
end
However, the use of eval is not recommanded, you might be better off using cell array
M_n = mat2cell( A, [size(A,1)], ones( 1, size(A,2) ) );
Now you have M_n a cell array with 42 cells one for each column of A.
You can access the ii-th column by M_n{ii}
Generally, doing if you consider doing this kind of things: don't.
It does not scale up well, and having them in one array is usually far more convenient.
As long as the results have the same shape, you can use a standard array, if not you can put each result in a cell array eg. :
results = cell(nTests,1)
result{1} = runTest(inputs{1})
or even
results = cellfun(#runTest,inputs,'UniformOutput',false); % where inputs is a cell array
And so on.
If you do want to write the numbers to a file at each iteration, you could do it without the names with csvwrite or the like (since you're only talking about 80 numbers a time).
Another option is using matfile, which lets you write directly to a variable in a .mat file. Consult help matfile for the specifics.

Using loops to get multiple values into a cell

I have 31 subjects (S1, S2, S3, S4, etc.). Each subject has 3 images, contrast1.img, contrast2.img, and contrast3.img. I would like to use a loop to get all paths to the contrasts from all the subjects into a nx1 cell called P. P should be something like this:
Data/S1/contrast1.img
Data/S1/contrast2.img
Data/S1/contrast3.img
Data/S2/contrast1.img
Data/S2/contrast2.img
Data/S2/contrast3.img
...
Data/S31/contast3.img
This is what I've tried:
A={'S1','S2','S3',...,'S31'}; % all the subjects
C={'contrast1.img','contrast2.img','contrast3.img'}; % contrast images needed for each subject
P=cell(31*3,1)
for i=1:length(A)
for j=1:length(C)
P{j}=spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j)))); % this is to select the three contrast images for each subject. It works in my script. It might not be 100% correct here since I had to simplify for this example.
end
end
This, however, only give me P with the 3 contrast images of the last subject. Previous subjects get overwritten. This indicates that the loop is wrong but I'm not sure how to fix it. Could anyone help?
No loop needed. Use ndgrid to generate the combinations of numbers, num2str with left alignment to convert to strings, and strcat to concatenate without trailing spaces:
M = 31;
N = 3;
[jj ii] = ndgrid(1:N, 1:M);
P = strcat('Data/S',num2str(ii(:),'%-i'),'/contrast',num2str(jj(:),'%-i'),'.img')
I would use a cell matrix, which directly represents the subject index and the contrast index.
To preallocate use P=cell(length(A),length(C)) and to fill it use P{i,j}=...
When you want to access the 3rd image of the 5th subject, use P{5,3}
The problem is where you assign P{j}.
Since j only loops 1:3 and doesn't care about i, you are just rewriting all three values for P{j}. I think you want to concatenate the new values to the cell array instead
for i=1:length(A)
for j=1:length(C)
P ={P; spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));}
end
end
or you could assign each value directly such as
for i=1:length(A)
for j=1:length(C)
P{3*(i-1)+j} =spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));
end
end

Create a matrix combining many variables by using their names and a for loop

Suppose I have n .mat files and each are named as follows: a1, a2, ..., an
And within each of these mat files there is a variable called: var (nxn matrix)
I would like to create a matrix: A = [a1.var a2.var, ..., an.var] without writing it all out because there are many .mat files
A for-loop comes to mind, something like this:
A = []
for i = 1:n
[B] = ['a',num2str(i),'.mat',var];
A = [A B]
end
but this doesn't seem to work or even for the most simple case where I have variables that aren't stored as a(i) but rather 'a1', 'a2' etc.
Thank you very much!
load and concatenate 'var' from each of 'a(#).mat':
n = 10;
for i = n:-1:1 % 1
file_i = sprintf('a%d.mat', i); % 2
t = load(file_i, 'var');
varsCell{i} = t.var; % 3
end
A = [varsCell{:}]; % concatenate each 'var' in one step.
Here are some comment on the above code. All the memory-related stuff isn't very important here, but it's good to keep in mind during larger projects.
1)
In MATLAB, it is rarely a good idea or necessary to grow variables during a for loop. Each time an element is added, MATLAB must find and allocate a new block of RAM. This can really slow things down, especially for long loops or large variables. When possible, pre-allocate your variables (A = zeros(n,n*n)). Alternatively, it sometimes works to count backwards in the loop. MATLAB pre-allocates the whole array, since you're effectively telling it the final size.
2)
Equivalent to file_i = ['a',num2str(i),'.mat'] in this case, sprintf can be clearer and more powerful.
3)
Store each 'var' in a cell array. This is a balance between allocating all the needed memory and the complication of indexing into the correct places of a preallocated array. Internally, the cell array is a list of pointers to the location of each loaded 'var' matrix.
to create a test set...
generate 'n' matrices of n*n random doubles
save each as 'a(#).mat' in current directory
for i = 1:n
var = rand(n);
save(sprintf('a%d.mat',i), 'var');
end
Code
%%// The final result, A would have size nX(nXn)
A = zeros(n,n*n); %%// Pre-allocation for better performance
for k =1:n
load(strcat('a',num2str(k),'.mat'))
A(1:n,(k-1)*n+1:(k-1)*n+n) = var;
end

Extracting a matrix of data from a matrix of structs

I have a matrix of structs. I'm trying to extract from that matrix a matrix the same size
with only one of the fields as values.
I've been trying to use struct2cell and similar functions without success.
How can this be done?
If I understand you correctly, you have an array of struct like e.g this
s(1:2,1:3) = struct('a',1,'b',2);
Now you want a different struct that only has the field b
[newS(1:2,1:3).b] = deal(s.b);
edit
If all you need is the output (and if the field values are scalar), you can do the following:
out = zeros(size(s));
out(:) = cat(1,s.b)
I'll borrow Jonas' example. You can use the [] to gather a particular field.
% Create structure array
s(1:2,1:3) = struct('a',1,'b',2);
% Change values
for idx = 1:prod(size(s))
s(idx).a = idx;
s(idx).b = idx^2;
end
% Gather a specific field and reshape it to the size of the original matrix
A = reshape([s.a],size(s));
B = reshape([s.b],size(s));
I have a similar problem, but the contents of the field in my structure array are varying length strings that I use to tag my data, so when I extract the contents of the field, I want a cell of varying length strings.
This code using getfield and arrayfun does the job, but I think it is more complicated than it needs to be.
sa = struct('name', {'ben' 'frank', 'betty', 'cybil', 'jack'}, 'value', {1 1 2 3 5})
names = arrayfun(#(x) getfield(x, 'name'), sa, 'UniformOutput', false)
Can anyone suggest cleaner alternative? extractfield in the mapping toolbox seems to do the job, but it is not part of the base MATLAB system.
Update: I have answered my own embedded question.
names = {sa.name}