Printing multiple disp functions with one for loop - matlab

So, I have a series of display functions, ranging from x1 to x7. These all contain both strings and variables like:
x1 = ['The result of the scalar multiplication of V and U: ',num2str(scalar_uv)];
x2 = similar to above but with for example a value on the cross multiplication of the two scalars.
Instead of printing out each one through:
disp(x1);
disp(x2);
disp(x3);
I thought it would be possible to print them all out through a for loop or perhaps a nested for loop but I just can't figure out how to do it. I preferably don't want straight up solutions (I won't say no to them) but rather some hints or tips of possible.

A simple example solution would be to make a cell array and loop through it, or use celldisp() to display it. But if you want to print nicely, i.e. formatted specifically, to the command window you can use the fprintf function and format in line breaks. For example:
for displayValue = {x1, x2, x3, x4}
fprintf('%s\n', displayValue{1});
end
If you want more formatting options, such as precision, or fieldwidth, the formatspec code (%s in the example) has many configurations. You can see them on the fprintf helpdoc. The \n just tells the fprintf function to create a newline when it prints.

Instead of creating seven different variables (x1...x7), just create a cell array to hold all your strings:
x{1} = ['The result of the scalar multiplication of V and U: ',num2str(scalar_uv)];
x{2} = ['Some other statement with a value at the end: ',num2str(somevar)];
Now you can write a loop:
for iX = 1:length(x)
disp(x{iX})
end
Or use cellfun to display them without a for loop:
cellfun(#disp,x)
If you really want to keep them named x1...x7, then you can use an eval statement to get your variable names:
for iX = 1:7
disp(eval(['x' num2str(iX)]));
end

Related

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

How to manipulate and assign parts of a MATLAB field - Comma-separated list assignment

Consider the following MATLAB struct:
a(1).num=1; a(2).num=2; a(3).num=3;
The thing I want to do is to replace some of the elements of num with the old value minus a (scalar) number. For example, I would like to subtract 1 from a(2).num and a(3).num.
I already tried different ways:
a(2:3).num=a(2:3).num-1;
??? Error using ==> minus Too many input arguments.
Next try:
>>a(2:3).num=[a(2:3).num]-1;
??? Insufficient outputs from right hand side to satisfy comma separated list
expansion on left hand side. Missing [] are the most likely cause.
And last:
>> [a(2:3).num]=[a(2:3).num]-1;
??? Error using ==> minus
Too many output arguments.
arrayfun couldn´t help either.
Probably there is a quite easy answer to this question, but I couldn´t find any.
Easiest is a two-line solution:
C = num2cell([a(2:3).num]-1);
[a(2:3).num] = C{:}
Nicest is to have a function like deal, but with a function applied to each argument:
function varargout = fcnDeal(varargin)
%// (Copied from MATLAB's deal()
if nargin==1,
varargout = varargin(ones(1,nargout));
else
if nargout ~= nargin-1
error('fcnDeal:narginNargoutMismatch',...
'The number of outputs should match the number of inputs.')
end
%//...Except this part
varargout = cellfun(varargin{1}, varargin(2:end), 'UniformOutput', false);
end
end
Then what you want to do is just a matter of
[a(2:3).num] = fcnDeal(#(x)x-1, a(2:3).num)
You can manipulate them in the loop
index = [1,2]
for i = index
a(i).num = a(i).num - 1;
end

Linear indexing of 3D matrix: best way to expand the first 2 dims to a vector (slow sprintf on scalars)

I have a 3D vector s1(nmax,mmax,ntimeSTEPS). I want to take at each time step j (i.e. each value of the third dimension) all the elements of the first two dimensions and obtain a vector to give to sprintf. However, sprintf is PAINFULLY SLOW if inside a cycle! I checked the manual and it looks like there is no way to do that directly with linear indexing. Or am I missing something? I can only think of using reshape, but something like s1(:,j) would be the top, but that's not how MATLAB works. I did:
nmax = 800;
mmax =400;
nmax_x_mmax = nmax*mmax;
ntimeSTEPS = 1;
charINPUT = cell(nmax_x_mmax,1);
s1 = ones(nmax,mmax,ntimeSTEPS)*1234;
tic
for j=1:ntimeSTEPS
%... other stuff
input=reshape(s1(:,:,j),nmax_x_mmax,1);
for kk=1:length(input)
charINPUT{kk} = sprintf('%6.3f',input(kk));
end
%... other stuff (collecting movie frames etc)
end
toc
This on a single time steps takes 5.09 SECONDS on my i7 2.2 GHz! I am trying to do an animation and this is crazily slow. If I increase the size of the array its basically stuck.
Any suggestion for doing this with linear indexes?
Using sprintf
sprintf can take an array. Output with newlines and use regexp to parse out the digits and put them in a cell array of strings.
charINPUT = regexp(sprintf('%6.3f\n',s1(:)),'(?<=\s*)(\S*)(?=\n)','match')
Without sprintf
You don't have to use sprintf in a loop to build your cell array of strings. Since num2str takes a format specifier, you can just do this for the whole thing:
charINPUT = cellstr(num2str(s1(:),'%6.3f'))
You can either skip the loop over ntimeSTEPS entirely, or if you are performing other operations you are not showing that require the loop you can handle indexing as follows.
For direct indexing of s1 with no temporary variable, you can compute the linear indexes yourself via (1:nmax*nmax) + (j-1)*nmax*nmax.
for j=1:ntimeSTEPS,
stepInds = (1:nmax*nmax) + (j-1)*nmax*nmax;
charINPUT = cellstr(num2str(s1(stepInds),'%6.3f'))
end
Try this
for idx = 1:numel(s1)
charINPUT{idx} = sprintf('%6.3f',s1(idx));
end

How do I create a vector that accepts strings?

Ok the problem is, I want to receive mathematical functions. And I won't know how many until the program runs.
When it runs i ask for an n number of functions i am going to receive and it starts saving them from the input.
So far I have this
function test()
n = input('number of equations?');
v = [1:n]
%in an ideal world, this ^ here would allow me to put a string in each position but
% they are not the same type and I understand that.. but how can I build a vector for saving my functions
%I want a vector where I can put strings in each position that is what I need
for i=1:n
x = input('what is the function?','s');
v(i)=x
end
v
%this would be my vector already changed with a function in each position.
end
When you want to store strings of different lengths, use cell arrays:
v = cell(1,n);
for i=1:n
v{i} = input('what is the function?','s'); #% note the curly braces
end
To use these as functions, use str2func:
for i=1:n
fh{i} = str2func(v{i});
end
fh is now a cell array containing handles to the functions defined by the user-input strings.