Find values in 3d matrix - matlab

I would like to do the equivalent of
x = [1, 0, 3; 2, 3, 0; 0, 0, 3];
[yy, xx, vals] = find(x);
where I really need the vals variable. I need all three, but vals is important. Now consider the 3d case, and flip one, so it's more interesting.
x = repmat(x, [1, 1, 3]);
x(:, :, 2) = fliplr(x(:, :, 1));
I'd like to do the same as before. I found this in several places
[yy, xx, zz] = ind2sub(size(x), find(x));
but then I don't know how to extract vals properly... I also don't really care about zz, but I'm sure they somehow need to be used for indexing.
Any help would be appreciated.

find with one output argument, as you used in your last statement:
[yy, xx, zz] = ind2sub(size(x), find(x));
returns linear indices into the matrix. You can use these to index:
index = find(x);
vals = x(index);
[xx,yy,zz] = ind2sub(size(x), index);

I'm not sure I've understood what you want to achieve, nevertheless, considering your last matrix x
x = [1, 0, 3; 2, 3, 0; 0, 0, 3]
z = repmat(x, [1, 1, 3]);
x(:, :, 2) = fliplr(x(:, :, 1))
with
[yy, xx, vals] = find(x)
you have:
yy the indices of the rows of the found elements
xx the indices of the columns of the found elements
then you can use
lin_idx=sub2ind(size(x),yy,xx)
to get the linear indices of the values inside the matrix x
now you can use
[a,b,c]=ind2sub(size(x),lin_idx)
to get the 3D indices of the elements in the matrix
You can access the values using that indices:
for i=1:length(a)
k(i)=x(a(i),b(i),c(i))
end
Now the array k contains the values (as per the array vals returned by find).

Related

Split matrix into SubMatrixes of Leading Coefficients

