What I want to do is to sort these coordinates points:
Measured coordinates (x,y)= (2,2),(2,3),(1,2),(1,3),(2,1),(1,1),(3,2),(3,3),(3 ,1)
I need to get sequences or trajectories of this points to follow them by iteration.
data = [2,2 ; 2,3 ; 1,2 ; 1,3 ; 2,1 ; 1,1 ; 3,2 ; 3,3 ; 3 ,1]
% corresponding sort-value, pick one out or make one up yourself:
sortval = data(:,1); % the x-value
sortval = data(:,2); % y-value
sortval = (data(:,1)-x0).^2 + (data(:,2)-y0).^2; % distance form point (xo,y0)
sortval = ...
[~,sortorder] = sort(sortval);
sorted_data = data(sortorder,:);
But from you comment, I understand you actually need something to reconstruct a path and iteratively find the closest neighbour of the last found point (of the reconstructed path so far).
The following is how I would solve this problem (using pdist2 for calculating the distances between all the points for easiness):
data = [2,2 ; 2,3 ; 1,2 ; 1,3 ; 2,1 ; 1,1 ; 3,2 ; 3,3 ; 3 ,1];
dist = pdist2(data,data);
N = size(data,1);
result = NaN(1,N);
result(1) = 1; % first point is first row in data matrix
for ii=2:N
dist(:,result(ii-1)) = Inf;
[~, closest_idx] = min(dist(result(ii-1),:));
result(ii) = closest_idx;
end
which results in:
result =
1 2 4 3 6 5 9 7 8
being the indices to consecutive points on the curve. Here's a plot of this result:
As #mathematician1975 already mentioned, there can be equal distances to a point. This is solved here by using min which just finds the first occurrence of the minimum in an array. This means that if you order your input data differently, you can get different results of course, this is inherent to the equal-distance issue.
2nd remark: I don't know how this will behave when using large input data matrices, probably a bit slow because of the loop, which you can't avoid. I still see room for improvement, but that's up to you ;)
Create a matrix from your points so that you have something like
A = [2 2 1 1 2 1 3 3 3;
2 3 2 3 1 1 2 3 1]';
then try
B = sortrows(A,1);
to get a matrix with rows that are your points ordered by xvalue or
B = sortrows(A,2)
to get a matrix with rows that are your points ordered by their 'y' value. If your points are ordered with respect to some other ordering parameter (such as time) then sorting will not work unless you remember the order that they were created in.
Related
I have a file that contain the data logged of 6 experiments with this information logged "time ax ay az gx gy gz"
I will call it logmpu6050 in my specific case a 26,220X7 matrix.
I can recognize every experiment because time restart from a lower random value from the previous.
So when this condition is satisfied ti>ti+1 the data of the following experiment starts from the i+1 row.
I defined a "boundary vector" "ind" that contains all this value, and i added the first (1,1) and the last value(end,1) of the first column of the logmpu6050 matrix because are two exeption that don't satisfy the condition.
But when i want to know for example, this information:
query1=logmpu6050(ind(1),:)
Matlab gave me the values of the second row of ind, not the first, as you can see in the pic attached. Why?
I also tought it could start counting from 0, but is false, Matlab dispalys an error message with the 0 value.
Thanks, always, for your time, my civil engineer background makes hard to solve this kind of problems.
Here the code i wrote.
%Open the file
filename= uigetfile ('.txt');
fileID = fopen (filename);
logmpu6050 =csvread(filename);
fclose (fileID);
n=length(logmpu6050);
%Count every time i>i+1 and store the entire raw value
ind=find(diff(logmpu6050(:,1))<0);
ind=[logmpu6050(1,1);ind(:,:);logmpu6050(end,1)];
%No errors appear - logmpu6050 is a 26220X7 double - ind is a 7x1
ind
query1=logmpu6050(ind(1),:)
query2=logmpu6050(ind(2),:)
An alternative method could split the matrix into a cell array of submatrices:
% Generate an example
N = 3; % Num of experiments
n = randi([2,5],N,1); % Points per experiment
logmpu6050 = cell2mat(arrayfun(#(x) [(1:n(x))' x*ones(n(x),6)],1:N,'UniformOutput',0)');
% Find cut points
cuts = [diff(logmpu6050(:,1))<0;1];
% Split into a cell array
experiments = mat2cell(logmpu6050,diff([0;find(cuts)]));
Then you can access the submatrices like:
% The first experiment
experiments{1}
% The second experiment
experiments{2}
I think a lookup function would work nicely to pull out the submatrices you want.
Here's an example
% Generate an example data matrix
n = 3; % Points per experiment
N = 3; % Num of experiments
logmpu6050 = [repmat((1:n),1,N); repmat((1:n*N),6,1)]';
% Make a lookup function
lookup = #(x) cumsum([1;diff(logmpu6050(:,1))<0])==x;
% Get experiment 1 data
logmpu6050(lookup(1),:)
% Get experiment 2 data
logmpu6050(lookup(2),:)
This will output for the first experiment:
ans =
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
and for the second:
ans =
1 4 4 4 4 4 4
2 5 5 5 5 5 5
3 6 6 6 6 6 6
I have a cluster of points in 3D point clouds, says
A = [ 1 4 3;
1 2 3;
1 6 3;
1 5 3];
The distance matrix then was found:
D= pdist(A);
Z= squareform(D);
Z =
0 2 2 1
2 0 4 3
2 4 0 1
1 3 1 0
I would like to sort the points so that the sum of the distance travelled through the points will be the smallest, and output in another matrix. This is similar to TSP problem but in a 3D model. Is there any function can do this?
Your help is really appreciated in advance.
This could be one approach and must be efficient enough for a wide range of datasizes -
D = pdist(A);
Z = squareform(D); %// Get distance matrix
N = size(A,1); %// Store the size of the input array for later usage
Z(1:N+1:end) = Inf; %// Set diagonals as Infinites as we intend to find
%// minimum along each row
%// Starting point and initialize an array to store the indices according
%// to the sorted requirements set in the question
idx = 1;
out_idx = zeros(N,1);
out_idx(1) = idx;
%// Perform an iterative search to look for nearest one starting from point-1
for k = 2:N
start_ind = idx;
[~,idx] = min(Z(start_ind,:));
Z(:,start_ind) = Inf;
out_idx(k) = idx;
end
%// Now that you have the list of indices based on the next closest one,
%// sort the input array based on those indices and have the desired output
out = A(out_idx,:)
Sample run for given input -
A =
1 4 3
1 2 3
1 6 3
1 5 3
1 2 3
out =
1 4 3
1 5 3
1 6 3
1 2 3
1 2 3
The only way I can see you do this is by brute force. Also bear in mind that because this is brute force, this will scale very badly as the total number of points increases. This is fine for just 4 points, but if you want to scale this up, the total number of permutations for N points would be N! so be mindful of this before using this approach. If the number of points increases, then you may get to a point where you run out of memory. For example, for 10 points, 10! = 3628800, so this probably won't bode well with memory if you try and go beyond 10 points.
What I can suggest is to generate all possible permutations of visiting the 4 points, then for each pair of points (pt. 1 -> pt. 2, pt. 2 -> pt. 3, pt. 3 -> pt. 4), determine and accumulate the distances, then find the minimum distance accumulated. Whichever distance is the minimum will give you the sequence of nodes you need to visit.
Start with perms to generate all possible ways to visit four points exactly once, then for each pair of points, figure out the distances between the pairs and accumulate the distances. Keep considering pairs of points along each unique permutation until we reach the end. Once we're done, find the smallest distance that was generated, and return the sequence of points to generate this sequence.
Something like:
%// Your code
A = [ 1 4 3;
1 2 3;
1 6 3;
1 5 3];
D = pdist(A);
Z = squareform(D);
%// Generate all possible permutations to visit for our points
V = perms(1:size(A,1));
%// Used to accumulate our distances per point pair
dists = zeros(size(V,1), 1);
%// For each point pair
for idx = 1 : size(V,2)-1
%// Get the point pair in the sequence
p1 = V(:,idx);
p2 = V(:,idx+1);
%// Figure out the distance between the two points and add them up
dists = dists + Z(sub2ind(size(Z), p1, p2));
end
%// Find which sequence gave the minimum distance travelled
[~,min_idx] = min(dists);
%// Find the sequence of points to generate the minimum
seq = V(min_idx,:);
%// Give the actual points themselves
out = A(seq,:);
seq and out give the actual sequence of points we need to visit, followed by the actual points themselves. Note that we find one such possible combination. There may be a chance that there is more than one possible way to get the minimum distance travelled. This code just returns one possible combination. As such, what I get with the above is:
>> seq
seq =
3 4 1 2
>> out
out =
1 6 3
1 5 3
1 4 3
1 2 3
What the above is saying is that we need to start at point 3, then move to point 4, point 1, then end at point 2. Also, the sequence of pairs of points we need to visit is points 3 and 4, then points 4 and 1 and finally points 1 and 2. The distances are:
Pt. 3 - Pt. 4 - 1
Pt. 4 - Pt. 1 - 1
Pt. 1 - Pt. 2 - 2
Total distance = 4
If you take a look at this particular problem, the minimum possible distance would be 4 but there is certainly more than one way to get the distance 4. This code just gives you one such possible traversal.
I have a matrix with constant consecutive values randomly distributed throughout the matrix. I want the indices of the consecutive values, and further, I want a matrix of the same size as the original matrix, where the number of consecutive values are stored in the indices of the consecutive values. For Example
original_matrix = [1 1 1;2 2 3; 1 2 3];
output_matrix = [3 3 3;2 2 0;0 0 0];
I have struggled mightily to find a solution to this problem. It has relevance for meteorological data quality control. For example, if I have a matrix of temperature data from a number of sensors, and I want to know what days had constant consecutive values, and how many days were constant, so I can then flag the data as possibly faulty.
temperature matrix is number of days x number of stations and I want an output matrix that is also number of days x number of stations, where the consecutive values are flagged as described above.
If you have a solution to that, please provide! Thank you.
For this kind of problems, I made my own utility function runlength:
function RL = runlength(M)
% calculates length of runs of consecutive equal items along columns of M
% work along columns, so that you can use linear indexing
% find locations where items change along column
jumps = diff(M) ~= 0;
% add implicit jumps at start and end
ncol = size(jumps, 2);
jumps = [true(1, ncol); jumps; true(1, ncol)];
% find linear indices of starts and stops of runs
ijump = find(jumps);
nrow = size(jumps, 1);
istart = ijump(rem(ijump, nrow) ~= 0); % remove fake starts in last row
istop = ijump(rem(ijump, nrow) ~= 1); % remove fake stops in first row
rl = istop - istart;
assert(sum(rl) == numel(M))
% make matrix of 'derivative' of runlength
% don't need last row, but needs same size as jumps for indices to be valid
dRL = zeros(size(jumps));
dRL(istart) = rl;
dRL(istop) = dRL(istop) - rl;
% remove last row and 'integrate' to get runlength
RL = cumsum(dRL(1:end-1,:));
It only works along columns since it uses linear indexing. Since you want do something similar along rows, you need to transpose back and forth, so you could use it for your case like so:
>> original = [1 1 1;2 2 3; 1 2 3];
>> original = original.'; % transpose, since runlength works along columns
>> output = runlength(original);
>> output = output.'; % transpose back
>> output(output == 1) = 0; % see hitzg's comment
>> output
output =
3 3 3
2 2 0
0 0 0
I have a <206x193> matrix A. It contains the values of a parameter at 206 different locations at 193 time steps. I am interested in the maximum value at each location over all times as well as the corresponding indices. I have another matrix B with the same dimensions of A and I'm interested in values for each location at the time that A's value at that location was maximal.
I've tried [max_val pos] = max(A,[],2), which gives the right maximum values, but A(pos) does not equal max_val.
How exactly does this function work?
I tried a smaller example as well. Still I don't understand the meaning of the indices....
>> H
H(:,:,1) =
1 2
3 4
H(:,:,2) =
5 6
7 8
>> [val pos] = max(H,[],2)
val(:,:,1) =
2
4
val(:,:,2) =
6
8
pos(:,:,1) =
2
2
pos(:,:,2) =
2
2
The indices in idx represent the index of the max value in the corresponding row. You can use sub2ind to create a linear index if you want to test if A(pos)=max_val
A=rand(206, 193);
[max_val, idx]=max(A, [], 2);
A_max=A(sub2ind(size(A), (1:size(A,1))', idx));
Similarly, you can access the values of B with:
B_Amax=B(sub2ind(size(A), (1:size(A,1))', idx));
From your example:
H(:,:,2) =
5 6
7 8
[val pos] = max(H,[],2)
val(:,:,2) =
6
8
pos(:,:,2) =
2
2
The reason why pos(:,:,2) is [2; 2] is because the maximum is at position 2 for both rows.
max is a primarily intended for use with vectors. In normal mode, even the multi-dimensional arrays are treated as a series of vectors along which the max function is applied.
So, to get the values in B at each location at the time where A is maximum, you should
// find the maximum values and positions in A
[c,i] = max(A, [], 2);
// iterate along the first dimension, to retrieve the corresponding values in B
C = [];
for k=1:size(A,1)
C(k) = B(k,i(k));
end
You can refer to #Jigg's answer for a more concise way of creating matrix C
How in matlab I can interactively append matrix with rows?
For example lets say I have empty matrix:
m = [];
and when I run the for loop, I get rows that I need to insert into matrix.
For example:
for i=1:5
row = v - x; % for example getting 1 2 3
% m.append(row)?
end
so after inserting it should look something like:
m = [
1 2 3
3 2 1
1 2 3
4 3 2
1 1 1
]
In most programming languages you can simply append rows into array/matrix. But I find it hard to do it in matlab.
m = [m ; new_row]; in your loop. If you know the total row number already, define m=zeros(row_num,column_num);, then in your loop m(i,:) = new_row;
Just use
m = [m; row];
Take into account that extending a matrix is slow, as it involves memory reallocation. It's better to preallocate the matrix to its full size,
m = NaN(numRows,numCols);
and then fill the row values at each iteration:
m(ii,:) = row;
Also, it's better not to use i as a variable name, because by default it represents the imaginary unit (that's why I'm using ii here as iteration index).
To create and add a value into the matrix you can do this and can make a complete matrix like yours.
Here row = 5 and then column = 3 and for hence two for loop.
Put the value in M(i, j) location and it will insert the value in the matrix
for i=1:5
for j=1:3
M(i, j) = input('Enter a value = ')
end
fprintf('Row %d inserted successfully\n', i)
end
disp('Full Matrix is = ')
disp(M)
Provably if you enter the same values given, the output will be like yours,
Full Matrix is =
1 2 3
3 2 1
1 2 3
4 3 2
1 1 1