4 Dimensional Meshgrid - matlab - matlab

I want to create a 4 dimensional meshgrid.
I know I need to use the ngrid function. However, the output of meshgrid and ngrid is not exactly the same unless one permutes dimensions.
To illustrate, a three dimensional meshgrid seems to be equivalent to a three dimensional ngrid if the following permutations are done:
[X_ndgrid,Y_ndgrid,Z_ndgrid] = ndgrid(1:3,4:6,7:9)
X_meshgrid = permute(X_ndgrid,[2,1,3]);
Y_meshgrid = permute(Y_ndgrid,[2,1,3]);
Z_meshgrid = permute(Z_ndgrid,[2,1,3]);
sum(sum(sum(X == X_meshgrid))) == 27
sum(sum(sum(Y == Y_meshgrid))) == 27
sum(sum(sum(Z == Z_meshgrid))) == 27
I was wondering what are the right permutations for a 4-D meshgrid.
[X_ndgrid,Y_ndgrid,Z_ndgrid, K_ndgrid] = ndgrid(1:3,4:6,7:9,10:12 )
Edit: EBH, thanks for your answer below. Just one more quick question. If the endgoal is to create a grid in order to use interpn, what would be the difference between creating a grid with meshgrid or with ndgrid (assuming a 3 dimensional problem?)