I am working with MATLAB_R2016a, and am currently trying to find the right matrix fraction description of a MIMO system. Suppose I have a matrix of the form:
[s^2+3s+1, s+1, s^3+2s; s^3+3, s^2-6, s-5];
Is there a simple way to generate submatrixes of coefficients for each degree of s? Like so:
[0, 0, 1; 1, 0, 0] s^3 + [0, 0, 0 ; 0, 1, 0] s^2 + [3, 1, 2; 0, 0, 1] s + [1,1,0;3,-6,-5];
I figure it can be done with a loop and extracting the degree of each polynomial element, but wanted to know if people had found easier work-arounds?
I suppose you use symbolic toolbox to work on polynomials. So, as #10a commented you can use coeffs function.
You just need to made some workaround to get final result.
For arbitrary polynomials you can use the next code:
syms x
% find all coefficients for each polynomial. Results are of different sizes!
% because of different degrees of polinomils
coef = arrayfun( #(y) coeffs(y, 'All') , [2*x^2 + 3*x + 5, x^2+3; x^3, x + 7] ,...
'UniformOutput' , false)
% find max degree
max_size = cellfun( #(x) size(x,2), coef)
max_size = max(max_size(:))
% and finally fill with zeros all surplus places in arrays to get unified size
result = cellfun( #(x) [zeros(1, max_size - size(x,2)) x], coef, 'UniformOutput', false)

3d matrix: how to use (row, column) pairs with 3rd dimension wildcard in MATLAB?

I have a 3 dimensional matrix, and a list of (row, column) pairs. I would like to extract the 2 dimensional matrix that corresponds to the elements in those positions, projected through the depth of the matrix. For instance, suppose,
>> a = rand(4, 3, 2)
a(:,:,1) =
0.5234 0.7057 0.0282
0.6173 0.2980 0.9041
0.7337 0.9380 0.9639
0.0591 0.8765 0.1693
a(:,:,2) =
0.8803 0.2094 0.5841
0.7151 0.9174 0.6203
0.7914 0.7674 0.6194
0.2009 0.2542 0.3600
>> rows = [1 4 2 1];
>> cols = [1 2 1 3];
What I'd like to get is,
0.5234 0.8765 0.6173 0.0282
0.8803 0.2542 0.7151 0.5841
maybe with some permutation of dimensions. Also, although this example has the wildcard in the last dimension, I also have cases where it's in the first or second.
I naively tried a(rows, cols, :) and got a 3d matrix where the diagonal plane is what I want. I also found sub2ind, which will extract the desired elements from the a(:,:,1) plane. I could work with one of these to get to what I want, but I'm wondering is there a more canonical, elegant, or efficient method that I'm missing?
Update
This was the solution I used, based on the answer posted below,
sz = size(a);
subs = [repmat(rows, [1, sz(3)]);
repmat(cols, [1, sz(3)]);
repelem([1:sz(3)], length(rows))];
result = a(sub2ind(sz, subs(1,:), subs(2,:), subs(3,:)));
sub2ind is pretty much what you have to use here to convert your subscripts into linear indices (apart from manually computing the linear indices yourself). You can do something like the following which will convert the rows and cols to a linear index (in a 2D slice) and then it adds an offset (equal to the number of elements in a 2D slice) to these indices to sample all elements in the third dimension.
sz = size(a);
inds = sub2ind(sz(1:2), rows, cols);
inds = bsxfun(#plus, inds, (0:(sz(3)-1)).' * prod(sz(1:2)));
result = a(inds);
And to actually compute the linear indices yourself
inds = (cols - 1) * sz(1) + rows;
inds = bsxfun(#plus, inds, (0:(sz(3) - 1)).' * prod(sz(1:2)));
result = a(inds);
Another option would be to permute your initial matrix to bring the third dimension to the first dimension, reshape it to a 2D matrix, and then use the linear index as the second subscript
% Create a new temporary matrix
anew = reshape(permute(a, [3, 1, 2]), size(a, 3), []);
% Grab all rows (the 3rd dimension) and compute the columns to grab
result = anew(:, (cols - 1) * size(a, 1) + rows);

MATLAB get xyrgb pixel values

I'm trying to get a five column matrix with one row for each pixel in an image. The first two columns are the location (x,y) of the pixel, and the remaining columns are the RGB values of the pixel.
I can use a loop to create this matrix, but I would like to vectorize this operation for efficiency purposes. I can get the RGB values with img(:,:,1), img(:,:,2), and img(:,:,3) respectively, but I don't know how to get the x and y value of the associated pixel while vectorizing.
You can use meshgrid to get all x and y coordinates and then append these to your data resulting in a N x 5 matrix.
[x, y] = meshgrid(1:size(img, 2), 1:size(img, 1));
out = cat(2, x(:), y(:), reshape(img, [], 3));
Find is one way to query the coordinates.
You can separate the RGB channels, find the coordinates and then concatenate the results:
imgR = img(:, :, 1);
imgG = img(:, :, 2);
imgB = img(:, :, 3);
[rows, cols] = find(imgR + 1); % +1 to avoid zeros!
M = [rows, cols, imgR(:), imgG(:), imgB(:)];

How to do this kind of sorting (in MATLAB)?

I have a square matrix and I want to get a 2 by n matrix that will have indices of matrix in a sorted order. For example, I want to get from this matrix
0 0 0
1 0 0
2 3 0
something like this
[3 2; 3 1; 2 1] ....
(3,2) being the indices of the biggest element in the matrix, (3,1) the second biggest and so on. It would be good if it could ignore zeros (or NaN-s instead of zeros).
Additional information about the matrix: it is positive, but not necessarily 3 by 3, diagonal elements and every element above the diagonal is either 0 or NaN (a side question, which is processed faster, NaNs or 0s?)
This considers only non-zero elements:
[ii, jj, aa] = find(A);
[~, kk] = sort(aa, 'descend');
result = [ii(kk) jj(kk)];
Assuming your matrix is in A, you need to use the ind2sub function,
Edited to remove zero indices
[Ap, i] = sort(A(:), 'descend');
[r,c] = ind2sub(size(A), i);
orderedPairs = [r,c];
orderedPairsSansZeros = orderedPairs(Ap ~= 0, :);
This following should work. The matrix sortix is what you're looking for. I've replaced a zero in your (1,3) element with NaN so you can see that NaN's don't show up in your final ordered matrix.
matrix = [0, 0, NaN;
1, 3, 0;
2, 3, 0];
new_matrix = matrix;
%new_matrix(new_matrix(:)==0) = NaN; % uncomment to get rid of zeros
saveix = 1;
for i=1:length(matrix(:))
[maxVal, maxIndex] = max(new_matrix(:));
allMax = ismember(new_matrix, maxVal);
idx = find(allMax);
for ix=1:length(idx)
[sortix(saveix, 1), sortix(saveix, 2)] = ind2sub(size(matrix), ...
idx(ix));
saveix = saveix + 1;
end
new_matrix(idx) = NaN;
end

How to update multiple graphs from one plot in one statement in Matlab?

I have something like this:
p = plot([0 1], [0 1], [1 2], [1 2]);
I want to take each pair and append another number.
x = get(p, 'XData');
y = get(p, 'YData');
x1 = mat2cell([x{1} double(2)]);
y1 = mat2cell([y{1} double(2)]);
x2 = mat2cell([x{2} double(3)]);
y2 = mat2cell([y{2} double(3)]);
set(p, 'XData', [x1; x2], 'YData', [y1; y2]); % this does not work
drawnow;
'get' is giving me some data in a format and I am 'set'-ing back in the same format the data with one more value for each pair.
The error I get is: Conversion to double from cell is not possible.
There are a number of different ways to fetch the current plot points and add to them. The first two lines of Eitan's answer (using cellfun) are one way. Here's one using cell2mat and num2cell:
newX = [2 3]; % New x values to add
newY = [2 3]; % New y values to add
X = num2cell([cell2mat(get(p,'XData')) newX(:)], 2);
Y = num2cell([cell2mat(get(p,'YData')) newY(:)], 2);
The key issue to note when using the set function on multiple handles is stated in this excerpt from the documentation:
set(H,pn,MxN_pv) sets n property values on each of m graphics objects, where m = length(H) and n is equal to the number of property names contained in the cell array pn. This allows you to set a given group of properties to different values on each object.
As a result, your single call to set has to look like this:
set(p, {'XData'}, X, {'YData'}, Y);
Note that length(p) is equal to 2, the property strings are placed in cell arrays, and X and Y are each 2-by-1 cell arrays.
Try redrawing the plot:
xcoor = cellfun(#horzcat, get(p, 'XData'), {2; 3}, 'UniformOutput', false);
ycoor = cellfun(#horzcat, get(p, 'YData'), {2; 3}, 'UniformOutput', false);
c = [xcoor; ycoor];
plot(c{:})