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
Related
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*')
I would like to draw a bar chart with "unequal samples". Here is an example code
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 * ones(size(C))];
figure
boxplot([A; B; C],group)
set(gca,'XTickLabel',{'A','B','C'})
The output is as below:
However, I would like to have a distance between group1,2 with group 3. As same as what you see in the figure below:(this figure is just a copy paste from another source but the distance between box plot of each group is visible)
I tried to use 'factorgap' in such command
figure
boxplot([A; B; C ],group,'factorgap',[50,1])
However, because the number of samples in each group is different it did not work.
Any suggestion?
The first solution I propose you is in fact a small workaround that consists in inserting another, invisible group between the second and the third one:
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'});
Here is the output:
Now, let's build up something serious:
% Define the sample data...
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]';
% Find the length of the largest vector...
A_len = numel(A);
B_len = numel(B);
C_len = numel(C);
max_len = max([A_len B_len C_len]);
% Transform vectors into fixed size vectors of length max_len...
A = [A; NaN(max_len - A_len,1)];
B = [B; NaN(max_len - B_len,1)];
C = [C; NaN(max_len - C_len,1)];
% Define labels and groups...
L1 = [repmat('A',1,numel(A)),repmat('B',1,numel(B))];
L2 = repmat('C',1,numel(C));
L = [L1 L2];
G = [repmat('1',1,numel(L1)),repmat('2',1,numel(L2))];
% Plot the boxes...
boxplot([A B C],{G';L'},'FactorGap',50);
Here is the output:
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)
I'm trying to implement the Baker map.
Is there a function that would allow one to divide a 8 x 8 matrix by providing, for example, a sequence of divisors 2, 4, 2 and rearranging pixels in the order as shown in the matrices below?
X = reshape(1:64,8,8);
After applying divisors 2,4,2 to the matrix X one should get a matrix like A shown below.
A=[31 23 15 7 32 24 16 8;
63 55 47 39 64 56 48 40;
11 3 12 4 13 5 14 6;
27 19 28 20 29 21 30 22;
43 35 44 36 45 37 46 38;
59 51 60 52 61 53 62 54;
25 17 9 1 26 18 10 2;
57 49 41 33 58 50 42 34]
The link to the document which I am working on is:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.39.5132&rep=rep1&type=pdf
This is what I want to achieve:
Edit: a little more generic solution:
%function Z = bakermap(X,divisors)
function Z = bakermap()
X = reshape(1:64,8,8)'
divisors = [ 2 4 2 ];
[x,y] = size(X);
offsets = sum(divisors)-fliplr(cumsum(fliplr(divisors)));
if any(mod(y,divisors)) && ~(sum(divisors) == y)
disp('invalid divisor vector')
return
end
blocks = #(div) cell2mat( cellfun(#mtimes, repmat({ones(x/div,div)},div,1),...
num2cell(1:div)',...
'UniformOutput',false) );
%create index matrix
I = [];
for ii = 1:numel(divisors);
I = [I, blocks(divisors(ii))+offsets(ii)];
end
%create Baker map
Y = flipud(X);
Z = [];
for jj=1:I(end)
Z = [Z; Y(I==jj)'];
end
Z = flipud(Z);
end
returns:
index matrix:
I =
1 1 3 3 3 3 7 7
1 1 3 3 3 3 7 7
1 1 4 4 4 4 7 7
1 1 4 4 4 4 7 7
2 2 5 5 5 5 8 8
2 2 5 5 5 5 8 8
2 2 6 6 6 6 8 8
2 2 6 6 6 6 8 8
Baker map:
Z =
31 23 15 7 32 24 16 8
63 55 47 39 64 56 48 40
11 3 12 4 13 5 14 6
27 19 28 20 29 21 30 22
43 35 44 36 45 37 46 38
59 51 60 52 61 53 62 54
25 17 9 1 26 18 10 2
57 49 41 33 58 50 42 34
But have a look at the if-condition, it's just possible for these cases. I don't know if that's enough. I also tried something like divisors = [ 1 4 1 2 ] - and it worked. As long as the sum of all divisors is equal the row-length and the modulus as well, there shouldn't be problems.
Explanation:
% definition of anonymous function with input parameter: div: divisor vector
blocks = #(div) cell2mat( ... % converts final result into matrix
cellfun(#mtimes, ... % multiplies the next two inputs A,B
repmat(... % A...
{ones(x/div,div)},... % cell with a matrix of ones in size
of one subblock, e.g. [1,1,1,1;1,1,1,1]
div,1),... % which is replicated div-times according
to actual by cellfun processed divisor
num2cell(1:div)',... % creates a vector [1,2,3,4...] according
to the number of divisors, so so finally
every Block A gets an increasing factor
'UniformOutput',false...% necessary additional property of cellfun
));
Have also a look at this revision to have a simpler insight in what is happening. You requested a generic solution, thats the one above, the one linked was with more manual inputs.
I have a loop:
for i=1:size(A,1),
if A(i,4:6) == [0,0,3.4]
K = [K; A(i,:)];
end
end
and I would like to delete the last row in the matrix but I do not know what number row it will be. How do I delete the last row in the matrix in the loop? Or should I do it after the loop?
Why do you have loop? it is a one time action, not something you do several times.
check this out, I delete the last row:
>> a = magic(5);
>> a
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
>> a = a(1:end-1,:);
>> a
a =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
you can refer to last row by END keyword:
A= A(1:end-1, :)