How do i plot pair of points from an array - arrays

I have a matrix:
img = [1 1 2 2
1 1 2 2
3 2 2 2
3 2 2 2
3 3 3 2];
from which I obtained the array of points:
A = [3 2; 5 4];
I need to plot each pair of points (y,x) row-by-row (i.e (3,2), (5,4), etc) and i have tried the code:
for i = 1: size(A, 2)
plot(A(i, 1), A(i, 2), '*')
end
This however does not give the expected positions of the points. Please, what could be wrong with my code and what can I do to make this work?

Since your pairs of points are in row/column order, you'll need to switch the order for plot as the order of inputs to plot are x/y. Also, you'll want to use the number of rows size(A, 1) rather than size(A, 2)
for k = 1:size(A, 1)
plot(A(k,2), A(k,1), '*')
hold on
end
You can also just plot everything at once without the loop
plot(A(:,2), A(:,1), '*');

Related

Sum up vector values till threshold, then start again

I have a vector a = [1 3 4 2 1 5 6 3 2]. Now I want to create a new vector 'b' with the cumsum of a, but after reaching a threshold, let's say 5, cumsum should reset and start again till it reaches the threshold again, so the new vector should look like this:
b = [1 4 4 2 3 5 6 3 5]
Any ideas?
You could build a sparse matrix that, when multiplied by the original vector, returns the cumulative sums. I haven't timed this solution versus others, but I strongly suspect this will be the fastest for large arrays of a.
% Original data
a = [1 3 4 2 1 5 6 3 2];
% Threshold
th = 5;
% Cumulative sum corrected by threshold
b = cumsum(a)/th;
% Group indices to be summed by checking for equality,
% rounded down, between each cumsum value and its next value. We add one to
% prevent NaNs from occuring in the next step.
c = cumsum(floor(b) ~= floor([0,b(1:end-1)]))+1;
% Build the sparse matrix, remove all values that are in the upper
% triangle.
S = tril(sparse(c.'./c == 1));
% In case you use matlab 2016a or older:
% S = tril(sparse(bsxfun(#rdivide,c.',c) == 1));
% Matrix multiplication to create o.
o = S*a.';
By normalizing the arguments of cumsum with the threshold and flooring you can get grouping indizes for accumarray, which then can do the cumsumming groupwise:
t = 5;
a = [1 3 4 2 1 5 6 3 2];
%// cumulative sum of normalized vector a
n = cumsum(a/t);
%// subs for accumarray
subs = floor( n ) + 1;
%// cumsum of every group
aout = accumarray( subs(:), (1:numel(subs)).', [], #(x) {cumsum(a(x))});
%// gather results;
b = [aout{:}]
One way is to use a loop. You create the first cumulative sum cs, and then as long as elements in cs are larger than your threshold th, you replace them with elements from the cumulative sum on the rest of the elements in a.
Because some elements in a might be larger than th, this loop will be infinite unless we also eliminate these elements too.
Here is a simple solution with a while loop:
a = [1 3 4 2 1 5 6 3 2];
th = 5;
cs = cumsum(a);
while any(cs>th & cs~=a) % if 'cs' has values larger that 'th',
% and there are any values smaller than th left in 'a'
% sum all the values in 'a' that are after 'cs' reached 'th',
% excluding values that are larger then 'th'
cs(cs>th & cs~=a) = cumsum(a(cs>th & cs~=a));
end
Calculate the cumulative sum and replace the indices value obeying your condition.
a = [1 3 4 2 1 5 6 3 2] ;
b = [1 4 4 2 3 5 6 3 5] ;
iwant = a ;
a_sum = cumsum(a) ;
iwant(a_sum<5) = a_sum(a_sum<5) ;

Collapsing matrix into columns

I have a 2D matrix where the № of columns is always a multiple of 3 (e.g. 250×27) - due to a repeating organisation of the results (A,B,C, A,B,C, A,B,C, and so forth). I wish to reshape this matrix to create a new matrix with 3 columns - each containing the aggregated data for each type (A,B,C) (e.g. 2250×3).
So in a matrix of 250×27, all the data in columns 1,4,7,10,13,16,19,22,25 would be merged to form the first column of the resulting reshaped matrix.
The second column in the resulting reshaped matrix would contain all the data from columns 2,5,8,11,14,17,20,23,26 - and so forth.
Is there a simple way to do this in MATLAB? I only know how to use reshape if the columns I wanted to merge were adjacent (1,2,3,4,5,6) rather than non-adjacent (1,4,7,10,13,16) etc.
Shameless steal from #Divakar:
B = reshape( permute( reshape(A,size(A,1),3,[]), [1,3,2]), [], 3 );
Let A be your matrix. You can save every third column in one matrix like:
(Note that you don't have to save them as matrices separately but it makes this example easier to read).
A = rand(27); %as test
B = A(:,1:3:end);
C = A(:,2:3:end);
D = A(:,3:3:end);
Then you use reshape:
B = reshape(B,[],1);
C = reshape(C,[],1);
D = reshape(D,[],1);
And finally put it all together:
A = [B C D];
You can just treat every set of columns as a single item and do three reshapes together. This should do the trick:
[save as "reshape3.m" file in your Matlab folder to call it as a function]
function out = reshape3(in)
[~,C]=size(in); % determine number of columns
if mod(C,3) ~=0
error('ERROR: Number of rows must be a multiple of 3')
end
R_out=numel(in)/3; % number of rows in output
% Reshape columns 1,4,7 together as new column 1, column 2,5,8 as new col 2 and so on
out=[reshape(in(:,1:3:end),R_out,1), ...
reshape(in(:,2:3:end),R_out,1), ...
reshape(in(:,3:3:end),R_out,1)];
end
Lets suppose you have a 3x6 matrix A
A = [1 2 3 4 5 6;6 5 4 3 2 1;2 3 4 5 6 7]
A =
1 2 3 4 5 6
6 5 4 3 2 1
2 3 4 5 6 7
you extract the size of the matrix
b =size(A)
and then extract each third column for a single row
c1 = A((1:b(1)),[1:3:b(2)])
c2 = A((1:b(1)),[2:3:b(2)])
c3 = A((1:b(1)),[3:3:b(2)])
and put them in one matrix
A_result = [c1(:) c2(:) c3(:)]
A_result =
1 2 3
6 5 4
2 3 4
4 5 6
3 2 1
5 6 7
My 2 cents:
nRows = size(matrix, 1);
nBlocks = size(matrix, 2) / 3;
matrix = reshape(matrix, [nRows 3 nBlocks]);
matrix = permute(matrix, [1 3 2]);
matrix = reshape(matrix, [nRows * nBlocks 1 3]);
matrix = reshape(matrix(:), [nRows * nBlocks 3]);
Here's my 2 minute take on it:
rv = #(x) x(:);
ind = 1:3:size(A,2);
B = [rv(A(:,ind)) rv(A(:,ind+1)) rv(A(:,ind+2))];
saves a few ugly reshapes, may be a bit slower though.
If you have the Image Processing Toolbox, im2col is a very handy solution:
out = im2col(A,[1 4], 'distinct').'
Try Matlab function mat2cell, I think this form is allowed.
X is the "start matrix"
C = mat2cell(X, [n], [3, 3, 3]); %n is the number of rows, repeat "3" as many times as you nedd
%extract every matrix
C1 = C{1,1}; %first group of 3 columns
C2 = C{1,2}; %second group of 3 columns
%repeat for all your groups
%join the matrix with vertcat
Cnew = vertcat(C1,C2,C3); %join as many matrix n-by-3 as you have

Vectorization- Matlab

Given a vector
X = [1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3]
I would like to generate a vector such
Y = [1 2 3 4 5 1 2 3 4 5 6 1 2 3 4 5]
So far what I have got is
idx = find(diff(X))
Y = [1:idx(1) 1:idx(2)-idx(1) 1:length(X)-idx(2)]
But I was wondering if there is a more elegant(robust) solution?
One approach with diff, find & cumsum for a generic case -
%// Initialize array of 1s with the same size as input array and an
%// intention of using cumsum on it after placing "appropriate" values
%// at "strategic" places for getting the final output.
out = ones(size(X))
%// Find starting indices of each "group", except the first group, and
%// by group here we mean run of identical numbers.
idx = find(diff(X))+1
%// Place differentiated and subtracted values of indices at starting locations
out(idx) = 1-diff([1 idx])
%// Perform cumulative summation for the final output
Y = cumsum(out)
Sample run -
X =
1 1 1 1 2 2 3 3 3 3 3 4 4 5
Y =
1 2 3 4 1 2 1 2 3 4 5 1 2 1
Just for fun, but customary bsxfun based alternative solution -
%// Logical mask with each column of ones for presence of each group elements
mask = bsxfun(#eq,X(:),unique(X(:).')) %//'
%// Cumulative summation along columns and use masked values for final output
vals = cumsum(mask,1)
Y = vals(mask)
Here's another approach:
Y = sum(triu(bsxfun(#eq, X, X.')), 1);
This works as follows:
Compare each element with all others (bsxfun(...)).
Keep only comparisons with current or previous elements (triu(...)).
Count, for each element, how many comparisons are true (sum(..., 1)); that is, how many elements, up to and including the current one, are equal to the current one.
Another method is using the function unique
like this:
[unqX ind Xout] = unique(X)
Y = [ind(1):ind(2) 1:ind(3)-ind(2) 1:length(X)-ind(3)]
Whether this is more elegant is up to you.
A more robust method will be:
[unqX ind Xout] = unique(X)
for ii = 1:length(unqX)-1
Y(ind(ii):ind(ii+1)-1) = 1:(ind(ii+1)-ind(ii));
end

Array filter based on multiple columns

Suppose I have a 4 x n array:
A = [1 2 3 4; ...
2 4 8 9; ...
6 7 9 4; ...
1 8 3 4];
I want to filter the whole array based on the content of the first two columns.
For example, if I want to return array rows which contain a 2 in the first two columns, the answer I'm looking for isL
R = [1 2 3 4;...
2 4 8 9];
Or, if I want to return rows containing a 1 in the first two columns, the answer I'm looking for is...
A = [1 2 3 4;...
1 8 3 4];
I'm sure it's obvious but how can I do this in MATLAB? Filtering the whole array based on find or evaluation commands (e.g. A == 2) is totally fine. It's the filtering based on multiple columns in any order I can't figure out.
To check for a given number, just apply any along 2nd dimension restricted to the desired columns, and use that as a logical index to select the desired rows:
cols = [1 2]; %// columns to look at
val = 1; %// value to look for
R = A(any(A(:, cols)==val, 2), :);
If you want to look for several values, for example, select all rows that contain either 2 or 3 in columns 1 or 2: use ismember instead of ==:
cols = [1 2]; %// columns to look at
vals = [2 3]; %// values to look for
R = A(any(ismember(A(:, cols), vals), 2), :);
If you want to check if the numbers are within a range:
cols = [1 2]; %// columns to look at
v1 = 6; %// numbers should be greater or equal to this...
v2 = 8; %// ...and less than this
R = A(any(A(:, cols)>=v1, 2) & any(A(:, cols)<v2, 2), :);

Store matrix from a loop in Matlab

I have a 5 by 3 matrix, e.g the following:
A=[1 1 1; 2 2 2; 3 3 3; 4 4 4; 5 5 5]
I run a for loop:
for i = 1:5
AA = A(i)'*A(i);
end
My question is how to store each of the 5 (3 by 3) AA matrices?
Thanks.
You could pre-allocate enough memory to the AA matrix to hold all the results:
[r,c] = size(A); % get the rows and columns of A (r and c respectively)
AA = zeros(c,c,r); % pre-allocate memory to AA for all 5 products
% (so we have 5 3x3 arrays)
Now do almost the same loop as above BUT realize that A(i) in the above code only returns one element whereas you want the full row. So you want the data from row i but all columns which can be represented as 1:3 or just the colon :
for i=1:r
AA(:,:,i) = A(i,:)' * A(i,:);
end
In the above, A(i,:) is the ith row of A and we are setting all rows and columns in the third dimension (i) of AA to the result of the product.
Assuming, as in Geoff's answer, that you mean A(i,:)'*A(i,:) (to get 5 matrices of size 3x3 in your example), you can do it in one line with bsxfun and permute:
AA = bsxfun(#times, permute(A, [3 2 1]), permute(A, [2 3 1]));
(I'm also assuming that your matrices only contain real numbers, as in your example. If by ' you really mean conjugate transpose, you need to add a conj in the above).

Resources