The difference between meshgrid and ndgrid is that meshgrid order the first input vector by the columns, and the second by the rows, so:
>> [X,Y] = meshgrid(1:3,4:6)
X =
1 2 3
1 2 3
1 2 3
Y =
4 4 4
5 5 5
6 6 6
while ndgrid order them the other way arround, like:
>> [X,Y] = ndgrid(1:3,4:6)
X =
1 1 1
2 2 2
3 3 3
Y =
4 5 6
4 5 6
4 5 6
After the first 2 dimensions, there is no difference between them, so using permute only on the first 2 dimensions should be enough. So for 4 dimensions you just write:
[X_ndgrid,Y_ndgrid,Z_ndgrid,K_ndgrid] = ndgrid(1:3,4:6,7:9,10:12);
[X_meshgrid,Y_meshgrid,Z_meshgrid] = meshgrid(1:3,4:6,7:9);
X_meshgrid_p = permute(X_meshgrid,[2,1,3]);
Y_meshgrid_p = permute(Y_meshgrid,[2,1,3]);
all(X_ndgrid(1:27).' == X_meshgrid_p(:)) % the transpose is only relevant for this comparison, not for the result.
all(Y_ndgrid(1:27).' == Y_meshgrid_p(:)) % the transpose is only relevant for this comparison, not for the result.
all(Z_ndgrid(1:27).' == Z_meshgrid(:)) % the transpose is only relevant for this comparison, not for the result.
and it will return:
ans =
1
ans =
1
ans =
1
If you want to use it as an input for interpn, you should use the ndgrid format.

Related

how to reverse the element of matrix?

I am trying to reverse the elements of the matrix such that for given matrix order of the elements get reversed.
my code is as shown for the 3x3 matrix is working.
X = [ 1 2 3 ; 4 5 6 ; 7 8 9 ];
B = [fliplr(X(3,:));fliplr(X(2,:));fliplr(X(1,:))];
input X =
1 2 3
4 5 6
7 8 9
output:
B =
9 8 7
6 5 4
3 2 1
the above code I am trying to generalize for any matrix with the following code
[a,b]=size(X);
for i=0:a-1
A = [fliplr(X(a-i,:))];
end
but get only last row as output.
output A =
3 2 1
please help me to concatenate all the rows of the matrix one above to each other after it got reversed.
rot90 is the function made for this purpose.
B = rot90(A,2);
Your code doesn't work because you overwrite A in every loop iteration. Instead, you should index into A to save each of your rows.
However, fliplr can flip a whole matrix. You want to flip left/right and up/down:
B = flipud(fliplr(X));
This is the same as rotating the matrix (as Sardar posted while I was writing this):
B = rot90(X,2);
A totally different approach would work for arrays of any dimensionality:
X(:) = flipud(X(:));

MATLAB: Applying vectors of row and column indices without looping

I have a situation analogous to the following
z = magic(3) % Data matrix
y = [1 2 2]' % Column indices
So,
z =
8 1 6
3 5 7
4 9 2
y represents the column index I want for each row. It's saying I should take row 1 column 1, row 2 column 2, and row 3 column 2. The correct output is therefore 8 5 9.
I worked out I can get the correct output with the following
x = 1:3;
for i = 1:3
result(i) = z(x(i),y(i));
end
However, is it possible to do this without looping?
Two other possible ways I can suggest is to use sub2ind to find the linear indices that you can use to sample the matrix directly:
z = magic(3);
y = [1 2 2];
ind = sub2ind(size(z), 1:size(z,1), y);
result = z(ind);
We get:
>> result
result =
8 5 9
Another way is to use sparse to create a sparse matrix which you can turn into a logical matrix and then sample from the matrix with this logical matrix.
s = sparse(1:size(z,1), y, 1, size(z,1), size(z,2)) == 1; % Turn into logical
result = z(s);
We also get:
>> result
result =
8
5
9
Be advised that this only works provided that each row index linearly increases from 1 up to the end of the rows. This conveniently allows you to read the elements in the right order taking advantage of the column-major readout that MATLAB is based on. Also note that the output is also a column vector as opposed to a row vector.
The link posted by Adriaan is a great read for the next steps in accessing elements in a vectorized way: Linear indexing, logical indexing, and all that.
there are many ways to do this, one interesting way is to directly work out the indexes you want:
v = 0:size(y,2)-1; %generates a number from 0 to the size of your y vector -1
ind = y+v*size(z,2); %generates the indices you are looking for in each row
zinv = z';
zinv(ind)
>> ans =
8 5 9

visualizing 2D-graphs of n-dim. array via surf() in matlab

I want to show 2dim. Surface plots for different combinations of 2 parameters of a 3- or higher-dimensional array in matlab. The data for the non-shown dimensions are integrated (i.e. summed in the remaining dimensions). I am using surf(), and for parameter combinations other than (1,2) (eg. (1,3), (2,3) ...) I have to rearrange the data matrices in order to make it work.
I am looking for an alternative command (or shorter code) which does this work.
Here's the code:
a=zeros(3,3,2);
a(:,:,1) = [1 2 3 ;4 5 6; 7 8 9; 10 11 12]; % // data matrix
a(:,:,2) = -[1 2 3 ;4 5 6; 7 8 9; 10 11 12]*2; % // data matrix
ai=[[1 2 3 4]' [5 6 7 0]' [8 9 0 0]']; % // parameter vector
mat12 = sum(a,3);
surf(ai(1:3,2),ai(1:4,1),mat12)
aux13 = sum(a,2);
for i = 1:2; mat13(:,i) = aux13(:,:,i);
surf(ai(1:2,3),ai(1:4,1),mat13)
aux23 = sum(a,1);
for i = 1:2; mat23(i,:) = aux23(:,:,i);
surf(ai(1:3,2),ai(1:2,3),mat23)
In other words, I am looking for a way to use surf for matrices mat13 and mat23 without the aux13, aux23 variables and the for loop.
First your example doesn't run because you declare a=zeros(3,3,2); as a matrix [3x3x2] but you immediately try to populate it as a [4x3x2] matrix, so I had to adjust your first line to: a=zeros(4,3,2);
If I run your code with that adjustment, your auxiliary variable and for loops are to reform/reshape a matrix stripped of it's singleton dimension. Matlab provide a handy function for that : squeeze.
For example, your variable aux13 is of dimension [4x1x2], then mat13=squeeze(aux13); achieve the same thing than your for loop. Your matrix mat13 is now of dimension [4x2].
Since no for loop is needed, you can completely bypass your auxiliary variable by calling squeeze directly on the result of your summation: mat13=squeeze( sum(a,2) );
Full example, the code below does exactly the same than your code sample:
mat12 = sum(a,3);
surf(ai(1:3,2),ai(1:4,1),mat12)
mat13 = squeeze( sum(a,2) ) ;
surf(ai(1:2,3),ai(1:4,1),mat13)
mat23 = squeeze( sum(a,1) ) ;
mat23 = mat23.' ; %'// <= note the "transpose" operation here
surf(ai(1:3,2),ai(1:2,3),mat23)
Note that I had to transpose mat23 to make it match the one in your example.
sum(a,1) is [1x3x2] => squeeze that and you obtain a [3x2] matrix but your code arrange the same values in a [2x3] matrix, so the use of the transpose. The transpose operator has a shorthand notation .'.
I used it in the example in a separate line just to highlight it. Once understood you can simply write the full operation in one line:
mat23 = squeeze(sum(a,1)).' ;
The way you write your loops isn't exactly MATLAB syntax. Below is the correct loop syntax shown.
On line 2 and 3, you are trying to load (4x3)-matrices into (3x3)-matrices. That is why you get a subscript error. You could resolve it by making the zeros-matrix bigger. Here's some Syntax fixed:
a=zeros(4,3,2);
a(:,:,1) = [1 2 3 ;4 5 6; 7 8 9; 10 11 12]; % // data matrix
a(:,:,2) = -[1 2 3 ;4 5 6; 7 8 9; 10 11 12]*2; % // data matrix
ai=[[1 2 3 4]' [5 6 7 0]' [8 9 0 0]']; % // parameter vector
mat12 = sum(a,3);
surf(ai(1:3,2),ai(1:4,1),mat12)
aux13 = sum(a,2);
for i = 1:2 mat13(:,i) = aux13(:,:,i);
surf(ai(1:2,3),ai(1:4,1),mat13)
end
aux23 = sum(a,1);
for i = 1:2 mat23(i,:) = aux23(:,:,i);
surf(ai(1:3,2),ai(1:2,3),mat23)
end
Now, what are you exactly trying to do inside those loops?

combine two n dimensional cell arrays into a n by n dimensional one

I wonder how to do this in MATLAB.
I have a={1;2;3} and would like to create a cell array
{{1,1};{1,2};{1,3};{2,1};{2,2};{2,3};{3,1};{3,2};{3,3}}.
How can I do this without a for loop?
You can use allcomb from MATLAB File-exchange to help you with this -
mat2cell(allcomb(a,a),ones(1,numel(a)^2),2)
Just for fun, using kron and repmat:
a = {1;2;3}
b = mat2cell([kron(cell2mat(a),ones(numel(a),1)) repmat(cell2mat(a),numel(a),1)])
Here square brackets [] are used to perform a concatenation of both column vectors, where each is defined either by kron or repmat.
This can be easily generalized, but I doubt this is the most efficient/fast solution.
Using repmat and mat2cell
A = {1;2;3};
T1 = repmat(A',[length(A) 1]);
T2 = repmat(A,[1 length(A)]);
C = mat2cell(cell2mat([T1(:),T2(:)]),ones(length(T1(:)),1),2);
You can use meshgrid to help create unique permutations of pairs of values in a by unrolling both matrix outputs of meshgrid such that they fit into a N x 2 matrix. Once you do this, you can determine the final result using mat2cell to create your 2D cell array. In other words:
a = {1;2;3};
[x,y] = meshgrid([a{:}], [a{:}]);
b = mat2cell([x(:) y(:)], ones(numel(a)*numel(a),1), 2);
b will contain your 2D cell array. To see what's going on at each step, this is what the output of the second line looks like. x and y are actually 2D matrices, but I'm going to unroll them and display what they both are in a matrix where I've concatenated both together:
>> disp([x(:) y(:)])
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Concatenating both vectors together into a 2D matrix is important for the next line of code. This is a vital step in order to achieve what you want. After the second line of code, the goal will be to make each element of this concatenated matrix into an individual cell in a cell array, which is what mat2cell is doing in the end. By running this last line of code, then displaying the contents of b, this is what we get:
>> format compact;
>> celldisp(b)
b{1} =
1 1
b{2} =
1 2
b{3} =
1 3
b{4} =
2 1
b{5} =
2 2
b{6} =
2 3
b{7} =
3 1
b{8} =
3 2
b{9} =
3 3
b will be a 9 element cell array and within each cell is another cell array that is 1 x 2 which stores one row of the concatenated matrix as individual cells.

Averaging every n elements of a vector in matlab

I would like to average every 3 values of an vector in Matlab, and then assign the average to the elements that produced it.
Examples:
x=[1:12];
y=%The averaging operation;
After the operation,
y=
[2 2 2 5 5 5 8 8 8 11 11 11]
Therefore the produced vector is the same size, and the jumping average every 3 values replaces the values that were used to produce the average (i.e. 1 2 3 are replaced by the average of the three values, 2 2 2). Is there a way of doing this without a loop?
I hope that makes sense.
Thanks.
I would go this way:
Reshape the vector so that it is a 3×x matrix:
x=[1:12];
xx=reshape(x,3,[]);
% xx is now [1 4 7 10; 2 5 8 11; 3 6 9 12]
after that
yy = sum(xx,1)./size(xx,1)
and now
y = reshape(repmat(yy, size(xx,1),1),1,[])
produces exactly your wanted result.
Your parameter 3, denoting the number of values, is only used at one place and can easily be modified if needed.
You may find the mean of each trio using:
x = 1:12;
m = mean(reshape(x, 3, []));
To duplicate the mean and reshape to match the original vector size, use:
y = m(ones(3,1), :) % duplicates row vector 3 times
y = y(:)'; % vector representation of array using linear indices