Organize Points and Draw the Line - matlab

In Matlab, I've got several points in the 3D space. Those points represent a rope and I would like to draw a line linking all those points. Here is my problem: How the oraganization of those points should be done to have a "simple" and "more or less straigth line". In other words I would like to draw a line linking all the points from the first to the last one but not "going back". Maybe with a simple image i can explain better my problem:
This is what the code should do:
This is what the code shouldn't do:
Some idea of how can I achieve the intended result? How can I organize the points? I'm working with Matlab but if you know any paper where I can read how to do this it will be fine. Thank you.

If you just don't want to go back in the upper direction, the solution that #Dan suggested should be fine. Sort them in that direction before connecting.
However, if that is not a requirement but you are actually looking for a solution without ugly crossings that is as short as possible, you may want to look into solutions for the travelling salesman problem.
If you define the distance between 1 and 9 to be zero, the solution you find to the travelling salesman problem should give you a nice and short rope.
If you want to go for the TSP approach but get a little lost, just try a 'furthest insertion' start position or '2 opt' improvements as that is likely going to give a big improvement over random path selection already with minimal effort.

OK. I've found the right answer (by Gunther Struyf): Sort Coordinates Points in Matlab
In order to visualize the final result just add to Gunther's code the following lines:
row=data(:,1);
col=data(:,2);
figure
scatter(row,col,'r');
hold on
line(row(result),col(result));
The following code shows the same algorithm but for a 3D implementation:
close all;
data = [2,2, 2; 2,3,2 ; 1,2,3 ; 1,3,3 ; 2,1,3 ; 1,1,3 ; 3,2,4 ; 3,3,4 ; 3,1,5; 5,4,6; 7,3,8; 8,9,7; 9,4,7; 6,2,5; 5,8,6; 9,3,8;6,9,2];
row=data(:,1);
col=data(:,2);
frame=data(:,3);
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
figure
%Ploting the points directly (without sorting)
subplot(2,1,1);
scatter3(row,col,frame,'r');
hold on;
line(row,col,frame);
%Ploting after sorting
subplot(2,1,2);
scatter3(row,col,frame,'r');
hold on
line(row(result),col(result),frame(result));

Related

How do I get lines to stop extending beyond plot border? (Matlab)

