Aligning face data from MATLAB triangulation - matlab

I have a function f(x,y) which has certain symmetries that I would like to plot. Here is an example:
This plot can be generated with:
[x,y,z] =
0 0 0.1415
0.1999 0.1999 0.1165
0.2760 0 0.1268
0.3694 0.3694 0.0983
0.4830 0 0.1142
0.5090 0.5090 0.0903
0.5550 0.1871 0.0881
0.6189 0.3558 0.0715
0.6197 0.6197 0.0907
0.6399 0 0.1056
0.7071 0.7071 0.1415
0.7169 0.4835 0.0869
0.7215 0.1200 0.0859
0.7304 0.2392 0.0680
0.7643 0 0.1005
0.7926 0.3574 0.0856
0.8090 0.5878 0.1393
0.8581 0.1122 0.0821
0.8634 0.2343 0.0878
0.8794 0 0.0986
0.8910 0.4540 0.1332
0.9511 0.3090 0.1253
0.9877 0.1564 0.1191
1.0000 0 0.1169
t =
6 4 8
12 6 8
8 4 7
4 2 7
8 7 14
14 7 13
3 2 1
5 7 3
3 7 2
17 12 21
6 12 9
9 17 11
12 17 9
10 15 13
10 7 5
13 7 10
21 12 16
16 12 8
8 14 16
18 14 13
15 20 18
13 15 18
24 23 18
18 20 24
21 16 22
23 22 19
19 18 23
14 18 19
19 16 14
19 22 16
trisurf(t,x,y,z)
So I know that function has a reflection symmetry about y=x and then the resulting function is to be repeated in all the quadrants. Here is the code to do this:
allx = [x; x;-x;-x;y; y;-y;-y];
ally = [y;-y; y;-y;x;-x; x;-x];
allz = [z; z; z; z;z; z; z; z];
These are the new vertices for the surface I want to plot. Now how do I properly generate the faces for this new surface?
When I use a finer mesh and add some pretty lights it should look something like this:

Speculative:
So your question is about how to set-up the first argument of trisurf, i.e. how to define the extended t in your code. According to the docs this is the index into the vertices defined by the remaining arguments. I don't have MATLAB installed on this machine, but what happens if you do:
allx = [x; x;-x;-x];
ally = [y;-y; y;-y];
allz = [z; z; z; z];
s = size(x,1);
t = [t; t + s; t + 2*s; t + 3*s]
Just trying to think if this makes sense and if/how it extends into the other quadrants.

Related

Create Spiral Matrix Matlab

