Sequential connecting points in 2D in Matlab - matlab

I was wondering if you could advise me how I can connect several points together exactly one after each other.
Assume:
data =
x y
------------------
591.2990 532.5188
597.8405 558.6672
600.0210 542.3244
606.5624 566.2938
612.0136 546.6825
616.3746 570.6519
617.4648 580.4575
619.6453 600.0688
629.4575 557.5777
630.5477 584.8156
630.5477 618.5906
639.2696 604.4269
643.6306 638.2019
646.9013 620.7697
652.3525 601.1584
"data" is coordinate of points.
Now, I would like to connect(plot) first point(1st array) to second point, second point to third point and so on.
Please mind that plot(data(:,1),data(:,2)) will give me the same result. However, I am looking for a loop which connect (plot) each pair of point per each loop.
For example:
data1=data;
figure
scatter(X,Y,'.')
hold on
for i=1:size(data,1)
[Liaa,Locbb] = ismember(data(i,:),data1,'rows');
data1(Locbb,:)=[];
[n,d] = knnsearch(data1,data(i,:),'k',1);
x=[data(i,1) data1(n,1)];
y=[data(i,2) data1(n,2)];
plot(x,y);
end
hold off
Although, the proposed loop looks fine, I want a kind of plot which each point connect to maximum 2 other points (as I said like plot(x,y))
Any help would be greatly appreciated!

