New coordinates when reshaping a Matrix in Matlab - matlab

Take a 4-D matrix A with s1=size(A,1), s2=size(A,2), s3=size(A,3), s4=size(A,4).
Consider
B=reshape(A, s1*s2*s3*s4,1)
For example,
s1=2;
s2=3;
s3=2;
s4=4;
A(:,:,1,1)=[1 2 3; 4 5 6];
A(:,:,1,2)=[7 8 9; 10 11 12];
A(:,:,1,3)=[13 14 15; 16 17 18];
A(:,:,1,4)=[19 20 21; 22 23 24];
A(:,:,2,1)=[25 26 27; 28 29 30];
A(:,:,2,2)=[31 32 33; 34 35 36];
A(:,:,2,3)=[37 38 39; 40 41 42];
A(:,:,2,4)=[43 44 45; 46 47 48];
B=reshape(A, s1*s2*s3*s4,1);
%B=[1;4;2;5;3;6;25;28;26;29;27;30;7;10;8;11;9;12;...];
Given coordinates (i,j,h,k), I would like your help to write a function that gives me the position of A(i,j,h,k) in B.
I know how to do that when A is a 3-D matrix. In that case,
position_in_B= i + ( j-1 + (h-1)*s2 ) * s1;
How can I extend this result to 4-D matrices?

Here you can use sub2ind , for example:
B(sub2ind(size(A),1,1,1,4))
or you can continue with the extension you wrote:
position_in_B= #(i,j,h,k) i + ( j-1 + ( h-1 + (k-1) *s3 ) *s2 ) * s1;
B(position_in_B(1,1,1,4))

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*')

distance between box plots with unequal samples

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:

How to use rank index number to sort other set of data using loops?

I am quite new to Matlab, and am tasked to use Matlab to manage a finance/econs database.
To cut straight to the problem. Just imagine I have two sets of data, one is A and another one is B (see below). My objective is to rank the 3 columns according to value size, and then I would like to use the rank index for A (sorted_index) to position the values in B accordingly.
Below is the working but non-looping solution to obtain my answer:
A = [5 17 8; 11 2 9; 55 70 3; 11 8 33; 9 71 35; 9 2 3; 21 5 43; 5 2 9; 41 5 23; 61 72 91];
B = [1 2 3; 11 12 13; 21 22 23; 31 32 33; 1 2 3; 11 12 13; 21 22 23; 31 32 33; 41 42 43; 51 52 53];
[A_sorted sorted_index] = sort (A);
[B_sorted sorted_indexB] = sort (B);
B_sorted (:,1) = B(sorted_index(:,1),1);
B_sorted (:,2) = B(sorted_index(:,2),2);
B_sorted (:,3) = B(sorted_index(:,3),3);
The outcome of B (sorted according to the rank position of A):
1 12 23
31 12 13
1 32 3
11 22 13
11 42 33
31 32 43
21 2 33
41 22 3
21 2 23
51 52 53
The problem is, what if I have 2000 columns instead of just 3, how can i loop successfully?
I tried this
for ii= size(B,2); jj= size(B,2) ; kk= size(B,2);
temp = 0*B;
temp(:,ii) = B(sorted_index(:,jj),kk);
B_sortedTest= temp;
end
But it only turns out to give me the correct sorted result for the last column, the first two columns are overwritten (become all zeros). Can you help me to solve the problem?
Thank you very very much!
Here is my method without any loops:
A = [5 17 8; 11 2 9; 55 70 3; 11 8 33; 9 71 35; 9 2 3; 21 5 43; 5 2 9; 41 5 23; 61 72 91];
B = [1 2 3; 11 12 13; 21 22 23; 31 32 33; 1 2 3; 11 12 13; 21 22 23; 31 32 33; 41 42 43; 51 52 53];
[A_sorted sorted_index] = sort (A);
% converting sorted_index into a vectorized form and having linear indices instead of subscripts i.e.
% (row 2,column 3) in your sorted_index will be represented as 23=2*number of rows + 3=2*10+3.
linearSortedIndex=sub2ind(size(sorted_index),sorted_index(:),reshape(repmat((1:size(sorted_index,2),size(sorted_index,1),1).*ones(size(sorted_index)),[],1));
B_sorted1=reshape(B(linearSortedIndex),[],size(B,2));
%test that the result is correct
for i=1:size(B,2)
B_sorted2(:,i) = B(sorted_index(:,i),i);
end
isequal(B_sorted1,B_sorted2) %If it prints 1, then this method is correct.
Try this:
A = [5 17 8; 11 2 9; 55 70 3; 11 8 33; 9 71 35; 9 2 3; 21 5 43; 5 2 9; 41 5 23; 61 72 91];
B = [1 2 3; 11 12 13; 21 22 23; 31 32 33; 1 2 3; 11 12 13; 21 22 23; 31 32 33; 41 42 43; 51 52 53];
[A_sorted sorted_index] = sort (A);
[B_sorted sorted_indexB] = sort (B);
for i=1:size(B,2)
B_sorted (:,i) = B(sorted_index(:,i),i);
end

Contour Map NOT Circular in MATLAB

I'm trying get a basic circular temperature contour graph in MATLAB.
Instead, I'm getting a straight line and doesn't resemble at all to
MATLAB's examples for contour maps. I want 4 circular zones
representing 90 degrees, 80 degrees, 70 degrees, and 60 degrees.
Here is my code:
long = [0 1 2 3; 4 5 6 7; 8 9 10 11; 12 13 14 15];
lat = [15 16 17 18; 19 20 21 22; 23 24 25 26; 27 28 29 30];
temp = [98 95 94 92; 85 82 81 80; 72 75 74 71; 65 62 61 69];
figure;
contour(long,lat,temp,4)
The problem is that you've only provided a line of data and not a matrix. You need to provide a temperature for each pair of long and lat. So if long and lat are both 1x15 then temp should be 15x15.
For example:
x = 1:3
y = 1:3
z = [1 2 1; 2 3 2; 1 2 1];
contour(x,y,z);