Can any one help creating spiral matrix in matlab using only loops and if else conditions.
For example n=5, spiral matrix is:
17 16 15 14 13
18 5 4 3 12
19 6 1 2 11
20 7 8 9 10
21 22 23 24 25
There is a function spiral in your MATLAB installation, doing exactly what you want.
>> spiral(5)
ans =
21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
You can view the source code typing edit spiral
Try this:
nn = input('');
n = floor(1+(nn)/2);
a = zeros(nn,nn);
i=n;j=n;m=1;br=true;
if rem(nn,2)==0
j=n-1;
nn=nn+2;
end
for p=1:2:nn
k=0;
while k<p-2
k=k+1;
a(i,j)=m;
i=i-1;
m=m+1;
end
k=0;
while k<p-1
k=k+1;
a(i,j)=m;
j=j-1;
m=m+1;
end
k=0;
while k<p-1
if j<1
br = false;
break
end
k=k+1;
a(i,j)=m;
i=i+1;
m=m+1;
end
if ~br
break
end
k=0;
while k<p
k=k+1;
a(i,j)=m;
j=j+1;
m=m+1;
end
end
disp(a)
Here is a sample run:
Enter the number:
5
17 16 15 14 13
18 5 4 3 12
19 6 1 2 11
20 7 8 9 10
21 22 23 24 25
Another one, this time using an even number:
Enter the number:
6
36 35 34 33 32 31
17 16 15 14 13 30
18 5 4 3 12 29
19 6 1 2 11 28
20 7 8 9 10 27
21 22 23 24 25 26
Explanation: It starts with the central cell in the case of an odd number as input, and the bottom-left central cell in the case of an even input. It then, starting with 1 as the value and taking one circulation at a time, moves outwards, traverses right, up, left, down, and right again, incrementing the value to be assigned with each step, until the entire matrix is full.
Here is a custom function SpiralMatrix to construct the spiral matrix as your requested
function M = SpiralMatrix(n)
M = zeros(n);
% start from element M(1,1)
i = 1;
j = 1;
s = 1; % first element assigned to M(1,1)
M(i,j) = s;
while true
% fill row from left to right
idx = find(M(i,:)==0,1,'last');
M(i,j:idx) = s + (0:(idx-j));
s = s + idx - j;
j = idx;
% fill column from top to bottom
idx = find(M(:,j)==0,1,'last');
M(i:idx,j) = s + (0:(idx-i));
s = s + idx - i;
i = idx;
% fill row from right to left
idx = find(M(i,:)==0,1,'first');
M(i,j:-1:idx) = s + (0:(j-idx));
s = s + j - idx;
j = idx;
% fill column from bottom to top
idx = find(M(:,j)==0,1,'first');
M(i:-1:idx,j) = s + (0:(i-idx));
s = s + i-idx;
i = idx;
% break if matrix if fully filled
if nnz(M) == n^2
break;
end
end
M = n^2+1-fliplr(flipud(M));
end
such that
>> SpiralMatrix(5)
ans =
17 16 15 14 13
18 5 4 3 12
19 6 1 2 11
20 7 8 9 10
21 22 23 24 25
>> SpiralMatrix(7)
ans =
37 36 35 34 33 32 31
38 17 16 15 14 13 30
39 18 5 4 3 12 29
40 19 6 1 2 11 28
41 20 7 8 9 10 27
42 21 22 23 24 25 26
43 44 45 46 47 48 49

display mean instead of median in boxplot matlab

I have the example code below:
A = [16 20 15 17 22 19 17]';
B = [22 15 16 16 16 18]';
C = [23 9 15 18 13 27 17 14 16 15 21 19 17]';
group = [ ones(size(A));
2 * ones(size(B));
3;
4 * ones(size(C))
];
figure();
boxplot([A; B; NaN; C],group);
set(gca,'XTickLabel',{'A','B','','C'});
what can I add to the code to show the mean of each vector in the box plot instead of the median (which is a Matlab default), I know how to do it for one vector but if we have multiple boxplots, I need some help how to do it.
any suggestion, please?
Try removing the median line and then plotting the relevant means
:
A = [16 20 15 17 22 19 17]';
B = [22 15 16 16 16 18]';
C = [23 9 15 18 13 27 17 14 16 15 21 19 17]';
% Calculate means
meanOfA = mean(A);
meanOfB = mean(B);
meanOfC = mean(C);
group = [ ones(size(A));
2 * ones(size(B));
3;
4 * ones(size(C))
];
figure;
boxplot([A; B; NaN; C],group);
set(gca,'XTickLabel',{'A','B','','C'});
% Find handle for median line and set visibility off
h = findobj(gca,'Tag','Median');
set(h,'Visible','off');
%plot means as black asterisks.
hold on
plot(1,meanOfA, 'k*')
plot(2,meanOfB, 'k*')
plot(4,meanOfC, 'k*')

Fastest code to merge two matrices of different dimension in Matlab