Thanks for all of your helps, finally a solution is found:
n=1;
pt1=[data(n,1), data(n,2)];
figure
scatter(data(:,1),data(:,2))
hold on
for i=1:size(data,1)
if isempty(pt1)~=1
[Liaa,Locbb] = ismember(pt1(:)',data,'rows');
if Locbb~=0
data(Locbb,:)=[];
[n,d] = knnsearch(data,pt1(:)','k',1);
x=[pt1(1,1) data(n,1)];
y=[pt1(1,2) data(n,2)];
pt1=[data(n,1), data(n,2)];
plot(x,y);
end
end
end
hold off
BTW it is possible to delete the last longest line as it is not related to the question, if someone need it please let me know.

You don't need to use a loop at all. You can use interp1. Specify your x and y data points as control points. After, you can specify a finer set of points from the first x value to the last x value. You can specify a linear spline as this is what you want to accomplish if the behaviour you want is the same as plot. Assuming that data is a 2D matrix as you have shown above, without further ado:
%// Get the minimum and maximum x-values
xMin = min(data(:,1));
xMax = max(data(:,1));
N = 3000; % // Specify total number of points
%// Create an array of N points that linearly span from xMin to xMax
%// Make N larger for finer resolution
xPoints = linspace(xMin, xMax, N);
%//Use the data matrix as control points, then xPoints are the values
%//along the x-axis that will help us draw our lines. yPoints will be
%//the output on the y-axis
yPoints = interp1(data(:,1), data(:,2), xPoints, 'linear');
%// Plot the control points as well as the interpolated points
plot(data(:,1), data(:,2), 'rx', 'MarkerSize', 12);
hold on;
plot(xPoints, yPoints, 'b.');
Warning: You have two x values that map to 630.5477 but produce different y values. If you use interp1, this will give you an error, which is why I had to slightly perturb one of the values by a small amount to get this to work. This should hopefully not be the case when you start using your own data. This is the plot I get:
You'll see that there is a huge gap between those two points I talked about. This is the only limitation to interp1 as it assumes that the x values are strictly monotonically increasing. As such, you can't have the same two points in your set of x values.

Related

Highlight specific section of graph in MATLAB

I wish to highlight/mark some parts of a array via plot in MATLAB. After some research (like here) I tried to hold the first plot, find the indexes for highlighting and then a new plot, only with those points. However, those points are being drawn but all shifted to the beginning of the axis:
I'm currently trying using this code:
load consumer; % the main array to plot (157628x10 double) - data on column 9
load errors; % a array containing the error indexes (1x5590 double)
x = 1:size(consumer,1)'; % returns a (157628x1 double)
idx = (ismember(x,errors)); % returns a (157628x1 logical)
fig = plot(consumer(:,9));
hold on, plot(consumer(idx,9),'r.');
hold off
Another thing I would like to do was highlighting the whole section of the graph, like a "patch" on the same sections. Any ideas?
The trouble is that you are only providing the y-axis data to the plot function. By default, this means all data is plotted on the 1:numel(y) x locations of your plot, where y is your y-axis data.
You have 2 options...
Also provide x-axis data. You've already got the array x anyway!
figure; hold on;
plot(x, consumer(:,9));
plot(x(idx), consumer(idx,9), 'r.');
Aside: I'm slightly confused why you create idx. If errors is as you describe it (indexes of the array) then you should just be able to use consumer(errors,9).
Make all data which you don't want to appear equal to NaN. Because of the way you're loading your error indices in, this is less quick and easy. Basically you'd copy consumer(:,9) into a new variable, and index all undesirable points to set them equal to NaN.
This method has the benefit of breaking up discontinuous sections too.
y = consumer(:,9); % copy your y data before changes
idx = ~ismember(x, errors); % get the indices you *don't* want to re-plot
y(idx) = NaN; % Set equal to NaN so they aren't plotted
figure; hold on;
plot(x, consumer(:,9));
plot(x, y, 'r'); % Plot all points, NaNs wont show

Only plot lines of specific length

Below is an image showing a contour plot with areas of interest that have have been connected up by using their centroids. What I want to achieve is that only lines of a certain length are plotted. Currently, every point has a line drawn to every other point.
C=contourf(K{i});
[Area,Centroid] = Contour2Area(C);
% This converts any entries that are negative into a positive value
% of the same magnitiude
indices{i} = find( Centroid < 0);
Centroid(indices{i})=Centroid(indices{i}) * -1; %set all
% Does the same but for positive (+500)
indices{i} = find( Area > 500);
Area(indices{i})=0;
[sortedAreaVal, sortedAreaInd] = sort(Area, 'descend');
maxAreaVals = sortedAreaVal(1:10)';
maxAreaInd = sortedAreaInd(1:10)';
xc=Centroid(1,:); yc=Centroid(2,:);
hold on; plot(xc,yc,'-');
It would be very useful if there was a way of only plotting the lines that fall below a specific threshold. The next step will be to label and measure each line. Thanks in advance for your time.
If xc and yc are the x and y coordinates of the centroids, then you could do something like this:
sqrt(sum(diff([x,y],1).^2,2))
What this does is take the difference between successive [x,y] data points, then calculate the Euclidean distance between them. You then have all the information you need to select the ones you want and label the lengths.
One thing though, this will only compute distances between successive centroids. I wrote it this way because it appears that's what you're trying to do above. If you are interested in finding out the distances between all centroids, you would have to loop through and compute the distances.
Something along the lines of:
for i=1:length(xc)-1
for j=i+1:length(xc)
% distance calculation here...
Hope this helps.

Plot a cell into a time-changing curve

I have got a cell, which is like this : Data={[2,3],[5,6],[1,4],[6,7]...}
The number in every square brackets represent x and y of a point respectively. There will be a new coordinate into the cell in every loop of my algorithm.
I want to plot these points into a time-changing curve, which will tell me the trajectory of the point.
As a beginner of MATLAB, I have no idea of this stage. Thanks for your help.
Here is some sample code to get you started. It uses some basic Matlab functionalities that you will hopefully find useful as you continue using it. I added come data points to you cell array for illustrative purposes.
The syntax to access elements into the cell array might seem weird but is important. Look here for details about cell array indexing.
In order to give nice colors to the points, I generated an array based on the jet colormap built-in in Matlab. Basically issuing the command
Colors = jet(N)
create a N x 3 matrix in which every row is a 3-element color ranging from blue to red. That way you can see which points were detected before other (i.e. blue before red). Of course you can change that to anything you want (look here if you're interested).
So here is the code. If something is unclear please ask for clarifications.
clear
clc
%// Get data
Data = {[2,3],[5,6],[1,4],[6,7],[8,1],[5,2],[7,7]};
%// Set up a matrix to color the points. Here I used a jet colormap
%// available from MATLAB but that could be anything.
Colors = jet(numel(Data));
figure;
%// Use "hold all" to prevent the content of the figure to be overwritten
%// at every iterations.
hold all
for k = 1:numel(Data)
%// Note the syntax used to access the content of the cell array.
scatter(Data{k}(1),Data{k}(2),60,Colors(k,:),'filled');
%// Trace a line to link consecutive points
if k > 1
line([Data{k-1}(1) Data{k}(1)],[Data{k-1}(2) Data{k}(2)],'LineStyle','--','Color','k');
end
end
%// Set up axis limits
axis([0 10 0 11])
%// Add labels to axis and add a title.
xlabel('X coordinates','FontSize',16)
ylabel('Y coordinates','FontSize',16)
title('This is a very boring title','FontSize',18)
Which outputs the following:
This would be easier to achieve if all of your data was stored in a n by 2 (or 2 by n) matrix. In this case, each row would be a new entry. For example:
Data=[2,3;
5,6;
1,4;
6,7];
plot(Data(:, 1), Data(:, 2))
Would plot your points. Fortunately, Matlab is able to handle matrices which grow on every iteration, though it is not recommended.
If you really wanted to work with cells, there are a couple of ways you could do it. Firstly, you could assign the elements to a matrix and repeat the above method:
NumPoints = numel(Data);
DataMat = zeros(NumPoints, 2);
for I = 1:NumPoints % Data is a cell here
DataMat(I, :) = cell2mat(Data(I));
end
You could alternatively plot the elements straight from the cell, though this would limit your plot options.
NumPoints = numel(Data);
hold on
for I = 1:NumPoints
point = cell2mat(Data(I));
plot(point(1), point(2))
end
hold off
With regards to your time changing curve, if you find that Matlab starts to slow down after it stores lots of points, it is possible to limit your viewing window in time with clever indexing. For example:
index = 1;
SamplingRate = 10; % How many times per second are we taking a sample (Hertz)?
WindowTime = 10; % How far into the past do we want to store points (seconds)?
NumPoints = SamplingRate * WindowTime
Data = zeros(NumPoints, 2);
while running
% Your code goes here
Data(index, :) = NewData;
index = index + 1;
index = mod(index-1, NumPoints)+1;
plot(Data(:, 1), Data(:, 2))
drawnow
end
Will store your data in a Matrix of fixed size, meaning Matlab won't slow down.

Plotting rows of points in Matlab

So I'm still getting used to Matlab and am having a bit of trouble with plotting. I have a cell which contains a list of points in each row. I want to plot each row of points in a different colour on the same graph so I can compare them. The catch is that I need to make this work for an unknown number of points and rows (ie the number of points and rows can change each time I run the program).
So for example, I might have my cell array A:
A = {[0,0], [1,2], [3,4]; [0,0] [5,6], [9,2]}
and I want to plot the points in row 1 against their index (so a 3D graph) and then have the points in row 2 on the same graph in a different colour. The rows will always be the same length. (Each row will always have the same number of points). I've tried a few different for loops but just can't seem to get this right.
Any help in sending me in the right direction would be greatly appreciated!
The fact that the number of points and rows can change with each iteration should not pose much of a problem. I would suggest using the size function before your plot loops (size(A,1) and size(A,2)) to get the dimensions of the matrix.
Once you have the size of the matrix, loop through the dimensions and plot the lines on the same plot using holdon, and then finally just make the line color a function of the dimensions as you loop through so that you always have a different line color
You could just convert it to a matrix and plot it directly:
% Some dummy data - format a little different from your example
% to allow for different numbers of elements per row
A = {[0,0, 1,2, 3,4]; [0,0, 5,6]};
% Figure out how many columns we need in total
maxLen = max(cellfun(#length, A));
% Preallocate
Amat = NaN(size(A, 1), maxLen);
% Copy data
for n = 1:size(A, 1)
curA = A{n};
Amat(n, 1:length(curA)) = curA;
end
% Generate 1:N vector repeated the correct number of times (rows)
x = repmat(1:size(Amat, 2), size(Amat, 1), 1);
plot(x, Amat)
Edit: You mentioned a 3D graph at some point in your post. The above won't plot a 3D graph, so here's something that will:
% Generate Amat as above
% Then:
[X, Y] = meshgrid(1:size(Amat, 1), 1:size(Amat, 2));
surf(X, Y, Amat.'); % OR: plot3(X, Y, Amat.');
I'm not sure this is exactly what you want, but your question is slightly unclear on exactly what kind of graph you want out of this. If you just want coloured lines on your plot, you can use plot3 instead of surf, but IMHO surf will probably give you a clearer plot for this kind of data.

Two time series plots and shading between them...MATLAB

I am using MATLAB to plot two lines of a time series... (a min and max line)
I have the points converging at a single point at the end of the data.
I am trying to fill the area in between the lines and then plot other lines on top of the shaded area.
Here is my problem:
When I use "fill" it does exactly what I want it to do...but it draws a line from the last point of the data back to the initial data point. How do I get rid of it?
Here is a very vague sketch of my 2 examples:
The line below the graph is what I am talking about...
Any ideas how to avoid that?
Thanks!
I guess that you create the fill with
fill([xData1;xData2],[yData1;yData2])
where xData1 is a n-by-1 array of x-data for your first curve. This will lead to a weirdly-shaped polygon because the 'corners' of the polygon are not properly ordered.
Instead, you should do
fill([xData1;xData2(end:-1:1)],[yData1;yData2(end:-1:1])
i.e. flip the order of one of the two data sets.
As #Jonas explained (beat me to it), you need to properly order the data of the two time-series. Let me add an example to that:
%# first series
x1 = linspace(pi/4, 5*pi/4, 100);
y1 = cos(x1);
%# second series
x2 = linspace(pi/4, 5*pi/4, 100);
y2 = sin(x2);
subplot(121), fill([x1 x2], [y1 y2], 'r')
subplot(122), fill([x1 fliplr(x2)], [y1 fliplr(y2)], 'r')
hold on
plot(x1,y1, 'Color','b', 'LineWidth',3)
plot(x2,y2, 'Color','g', 'LineWidth',3)