define a series of matrices variables not using cell in Matlab - matlab

Here is my code:
A = zeros(10,10,10);
for i = 1:10
C{i} = A(:,:,i);
end
This is just a simple example and my question is: Is there any other way, NOT using a cell (C{i} in the code) to represent a series of 2D matrices variables (A(:,:,i) in the code) from a 3D matrix (A). Anyway I believe you will need some variable name like 'i'.
Thanks in advance!

You can do:
A = zeros(10,10,10);
for i = 1:10
eval(sprintf('A%d = A(:,:,%d)',i,i));
end
In this way you get 10 matrices whose names are A1, A2, ..., Ai,...
Anyway I suggest not using this method. It is more readable the one with cell arrays.

Related

save columns of matrix in vector variables in Matlab

In Matlab (R2021b) I am using some given function, which reads time-dependent values of several variables and returns them in a combined matrix together with a time vector. In the data matrix each column represents one vector of time-dependent values for one variable.
[data,time] = function_reading_data_of_several_values('filename');
For readability of the following code where the variables are further processed, I would like to store these columns in separate vector variables. I am doing it like that:
MomentX = data(1,:);
MomentY = data(2,:);
MomentZ = data(3,:);
ForceX = data(4,:);
ForceY = data(5,:);
ForceZ = data(6,:);
That is working. But is there some simpler (or shorter) way of assigning the column of the matrix to individual vectors? I am asking because in real program I have more than the 6 columns as in the example. Code is getting quite long. I was thinking of something similar to the line below, but that does not work:
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
Do you have any idea? Thanks for help!
Update:
Thanks to the hint here in the group to use tables, a solution could be like this:
...
[data,time] = function_reading_data_of_several_values('filename');
% data in matrix. Each column representing a stime dependent variable
varNames = {'MomentX', 'MomentX',...}; % Names of columns
T=array2table(data','VariableNames',varNames); % Transform to Table
Stress = T.MomentX/W + T.ForceY/A %accesing table columns
...
This seems to work fine and readable to me.
Solution 1: In industrial solutions like dSpace, it is very common to do it in struct arrays:
mydata.X(1).time = [0.01 0.02 0.03 0.04];
mydata.Y(1).name = 'MomentX';
mydata.Y(1).data = [1 2 3 4];
mydata.Y(2).name = 'MomentY';
mydata.Y(2).data = [2 3 4 5];
Solution 2: It is also very common to create tables
See: https://de.mathworks.com/help/matlab/ref/table.html
As already commented, it is probably better to use a table instead of separate variables may not be a good idea. But if you want to, it can be done this way:
A = magic(6): % example 6-column matrix
A_cell = num2cell(A, 1); % separate columns in cells
[MomentX, MomentY, MomentZ, ForceX, ForceY, ForceZ] = A_cell{:};
This is almost the same as your
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
except that the right-hand side needs to be a comma-separated list, which in this case is obtained from a cell array.

Create multiple variables of same size in Matlab

Say, I want to create 3 variables of same size in MATLAB:
a = zeros(3,3);
b = zeros(3,3);
c = zeros(3,3);
Is there any fast way to do this, I know this is not working but I think of something like
a,b,c = zeros(3,3);
Any suggestions?
To use deal there is no need to wrap it in a cell as NKN suggested:
[a,b,c]=deal(zeros(3,3))
Although you can do this:
a = zeros(3); % a 3x3 zero matrix
b = a;
c = a;
If you define the values that you want to assign, in a cell, the other way (faster) is:
c={zeros(3)};
[a1,a2,a3,a4]=deal(c{1})
it means that you put your assigning value in a cell and then use deal function. Notice that the a1,a2,a3,a4 does not have cell formats, but double formats and actually this is a very fast method.
If you use cell foramt you can assign more values at the same time, for example:
C = {rand(3) ones(3,1) eye(3) zeros(3,1)};
[a,b,c,d] = deal(C{:})
otherwise you can just get rid of the cell and use:
c=zeros(3);
[a1,a2,a3,a4]=deal(c);
as Daniel Suggested.

Foreach loop problems in MATLAB

I have the following piece of code:
for query = queryFiles
queryImage = imread(strcat('Queries/', query));
queryImage = im2single(rgb2gray(queryImage));
[qf,qd] = vl_covdet(queryImage, opts{:}) ;
for databaseEntry = databaseFiles
entryImage = imread(databaseEntry.name);
entryImage = im2single(rgb2gray(entryImage));
[df,dd] = vl_covdet(entryImage, opts{:}) ;
[matches, H] = matchFeatures(qf,qf,df,dd) ;
result = [result; query, databaseEntry, length(matches)];
end
end
It is my understanding that it should work as a Java/C++ for(query:queryFiles), however the query appears to be a copy of the queryFiles. How do I iterate through this vector normally?
I managed to sort the problem out. It was mainly to my MATLAB ignorance. I wasn't aware of cell arrays and that's the reason I had this problem. That and the required transposition.
From your code it appears that queryFiles is a numeric vector. Maybe it's a column vector? In that case you should convert it into a row:
for query = queryFiles.'
This is because the for loop in Matlab picks a column at each iteration. If your vector is a single column, it picks the whole vector in just one iteration.
In MATLAB, the for construct expects a row vector as input:
for ii = 1:5
will work (loops 5 times with ii = 1, 2, ...)
x = 1:5;
for ii = x
works the same way
However, when you have something other than a row vector, you would simply get a copy (or a column of data at a time).
To help you better, you need to tell us what the data type of queryFiles is. I am guessing it might be a cell array of strings since you are concatenating with a file path (look at fullfile function for the "right" way to do this). If so, then a "safe" approach is:
for ii = 1:numel(queryFiles)
query = queryFiles{ii}; % or queryFiles(ii)
It is often helpful to know what loop number you are in, and in this case ii provides that count for you. This approach is robust even when you don't know ahead of time what the shape of queryFiles is.
Here is how you can loop over all elements in queryFiles, this works for scalars, row vectors, column vectors and even high dimensional matrices:
for query = queryFiles(:)'
% Do stuff
end
Is queryFiles a cell array? The safest way to do this is to use an index:
for i = 1:numel(queryFiles)
query = queryFiles{i};
...
end

How to write this in an elegant way (cell arrays and structs in MATLAB)

I would like to plot connected points in MATLAB.
My connected points come from connecting objects of "stats", where each "stat" comes from a BW regionprops struct.
The code I have written works, but it suffers from a lot of "ugliness", which I couldnt fix even after trying various ways.
function plot_line( line )
a = cell2mat(line);
b = {a.Centroid};
matx = {};
maty = {};
for i = 1:size(b,2)
matx{end+1} = b{i}(1);
maty{end+1} = b{i}(2);
end
plot ( cell2mat(matx), cell2mat(maty) );
end
Can you help me make this code nicer? It's not critical, as my code works fine and as the lines are short (<100 points) the performance is not an issue.
It is just that it would be really nice to know how this tiny function should be written in the proper way, without for loops and 3 calls of cell2mat.
In my example:
line is a <1xn cell>,
line{1} has a property 'Centroid' and
line{i}.Centroid(1) are the x coordinates and
line{i}.Centroid(2) are the y coordinates.
Actually, all I need is plotting line{i}.Centroid(1), line{i}.Centroid(2) for i = 1:size(line,2), but I don't know how.
Instead of creating a cell array b, you can create a numerical array directly, by catenating using CAT:
tmp = cat(1,line{:});
coordinates = cat(1,tmp.Centroid);
plot(coordinates(:,1),coordinates(:,2))
EDIT
If you want to keep it really short (i.e. even shorter than #Amro's solution you can use CELLFUN like this in order get a one-liner:
plot(cellfun(#(x)x.Centroid(1),line),cellfun(#(x)x.Centroid(2),line))
Example:
line = repmat({struct('Centroid',[1 2])},1,5); %# similar to the data you have
%# extract x/y coordinates
x = cellfun(#(s)s.Centroid(1),line)
y = cellfun(#(s)s.Centroid(2),line)
%# plot
plot(x,y)
You could also do it as:
xy = cell2mat(cellfun(#(s)s.Centroid, line, 'UniformOutput',false)');
plot(xy(:,1),xy(:,2))

How can I create/process variables in a loop in MATLAB?

I need to calculate the mean, standard deviation, and other values for a number of variables and I was wondering how to use a loop to my advantage. I have 5 electrodes of data. So to calculate the mean of each I do this:
mean_ch1 = mean(ch1);
mean_ch2 = mean(ch2);
mean_ch3 = mean(ch3);
mean_ch4 = mean(ch4);
mean_ch5 = mean(ch5);
What I want is to be able to condense that code into a line or so. The code I tried does not work:
for i = 1:5
mean_ch(i) = mean(ch(i));
end
I know this code is wrong but it conveys the idea of what I'm trying to accomplish. I want to end up with 5 separate variables that are named by the loop or a cell array with all 5 variables within it allowing for easy recall. I know there must be a way to write this code I'm just not sure how to accomplish it.
You have a few options for how you can do this:
You can put all your channel data into one large matrix first, then compute the mean of the rows or columns using the function MEAN. For example, if each chX variable is an N-by-1 array, you can do the following:
chArray = [ch1 ch2 ch3 ch4 ch5]; %# Make an N-by-5 matrix
meanArray = mean(chArray); %# Take the mean of each column
You can put all your channel data into a cell array first, then compute the mean of each cell using the function CELLFUN:
meanArray = cellfun(#mean,{ch1,ch2,ch3,ch4,ch5});
This would work even if each chX array is a different length from one another.
You can use EVAL to generate the separate variables for each channel mean:
for iChannel = 1:5
varName = ['ch' int2str(iChannel)]; %# Create the name string
eval(['mean_' varName ' = mean(' varName ');']);
end
If it's always exactly 5 channels, you can do
ch = {ch1, ch2, ch3, ch4, ch5}
for j = 1:5
mean_ch(j) = mean(ch{j});
end
A more complicated way would be
for j = 1:nchannels
mean_ch(j) = eval(['mean(ch' num2str(j) ')']);
end
Apart from gnovice's answer. You could use structures and dynamic field names to accomplish your task. First I assume that your channel data variables are all in the format ch* and are the only variables in your MATLAB workspace. The you could do something like the following
%# Move the channel data into a structure with fields ch1, ch2, ....
%# This could be done by saving and reloading the workspace
save('channelData.mat','ch*');
chanData = load('channelData.mat');
%# Next you can then loop through the structure calculating the mean for each channel
flds = fieldnames(chanData); %# get the fieldnames stored in the structure
for i=1:length(flds)
mean_ch(i) = mean(chanData.(flds{i});
end