I am writing a report for a class and am having some issues with the lines of an unstable plot going beyond the boundary of the graph and overlapping the title and xlabel. This is despite specifying a ylim from -2 to 2. Is there a good way to solve this issue?
Thanks!
plot(X,u(:,v0),X,u(:,v1),X,u(:,v2),X,u(:,v3),X,u(:,v4))
titlestr = sprintf('Velocity vs. Distance of %s function using %s: C=%g, imax=%g, dx=%gm, dt=%gsec',ICFType,SDType,C,imax,dx,dt);
ttl=title(titlestr);
ylabl=ylabel("u (m/s)");
xlabl=xlabel("x (m)");
ylim([-2 2])
lgnd=legend('t=0','t=1','t=2','t=3','t=4');
ttl.FontSize=18;
ylabl.FontSize=18;
xlabl.FontSize=18;
lgnd.FontSize=18;
EDIT: Minimum reproducible example
mgc=randi([-900*10^10,900*10^10], [1000,2]);
mgc=mgc*1000000;
plot(mgc(:,1),mgc(:,2))
ylim([-1,1])
This is odd. It really looks like a Bug... partly
The reason is probably that the angle of the lines are so narrow that MATLAB runs into rounding errors when calculating the points to draw for your limits very small limits given very large numbers. (You see that you don't run into this problem when you don't scale the matrix mgc.
mgc = randi([-900*10^10,900*10^10], [1000,2]);
plot(mgc(:,1),mgc(:,2))
ylim([-1,1])
but if you scale it further, you run into this problem...
mgc = randi([-900*10^10,900*10^10], [1000,2]);
plot(mgc(:,1)*1e6,mgc(:,2)*1e6)
ylim([-1,1])
While those numbers are nowhere near the maximum number a double can represent (type realmax in the command window to see that this is a number with 308 zeros!); limiting the plot to [-1,1] on one of the axes -- note that you obtain the same phenom on the x-axis -- let MATLAB run into precision problems.
First of all, you see that it plots much less lines than before (in my case)... although, I just said to zoom on the y-axis. The thing is, that MATLAB does not recalculate the lines for the section but it really zooms into it (I guess that this may cause resolution errors with regard to pixels?)
Well, lets have a look at the data (Pro-tip, you can get the data of a line from a MATLAB figure by calling this snippet
datObj = findobj(gcf,'-property','YData','-property','XData');
X = datObj.XData;
Y = datObj.YData;
xlm = get(gca,'XLim'); % get the current x-limits
) We see that it represents the original data set, which is not surprising as you can also zoom out again.
Note that his only occurs if you have such a chaotic, jagged line. If you sort it, it does not happen.
quick fix:
Now, what happens, if we calculate the exact points for this section?
m = diff(Y)./diff(X); % slope
n = Y(1:end-1)-m.*X(1:end-1); % offset
x = [(-1-n); (1-n)]./m;
y = ones(size(x))./[-1 1].';
% plot
plot([xMinus1;xPlus1],(ones(length(xMinus1),2).*[-1 1]).')
xlim(xlm); % limit to exact same scale as before
The different colors indicate that they are now individual lines and not a single wild chaos;)
It seems Max pretty much hit the nail on the head as it pertains to the reason for this error is occurring. Per Enrico's advice I went ahead and submitted a bug report. MathWorks responded saying they were unsure it was "unexpected behavior" and would look into it more shortly. They also did suggest a temporary workaround (which, in my case, may be permanent).
This workaround is to put
set(gca,'ClippingStyle','rectangle');
directly after the plotting line.
Below is a modified version of the minimum reproducible example with this modification.
mgc=randi([-900*10^10,900*10^10], [1000,2]);
mgc=mgc*1000000;
plot(mgc(:,1),mgc(:,2))
set(gca,'ClippingStyle','rectangle');
ylim([-1,1])

Failed to plot simple graph in Octave

I want to draw a line on a graph to find the intersection point with another line. However, there's no response after I executed the script below. May I know what is the problem and how can I solve it?
x=1:2^20;
y2=2^24;
plot(x,y2);
Thanks!
What you want is to plot a line on 2^24. However, there are too many points for you computer probably, and you run out of memory
I am guessing that you'll need to plot your other inequality as well.
Something like
x=1:100:2^20;
% As Zoran and others suggested, You may not want all the points!
% It is too much memory
y2=2^24*ones(size(x)); % This ones is optional, but its good to know what you are doing (personal opinion)
plot(x,y2);
hold on
y1=(x+1).*log(x);
plot(x,y1);
However, you are still not there!
Another solution, which does not rely on plotting:
>> f = #(x) (x+1)*log(x)-2^24;
>> soln = fzero(f,1e6)
soln = 1.1987e+006
>> f(soln)
ans = 3.7253e-009
So your intersection point is at 1.1987e6.
Apparently,you have too many points for x, 2^20
Have to wait program to calculate, or plot,for example, every 100th point
This solution works for Matlab
x=1:100:2^20;
y2=2^2;
plot(x,y2,'o');
There is one more and maybe a bit smarter way: if you want to solve ((k+1)(ln k)<2^24) as you've commented above, use fsolve function to get just solution of an equation(!). Then use that solution to specify the area of your interest, so you won't have to plot the domain of 2^20.
(All functions are continuous so you don't have to worry about any wild singularities. Just examine the neigborhood of ks for which (k+1)(ln k)-2^24=0.)

GUI solving equations project

I have a Matlab project in which I need to make a GUI that receives two mathematical functions from the user. I then need to find their intersection point, and then plot the two functions.
So, I have several questions:
Do you know of any algorithm I can use to find the intersection point? Of course I prefer one to which I can already find a Matlab code for in the internet. Also, I prefer it wouldn't be the Newton-Raphson method.
I should point out I'm not allowed to use built in Matlab functions.
I'm having trouble plotting the functions. What I basically did is this:
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
cla % To clear axes when plotting new functions
ezplot(fun_f);
hold on
ezplot(fun_g);
axis ([-20 20 -10 10]);
The problem is that sometimes, the axes limits do not allow me to see the other function. This will happen, if, for example, I will have one function as log10(x) and the other as y=1, the y=1 will not be shown.
I have already tried using all the axis commands but to no avail. If I set the limits myself, the functions only exist in certain limits. I have no idea why.
3 . How do I display numbers in a static text? Or better yet, string with numbers?
I want to display something like x0 = [root1]; x1 = [root2]. The only solution I found was turning the roots I found into strings but I prefer not to.
As for the equation solver, this is the code I have so far. I know it is very amateurish but it seemed like the most "intuitive" way. Also keep in mind it is very very not finished (for example, it will show me only two solutions, I'm not so sure how to display multiple roots in one static text as they are strings, hence question #3).
function [Sol] = SolveEquation(handles)
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
f = inline(fun_f);
g = inline(fun_g);
i = 1;
Sol = 0;
for x = -10:0.1:10;
if (g(x) - f(x)) >= 0 && (g(x) - f(x)) < 0.01
Sol(i) = x;
i = i + 1;
end
end
solution1 = num2str(Sol(1));
solution2 = num2str(Sol(2));
set(handles.roots1,'string',solution1);
set(handles.roots2,'string',solution2);
The if condition is because the subtraction will never give me an absolute zero, and this seems to somewhat solve it, though it's really not perfect, sometimes it will give me more than two very similar solutions (e.g 1.9 and 2).
The range of x is arbitrary, chosen by me.
I know this is a long question, so I really appreciate your patience.
Thank you very much in advance!
Question 1
I think this is a more robust method for finding the roots given data at discrete points. Looking for when the difference between the functions changes sign, which corresponds to them crossing over.
S=sign(g(x)-f(x));
h=find(diff(S)~=0)
Sol=x(h);
If you can evaluate the function wherever you want there are more methods you can use, but it depends on the size of the domain and the accuracy you want as to what is best. For example, if you don't need a great deal of accurac, your f and g functions are simple to calculate, and you can't or don't want to use derivatives, you can get a more accurate root using the same idea as the first code snippet, but do it iteratively:
G=inline('sin(x)');
F=inline('1');
g=vectorize(G);
f=vectorize(F);
tol=1e-9;
tic()
x = -2*pi:.001:pi;
S=sign(g(x)-f(x));
h=find(diff(S)~=0); % Find where two lines cross over
Sol=zeros(size(h));
Err=zeros(size(h));
if ~isempty(h) % There are some cross-over points
for i=1:length(h) % For each point, improve the approximation
xN=x(h(i):h(i)+1);
err=1;
while(abs(err)>tol) % Iteratively improve aproximation
S=sign(g(xN)-f(xN));
hF=find(diff(S)~=0);
xN=xN(hF:hF+1);
[~,I]=min(abs(f(xN)-g(xN)));
xG=xN(I);
err=f(xG)-g(xG);
xN=linspace(xN(1),xN(2),15);
end
Sol(i)=xG;
Err(i)=f(xG)-g(xG);
end
else % No crossover points - lines could meet at tangents
[h,I]=findpeaks(-abs(g(x)-f(x)));
Sol=x(I(abs(f(x(I))-g(x(I)))<1e-5));
Err=f(Sol)-g(Sol)
end
% We also have to check each endpoint
if abs(f(x(end))-g(x(end)))<tol && abs(Sol(end)-x(end))>1e-12
Sol=[Sol x(end)];
Err=[Err g(x(end))-f(x(end))];
end
if abs(f(x(1))-g(x(1)))<tol && abs(Sol(1)-x(1))>1e-12
Sol=[x(1) Sol];
Err=[g(x(1))-f(x(1)) Err];
end
toc()
Sol
Err
This will "zoom" in to the region around each suspected root, and iteratively improve the accuracy. You can tweak the parameters to see whether they give better behaviour (the tolerance tol, the 15, number of new points to generate, could be higher probably).
Question 2
You would probably be best off avoiding ezplot, and using plot, which gives you greater control. You can vectorise inline functions so that you can evaluate them like anonymous functions, as I did in the previous code snippet, using
f=inline('x^2')
F=vectorize(f)
F(1:5)
and this should make plotting much easier:
plot(x,f(x),'b',Sol,f(Sol),'ro',x,g(x),'k',Sol,G(Sol),'ro')
Question 3
I'm not sure why you don't want to display your roots as strings, what's wrong with this:
text(xPos,yPos,['x0=' num2str(Sol(1))]);

"Text" function very slow, bottleneck of my code

I am dealing with a structured grid. I just wanna add to the plot a text of the type (m,n) that indicates the indices of each node. And maybe in the future the value of the variable instead. I use the text function. I profiled the code and most of the time is spent in that function. It is only a 101*101 grid, if you increase it the code is basically stuck. I already optimized it avoiding loops for text and spritnf, but it still too slow. Moreover, once the plot is created it is very stuck and it takes a few seconds every time to pan or zoom. See on the follow a minimal example. I also added the patch that I use to display the grid. (I use patch because I want to plot some grid quantities for each cell and I want to keep it general in case I move to an unstructured mesh with irregular polygons. Patch is superfast though, no prob with it). Any suggestion to speed this up? thanks
%define grid and grid numbering
DX = 10 ; %=DY
mmax = 101; %= number of nodes in x
nmax = mmax %= number of nodes in y
[ x y ] = meshgrid(0:DX:DX*(mmax-1),0:DX:DX*(mmax-1)); %grid
[ mMAT nMAT ] = meshgrid(1:mmax,1:nmax); %grid numbering
%
%display patch
%
cont = 0
for m=2:mmax
for n=2:nmax
cont=cont+1;
Xpatch(1:4,cont) = [ x(n-1,m-1) ; x(n-1,m) ; x(n,m) ; x(n,m-1) ] ;% ii+1 since it has the BC
Ypatch(1:4,cont) = [ y(n-1,m-1) ; y(n-1,m) ; y(n,m) ; y(n,m-1) ] ;
Zpatch(cont) = 1;
end
end
hpatch3 = patch(Xpatch(:,:),Ypatch(:,:),Zpatch(:)');
%
% display node indices
%
charINPUT = regexp(sprintf('(%d,%d)\n',mMAT(:),nMAT(:)),'(?<=\s*)(\S*)(?=\n)','match'); % use regexp to vectorize sprintf and so avoid slow loops with sprintf
text(x(:),y(:),charINPUT(:),'Clipping', 'on');
set(gcf,'position',[9 40 1350 650])
set(gcf,'PaperPositionMode','auto')
Guys I found the solutions. 100 times faster if you just set hittest to 'off'!!!!! I did this:
text(x(:), y(:), charINPUT(:), 'Clipping', 'on','hittest', 'off');
and my life changed.
Thanks.
A.
The problem is that text is simply displaying too much. The approach I would suggest is to utilize figure and axes callbacks (or undocumented listeners) to add the text (or annotations) when you reach a certain zoom level, and to maintain which text labels are displayed depending on the zoom and pan. In a nutshell, the callbacks would check the xlim and ylim properties of the axis and add the appropriate text for that range (and delete any old text).
If this seems like a solution you would be happy with, give it a shot. I can give you some hints and/or examples later. Thanks to Werner for the tip about using listeners.
I had a similar problem. I found that reducing the number of calls to text (in my case from ~500 to 1) by providing it with vectors rather than many individual calls, resulted in a significant performance benefit. In my specific case, I went from ~25s to display 1 graph to ~2s.
For me, the hittest off method did not have any performance benefit - though in my case there aren't any zooming/clipping concerns so maybe this explains the difference to other people's experience.

problem im motion control with MATLAB

i have a problem in motion control in matlab
imagine a four bar linkage mechanism like this.as you you know in an ordinary 4 bar linkage we have 2 fix points but here we have just one & the second one it fixed to a pinion (small gear).we have the ratio of gears so we have a relation between teta1 & teta2
teta2 = 5*teta1 (the mechanism can rotate in the first fix point)
i used to write this code for motion control but the when i run it the graphs are not correct (because they should be something linke sin or cos graph)
d(n) is a auxiliry vector for solving equations
please ask if you have further questions
this is the code :
clc,
close all,
clear all,
ax=0;
ay=0;
r1=12;
r2=7;
r3=9;
r4=5;
n=0;
for teta1=0:pi/180:2*pi
n=n+1;
D = r1*exp(i*teta1)-r2*exp(i*5*teta1);
tetad(n) = angle(D);
d(n) = abs(D);
landa(n)=acos((d(n)^2+(r3)^2-(r4)^2)/(2*d(n)*r3));
alfa(n)=acos((d(n)^2+(r4)^2-(r3)^2)/(2*d(n)*r4));
teta3(n)=landa(n)+tetad(n);
teta4(n)=(+pi-alfa(n)+tetad(n));
end
aa(n)=teta1*180/pi;
hh(n)=tetad(n)*180/pi;
bb(n)=landa(n)*180/pi;
cc(n)=alfa(n)*180/pi;
nn(n)=teta3(n)*180/pi;
dd(n)=5*teta1*180/pi;
ee(n)=teta4(n)*180/pi;
figure(1),plot(aa,hh),xlabel('teta1'),ylabel('tetad');
figure(2),plot(aa,d),xlabel('teta1'),ylabel('d');
figure(3),plot(aa,bb),xlabel('teta1'),ylabel('landa');
figure(4),plot(aa,cc),xlabel('teta1'),ylabel('alfa');
figure(5),plot(aa,nn),xlabel('teta1'),ylabel('teta3');
figure(6),plot(aa,dd),xlabel('teta1'),ylabel('5*teta1');
figure(7),plot(aa,ee),xlabel('teta1'),ylabel('teta4');
I have no idea what you are trying to solve here, but probably you want to move the end of your for-loop a few lines down, so the vectors you plot contain all values and not only the last one.