I have two matrices in Matlab A and B respectively of dimension MxN and GxN.
M can be greater or smaller than G.
A and B do not contain identical rows.
I want to construct a matrix C of dimension Hx(N+2) in the following way
C=[];
for i=1:size(A,1)
%if A(i,1:end-1) coincides with a row in B(:,1:end-1) (it can coincide with only one row at most)
%then C=[C;A(i,1:end) B(j,end)]; %where j is the index of the identical row in B
%otherwise impose C=[C;A(i,1:end) 0]
end
for i=1:size(B,1)
%if B(i,1:end-1) does not coincide with any row in A(:,1:end-1)
%then impose C=[C; B(i,1:end-1) 0 B(i,end)];
end
For example:
A=[1 2 3 4 5 100; 6 7 8 9 10 101; 11 12 13 14 15 102];
B=[6 7 8 9 10 103; 15 16 17 18 19 104]
C=[1 2 3 4 5 100 0; 6 7 8 9 10 101 103; 11 12 13 14 16 102 0; 15 16 17 18 19 0 104]
As M and G can be very high, I am looking for the fastest way to perform this.
You can use ismember + indexing to do your task:
[idx1,idx2] = ismember(A(:,1:end-1), B(:,1:end-1), 'rows');
idx3 = ~ismember(B(:,1:end-1), A(:,1:end-1), 'rows');
C(idx1,:) = [A(idx1,:) B(idx2(idx1),end)];
C(~idx1,:) = [A(~idx1,:) zeros(sum(~idx1),1)];
C=[C;B(idx3,1:end-1) zeros(sum(idx3),1) B(idx3,end)];
You could also use intersect with a bit of preallocation to speed up the assignment (if M or G gets really large).
A=[1 2 3 4 5 100; 6 7 8 9 10 101; 11 12 13 14 15 102];
B=[6 7 8 9 10 103; 15 16 17 18 19 104];
C=[1 2 3 4 5 100 0; 6 7 8 9 10 101 103; 11 12 13 14 16 102 0; 15 16 17 18 19 0 104];
[M,N] = size(A);
G = size(B,1);
[tmp, idxA, idxB] = intersect(A(:,1:end-1),B(:,1:end-1),'rows')
idxBnotA = setdiff([1:G],idxB);
H = M + G - length(idxA);
C1 = zeros(H,N+1);
C1(1:M,1:N) = A;
C1(idxA,end) = B(idxB,end);
C1(M+1:end,1:end-2) = B(idxBnotA,1:end-1);
C1(M+1:end,end) = B(idxBnotA,end)

How to sample matrix elements in matlab

I have a list of coordinates I would like to sample from a Matrix.
Is there any elegant way to do it?
Ideally, something that looks like:
A = magic(5)
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
r = 1:5; % row coordinates
c = 5:-1:1; % column coordinates
A(r,c)
ans =
15 14 13 12 11
Which is equivalent to
for k=1:length(r)
A(r(k), c(k))
end
I am sure someone has asked that, but I couldn't find it anywhere.
Applying #excaza comment I was able to solve this with:
rc_ids = sub2ind(size(A), r,c);
A(rc_ids)

Matlab: Cut Vector at missing values and create new vectors

I want to write a Matlab script.
In my example I have a vector A=[1 3 4 5 7 8 9 10 11 13 14 15 16 17 19 20 21]
Now I want to cut the vector automatically at the points where a number is missing(here the numbers 2, 6, 12, 18 are missing).
As a result I want to have the vectors [1] and [3 4 5] and [7 8 9 10 11] and [13 14 15 16 17] and [19 20 21]. So as you can see the new vectors have different lenghts.
I thought about using a for loop, but I am not sure how to write these new vectors.
Thank you for your help :)
One liner with diff, cumsum & accumarray -
out = accumarray(cumsum([0 ; diff(A(:))~=1])+1,A(:),[],#(x) {x})
Sample run -
>> A
A =
1 3 4 5 7 8 9 10 ...
11 13 14 15 16 17 19 20 21
>> celldisp(out)
out{1} =
1
out{2} =
3
4
5
out{3} =
7
8
9
10
11
out{4} =
13
14
15
16
17
out{5} =
19
20
21
This is one approach:
s = [find(diff(A(:).')>1) numel(A)]; %'// detect where consecutive difference exceeds 1
s = [s(1) diff(s)]; %// sizes of groups
result = mat2cell(A(:).', 1, s); %'// split into cells according to those sizes
In your example, this gives
>> celldisp(result)
result{1} =
1
result{2} =
3 4 5
result{3} =
7 8 9 10 11
result{4} =
13 14 15 16 17
result{5} =
19 20 21
Another approach (computes group sizes differently):
s = diff([0 sum(bsxfun(#lt, A(:), setdiff(1:max(A(:).'), A(:).')), 1) numel(A)]);
result = mat2cell(A(:).', 1, s);