Line plot of rows in a Matlab matrix with the x-axis is the maximum value - matlab

I am new here and new to matlab.
I have a matrix file in matlab and what I want to do is make a plot of the average all the rows. However, I only want to plot a few data points (about 20) of the values before, and after, the maximum value within that row. The matrix file has 550 columns.
I have worked out how to identify the maximum value and the column number of this maximum value using;
[maxvalue maxindex] = max(filename, [], 2)
As the maximum is never in the same column, i really need help in calculating the average values for each row (before and afer the max value), and then how to plot this where the maximum value would be 0 on the x-axis.
For example - i have a matrix like this;
14 51 623 23 4 1 4 5
0 0 3 5 67 37 37 5
0 0 0 0 574 4 5 6
and max value = 623
67
574
and max index = 3
5
5
So i would like to, plot the average of the 3 rows, 2 data points before and after the max values...so to plot the average of;
14, 51, 623, 23, 4, 1
3, 5, 67, 37, 37
0, 0, 574, 4, 5
Thanks so much for any help!

data = [14 51 623 23 4 1 4 5
0 0 3 5 67 37 37 5
0 0 0 0 574 4 5 6]; %// example data
data = data.'; %'// it's easier to work along columns
[~, pos] = max(data); %// position of maxima
ind = bsxfun(#plus,bsxfun(#plus, pos,(-2:2).'),(0:size(data,2)-1)*size(data,1));
%'// linear index into the matrix obtained from pos
data_trimmed = data(ind).'; %'// index and transpose back
data = data.'; %'// undo transpose to put data back into shape
Result:
data_trimmed =
14 51 623 23 4
3 5 67 37 37
0 0 574 4 5

Related

How to shift non circularly in Matlab

I am trying to shift non circularly in MATLAB so even if I shift outside of the index it will add 0s to correct it. I tried following the answer in How do I shift columns (left or right) in a matrix? but had no success.
data = [1 2 3 4 5; 11 12 13 14 15; 21 22 23 24 25; 31 32 33 34 35]
d = 3; % shift; positive/negative for right/left
result = zeros(size(data), 'like', data); % preallocate with zeros
result(:,max(1,1+d):min(end,end+d)) = data(:,max(1,1-d):min(end,end-d)); % write values
In my output results is nothing but the same size but all zeroes
Desired output:
0 0 0 1 2 3 4 5
0 0 0 11 12 13 14 15
0 0 0 21 22 23 24 25
0 0 0 31 32 33 34 35
You can do it by creating a matrix result, the final size, filled with zeros, then copying the original data into the final result, making sure you place the data at the right indices.
What you have in your example code is not right for what you ask. If I run it,the final result is padded fine but truncated at the size of the original data matrix. This is how some matrix are shifted (with the shifted columns dropped altogether), but that's not what you asked.
A simple way to do it, is to create a padding matrix of the proper size, then simply concatenate it with your original data matrix. This can be done as below:
%% Initial data
data = [1 2 3 4 5; 11 12 13 14 15; 21 22 23 24 25; 31 32 33 34 35] ;
d = 3 ;
%% shift and pad with zeros
nrows = size(data,1) ; % Number of rows in [data]
pad = zeros( nrows , abs(d) ) ; % create padding matrix
if d>0
result = [pad data] ; % Concatenate the filler matrix on the left
else
result = [data pad] ; % Concatenate the filler matrix on the right
end
And just to be sure:
>> result
result =
0 0 0 1 2 3 4 5
0 0 0 11 12 13 14 15
0 0 0 21 22 23 24 25
0 0 0 31 32 33 34 35
If you want to reuse the same way than in your example code, you have to adjust it a bit to allow for the new columns:
%% create result and copy data
result = zeros( size(data,1) , size(data,2)+abs(d) ) ;
colStart = max(1,1+d) ;
result(:,colStart:colStart+size(data,2)-1) = data ;
This will create the same result matrix as above.

Embedding an array into another

I have two arrays. The first one is a consecutive sequential one, like:
seq1 =
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
...continues
The second one is like:
seq2 =
2 250
3 260
5 267
6 270
8 280
10 290
13 300
18 310
20 320
21 330
...continues
I need to embed seq2 into seq1 in such a way that I end up with the sequence:
seq3 =
1 0
2 250
3 260
4 260
5 267
6 270
7 270
8 280
9 280
10 290
11 290
... continues
I could do this with loops but the arrays are really big so I don't want to use two for loops, it is taking too long. How can I do this in a vectorised manner?
I think this does what you want:
[~, jj, vv] = find(sum(bsxfun(#le, seq2(:,1), seq1(:,1).'), 1));
seq3 = seq1;
seq3(jj,2) = seq2(vv,2);
How it works
The required index is obtained by computing how many values in the first column of seq2 are less than or equal to each value in the first column or seq1 (code sum(bsxfun(#le, ...), 1)). This will be used to select the appropriate entries from the second column of seq2 and write them into the result. But before that, the value 0 in this index needs to be discarded. This is done using the three-output version of find (code [~, jj, vv] = find(...)).
If your second column of data is always increasing, you can solve this easily with accumarray and cummax:
seq = [seq1; seq2];
seq3 = cummax(accumarray(seq(:, 1), seq(:, 2), [], #max));
seq3 = [(1:numel(seq3)).' seq3];
And here's what you get for your sample inputs:
seq3 =
1 0
2 250
3 260
4 260
5 267
6 270
7 270
8 280
9 280
10 290
11 290
12 290
13 300
14 300
15 300
16 300
17 300
18 310
19 310
20 320
21 330
How it works...
After concatenating seq1 and seq2, accumarray collects all the values in the second column that have the same value in the first column (i.e. [0 250] for the value 2), then gets the maximum value of each set. The function cummax is then used to fill any zero values with the previous non-zero value. Finally, an index column is added to the new sequence.

Create adjacency matrix from nearest neighbour search. (convert adjacency list to adjacency matrix) - Matlab

I have a matrix 2000x5, in the first column the point number, and in columns 2-5 the 4 neighbours (0s if there isnt a neighbour). Is there an efficient way to create an adjacency matrix out of this ?
1 129 0 65 0
2 130 0 66 85
3 131 169 67 0
4 132 170 68 87
5 133 0 69 81
6 134 0 70 82
7 135 173 71 83
8 136 174 72 84
9 137 161 73 0
10 138 162 74 93
11 139 163 75 0
12 140 164 76 95
13 141 165 77 89
14 142 166 78 90
15 143 167 79 91
16 144 168 80 92
17 145 0 81 65
18 146 0 82 66
....
I found the following thread, where it is explained for just one neighbour, but I am not sure how to use it for multiple neighbours.
matlab adjacency list to adjacency matrix
I would very much appreciate any help.
A quick and simple technique:
adjMat = zeros(size(A,1));
for ind = 1:size(A,1)
% Flag 1 on each row 'ind' at the indices mentioned in col 2-5
adjMat(ind, nonzeros(A(ind,2:end))) = 1;
end
Since you have mentioned using the nearest neighbour search, it is likely that the adjacency list should be completely filled to result in a undirected graph, in the sense that if row 1 has 20 as a neighbour, row 20 very likely has 1 as a neighbour.
However technically speaking, this will produce an adjacency matrix exactly equivalent to the adjacency list, assuming nothing by itself.
Example:
For an adjacency list
A = [1 2 3; 2 0 1; 3 1 4; 4 5 3; 5 4 0]
A =
1 2 3
2 0 1
3 1 4
4 5 3
5 4 0
The result is:
adjMat =
0 1 1 0 0
1 0 0 0 0
1 0 0 1 0
0 0 1 0 1
0 0 0 1 0
P.S. To force undirected-ness, you can simply add another statement in the for loop body:
adjMat(nonzeros(A(ind,2:end)),ind) = 1;
This will ensure that the adjacency matrix will be symmetric, which is a characteristic of undirected graphs.
Firstly, I'm going to assume that the adjacency list is undirected. In any case, it's not that far of a stretch to go to multiple neighbours. What you need to do first is detect the total number of non-zero elements per row from columns 2 to 5. Once you do this, for the rows of the adjacency matrix, you would copy the point number for as many times as there are non-zero elements per that row. The function repelem is perfectly suitable to do that for you. The column indices would simply be the second to fifth columns removing all of the zero elements. How you can do this is first transpose the matrix resulting in indexing the second to fifth columns, then using a logical indexing matrix to remove out the zero entries. Doing this will unroll your vector in a column-major fashion, which is why transposing is required before doing this operation. Once you do this, you can create row and column access indices so that these can be input into sparse much like that post you linked.
Supposing that your matrix was stored in A, you would do something like this. This also assumes that each of the weights connecting the nodes are 1:
% Find total number of non-zero elements per row, skipping first column
non_zero = sum(A(:,2:end) ~= 0, 2);
% Create row indices
rows = repelem(A(:,1), non_zero);
% Create column indices
cols = A(:,2:end).';
cols = cols(cols ~= 0);
% Create adjacency matrix
adj = sparse([rows; cols],[cols; rows], 1);
The above representation is in sparse. If you want the full numeric version, cast the output using full:
adj = full(adj);
If your graph is directed
If you have a directed graph instead of an undirected graph, the above call to sparse duplicates edges so that you are creating links to and from each of the neighbours. If your graph is actually directed, then you simply have to only use the row and column indices once instead of twice as seen in the above code:
% Create adjacency matrix
adj = sparse(rows, cols , 1);
Test Case
Here's a small test case to show you that this works. Supposing my adjacency list looked like the following:
>> A = [1 0 2 3; 2 4 0 0; 3 0 0 4]
A =
1 0 2 3
2 4 0 0
3 0 0 4
The adjacency matrix is now:
>> full(adj)
ans =
0 1 1 0
1 0 0 1
1 0 0 1
0 1 1 0
Taking a look at the list above and how the matrix is populated, we can verify that this is correct.
Note about repelem
repelem assumes you have MATLAB R2015a or later. If you don't have this, you can consult this answer by user Divakar on a custom implementation of repelem here: Repeat copies of array elements: Run-length decoding in MATLAB

Find closest matching distances for a set of points in a distance matrix in Matlab

I have a matrix of measured angles between M planes
0 52 77 79
52 0 10 14
77 10 0 3
79 14 3 0
I have a list of known angles between planes, which is an N-by-N matrix which I name rho. Here's is a subset of it (it's too large to display):
0 51 68 75 78 81 82
51 0 17 24 28 30 32
68 17 0 7 11 13 15
75 24 7 0 4 6 8
78 28 11 4 0 2 4
81 30 13 6 2 0 2
82 32 15 8 4 2 0
My mission is to find the set of M planes whose angles in rho are nearest to the measured angles.
For example, the measured angles for the planes shown above are relatively close to the known angles between planes 1, 2, 4 and 6.
Put differently, I need to find a set of points in a distance matrix (which uses cosine-related distances) which matches a set of distances I measured. This can also be thought of as matching a pattern to a mold.
In my problem, I have M=5 and N=415.
I really tried to get my head around it but have run out of time. So currently I'm using the simplest method: iterating over every possible combination of 3 planes but this is slow and currently written only for M=3. I then return a list of matching planes sorted by a matching score:
function [scores] = which_zones(rho, angles)
N = size(rho,1);
scores = zeros(N^3, 4);
index = 1;
for i=1:N-2
for j=(i+1):N-1
for k=(j+1):N
found_angles = [rho(i,j) rho(i,k) rho(j,k)];
score = sqrt(sum((found_angles-angles).^2));
scores(index,:)=[score i j k];
index = index + 1;
end
end;
end
scores=scores(1:(index-1),:); % was too lazy to pre-calculate #
scores=sortrows(scores, 1);
end
I have a feeling pdist2 might help but not sure how. I would appreciate any help in figuring this out.
There is http://www.mathworks.nl/help/matlab/ref/dsearchn.html for closest point search, but that requires same dimensionality. I think you have to bruteforce find it anyway because it's just a special problem.
Here's a way to bruteforce iterate over all unique combinations of the second matrix and calculate the score, after that you can find the one with the minimum score.
A=[ 0 52 77 79;
52 0 10 14;
77 10 0 3;
79 14 3 0];
B=[ 0 51 68 75 78 81 82;
51 0 17 24 28 30 32;
68 17 0 7 11 13 15;
75 24 7 0 4 6 8;
78 28 11 4 0 2 4;
81 30 13 6 2 0 2;
82 32 15 8 4 2 0];
M = size(A,1);
N = size(B,1);
% find all unique permutations of `1:M`
idx = nchoosek(1:N,M);
K = size(idx,1); % number of combinations = valid candidates for matching A
score = NaN(K,1);
idx_triu = triu(true(M,M),1);
Atriu = A(idx_triu);
for ii=1:K
partB = B(idx(ii,:),idx(ii,:));
partB_triu = partB(idx_triu);
score = norm(Atriu-partB_triu,2);
end
[~, best_match_idx] = min(score);
best_match = idx(best_match_idx,:);
The solution of your example actually is [1 2 3 4], so the upperleft part of B and not [1 2 4 6].
This would theoretically solve your problem, and I don't know how to make this algorithm any faster. But it will still be slow for large numbers. For example for your case of M=5 and N=415, there are 100 128 170 583 combinations of B which are a possible solution; just generating the selector indices is impossible in 32-bit because you can't address them all.
I think the real optimization here lies in cutting away some of the planes in the NxN matrix in a preceding filtering part.

Comparing two matrix and took the value if match the criteria

I have some question. I have 2 matrix, it's have same size.
For example, first matrix :
1
1
0
0
1
0
Second matrix
34
56
12
12
33
14
Then, I want to compare this two matrix and groups it by the criteria on first matrix
so I will have this two groups matrix :
Matrix when the first matrix is have value 1
34
56
33
and
Matrix when the first matrix is have value 0
12
12
14
You could try this:
a = [1 1 0 0 1 0]';
b = [34 56 12 12 33 14]';
b(a==1)
b(a==0)