Fit a line to a part of a plot - matlab

I have two array 451x1 , I want to fit a line to a part of my data, for x=3.8 –4.1 , and I want to evaluate interception of fitted line with line y=0, Do you have any idea? (In matlab )
data

You can easily perform a linear regression by indexing the points of the curve you want to use and passing them to the function POLYFIT. Here's the code to do it and a plot of the fit line:
index = (x >= 3.8) & (x <= 4.1); %# Get the index of the line segment
p = polyfit(x(index),y(index),1); %# Fit polynomial coefficients for line
yfit = p(2)+x.*p(1); %# Compute the best-fit line
plot(x,y); %# Plot the data
hold on; %# Add to the plot
plot(x,yfit,'r'); %# Plot the best-fit line
axis([1 7 0 4e10]); %# Adjust the axes limits
Then you can compute where this line intercepts the x-axis (i.e. y = 0) like so:
>> -p(2)/p(1)
ans =
3.5264

I'm just guessing that your question is to estimate a line with a zero y-intercept, although honestly, "want to evaluate interception of fitted line with line y=0" makes little sense in English to me. So this is just a complete guess, unless you choose to clarify your question.
Delete that part of the data that does NOT lie in the interval of interest. (Or if you prefer, extract only that part which does.)
Fit a line with zero y-intercept to the data of interest.
slope = x(:)\y(:);

You would fit x respect to y like:
> ndx= find(x>= 3.8& x<= 4.1);
> b= [y(ndx) ones(size(ndx))]\ x(ndx)
Now b(2) is "the interception with" line y= 0.

Related

curve fitting: a number of curves with different length/number of points into one curve in 3D in Matlab

Say I've got a number of curves with different length (number of points in each curve and points distance are all vary). Could I find a curve in 3D space that fit best for this group of lines?
Code example in Matlab would be appreciated.
example data set:
the 1st curve has 10 points.
18.5860 18.4683 18.3576 18.2491 18.0844 17.9016 17.7709 17.6401 17.4617 17.2726
91.6178 91.5711 91.5580 91.5580 91.5701 91.6130 91.5746 91.5050 91.3993 91.2977
90.6253 91.1090 91.5964 92.0845 92.5565 93.0199 93.5010 93.9785 94.4335 94.8851
the 2nd curve has 8 points.
15.2091 15.0894 14.9765 14.8567 14.7360 14.6144 14.4695 14.3017
90.1138 89.9824 89.8683 89.7716 89.6889 89.6040 89.4928 89.3624
99.4393 99.9066 100.3802 100.8559 101.3340 101.8115 102.2770 102.7296
a desired curve is one that could represent these two exist curves.
I have thinking of make these curves as points scatters and fit a line out of them. But only a straight line can I get from many code snippet online.
So did I missing something or could someone provide some hint. Thanks.
Hard to come up with a bulletproof solution without more details, but here's an approach that works for the sample data provided. I found the line of best fit for all the points, and then parameterized all the points along that line of best fit. Then I did least-squares polynomial fitting for each dimension separately. This produced a three-dimensional parametric curve that seems to fit the data just fine.
Note that curve fitting approaches other than polynomial least-squares might be better suited to some cases---just substitute the preferred fitting function for polyfit and polyval.
Hope this is helpful!
clear;
close all;
pts1=[18.5860 18.4683 18.3576 18.2491 18.0844 17.9016 17.7709 17.6401 17.4617 17.2726;
91.6178 91.5711 91.5580 91.5580 91.5701 91.6130 91.5746 91.5050 91.3993 91.2977;
90.6253 91.1090 91.5964 92.0845 92.5565 93.0199 93.5010 93.9785 94.4335 94.8851]';
pts2=[ 15.2091 15.0894 14.9765 14.8567 14.7360 14.6144 14.4695 14.3017;
90.1138 89.9824 89.8683 89.7716 89.6889 89.6040 89.4928 89.3624;
99.4393 99.9066 100.3802 100.8559 101.3340 101.8115 102.2770 102.7296]';
%Combine all of our curves into a single point cloud
X = [pts1;pts2];
%=======================================================
%We want to first find the line of best fit
%This line will provide a parameterization of the points
%See accepted answer to http://stackoverflow.com/questions/10878167/plot-3d-line-matlab
% calculate centroid
x0 = mean(X)';
% form matrix A of translated points
A = [(X(:, 1) - x0(1)) (X(:, 2) - x0(2)) (X(:, 3) - x0(3))];
% calculate the SVD of A
[~, S, V] = svd(A, 0);
% find the largest singular value in S and extract from V the
% corresponding right singular vector
[s, i] = max(diag(S));
a = V(:, i);
%=======================================================
a=a / norm(a);
%OK now 'a' is a unit vector pointing along the line of best fit.
%Now we need to compute a new variable, 't', for each point in the cloud
%This 't' value will parameterize the curve of best fit.
%Essentially what we're doing here is taking the dot product of each
%shifted point (contained in A) with the normal vector 'a'
t = A * a;
tMin = min(t);
tMax = max(t);
%This variable represents the order of our polynomial fit
%Use the smallest number that produces a satisfactory result
polyOrder = 8;
%Polynomial fit all three dimensions separately against t
pX = polyfit(t,X(:,1),polyOrder);
pY = polyfit(t,X(:,2),polyOrder);
pZ = polyfit(t,X(:,3),polyOrder);
%And that's our curve fit: (pX(t),pY(t),pZ(t))
%Now let's plot it.
tFine = tMin:.01:tMax;
fitXFine = polyval(pX,tFine);
fitYFine = polyval(pY,tFine);
fitZFine = polyval(pZ,tFine);
figure;
scatter3(X(:,1),X(:,2),X(:,3));
hold on;
plot3(fitXFine,fitYFine,fitZFine);
hold off;

Extend a line through 3 points matlab

Im just trying to draw a line through the following points in matlab. Currently the line extends only to the points. I need to to extend and intercept the x axis. The code is below
A = [209.45 198.066 162.759];
B = [1.805 1.637 1.115];
plot(A,B,'*');
axis([0 210 0 2]);
hold on
line(A,B)
hold off
If you want to augment your points with a corresponding y==0 point, I suggest using interp1 to obtain the x-intercept:
A = [209.45 198.066 162.759];
B = [1.805 1.637 1.115];
x0 = interp1(B,A,0,'linear','extrap'); %extrapolate (y,x) at y==0 to get x0
[newA, inds] = sort([x0 A]); %insert x0 where it belongs
newB = [0 B];
newB = newB(inds); %keep the same order with B
plot(A,B,'b*',newA,newB,'b-');
This will use interp1 to perform a linear interpolant, with extrapolation switched on. By interpolating (B,A) pairs, we in effect invert your linear function.
Next we add the (x0,0) point to the data, but since matlab draws lines in the order of the points, we have to sort the vector according to x component. The sorting order is then used to keep the same order in the extended B vector.
Finally the line is plotted. I made use of plot with a linespec of '-' to draw the line in the same command as the points themselves. If it doesn't bother you that the (x0,0) point is also indicated, you can plot both markers and lines together using plot(newA,newB,'*-'); which ensures that the colors match up (in the above code I manually set the same blue colour on both plots).

Matlab extend plot over all axis range

I'm trying to use Matlab for some data plotting. In particular I need to plot a series of lines, some times given two points belonging to it, some times given the orthogonal vector.
I've used the following to obtain the plot of the line:
Line given two points A = [A(1), A(2)] B = [B(1), B(2)]:
plot([A(1),B(1)],[A(2),B(2)])
Line given the vector W = [W(1), W(2)]':
if( W(1) == 0 )
plot( [W(1), rand(1)] ,[W(2), W(2)])
else
plot([W(1), W(1) + (W(2)^2 / W(1))],[W(2),0])
end
where I'm calculating the intersection between the x-axis and the line using the second theorem of Euclid on the triangle rectangle formed by the vector W and the line.
My problem as you can see from the picture above is that the line will only be plotted between the two points and not on all the range of my axis.
I have 2 questions:
How can I have a line going across the whole axis range?
Is there a more easy and direct way (maybe a function?) to plot the line perpendicular to a vector? (An easier and more clean way to solve point 2 above.)
Thanks in advance.
Do you know the bounds of your axis for displaying the plot? If so, you can specify the range of the plot with the axis([xmin, xmax, ymin, ymax]) function.
So, from your question, if you know the slope m and intercept b, you can make sure your function plots the line across the whole window by specifying:
plot([xmin, xmax], [m*xmin + b, m*xmax + b]);
axis([xmin, xmax, min(m*xmin+b, m*xmax+b), max(m*xmin+b, m*xmax+b)]);
where xmin and xmax are values you specify as the range of your x-axis. This will make your line go from the corner of your plot to the other corner. If you want a buffer in the y-direction, then add one like so:
buffer = 5; % for example, you set this to something that looks good.
axis([xmin, xmax, min(m*xmin+b, m*xmax+b)-buffer, max(m*xmin+b, m*xmax+b)+buffer]);

extract line of image (matrix)

I load images in matlab and work with them as double matrices.
Now I want to extract the data values across a straight line from one point of the image to another. This line however does not equal to a column or row (that would be easy).
How can I do that with matlab?
A line obeys the eq of the line y=a*x+b. Here x and y are coordiantes of the image. So if you want a line defined by two points (x1,y1) -> (x2,y2), the slope a is (y2-y1)/(x2-x1) and b=y1-a*x1. So next , select points in the matrix the obey the eq of the line as follows:
Create data and end points:
m=peaks(50);
x1=5 ; x2=42;
y1=21; y2=29;
calculate ew of line parameters:
a=(y2-y1)/(x2-x1);
b=y1-a*x1;
define the line:
x=x1:x2;
y=round(a*x+b);
select the proper matrix elements using linear indexing:
ind=sub2ind(size(m),y,x)
plot:
subplot(2,1,1)
imagesc(m); hold on
colormap(bone)
line([x1 x2],[y1 y2],'Color',[1 0 0]);
subplot(2,1,2)
plot(m(ind))

maybe matrix plot!

for an implicit equation(name it "y") of lambda and beta-bar which is plotted with "ezplot" command, i know it is possible that by a root finding algorithm like "bisection method", i can find solutions of beta-bar for each increment of lambda. but how to build such an algorithm to obtain the lines correctly.
(i think solutions of beta-bar should lie in an n*m matrix)
would you in general show the methods of plotting such problem? thanks.
one of my reasons is discontinuity of "ezplot" command for my equation.
ok here is my pic:
alt text http://www.mojoimage.com/free-image-hosting-view-05.php?id=5039TE-beta-bar-L-n2-.png
or
http://www.mojoimage.com/free-image-hosting-05/5039TE-beta-bar-L-n2-.pngFree Image Hosting
and my code (in short):
h=ezplot('f1',[0.8,1.8,0.7,1.0]);
and in another m.file
function y=f1(lambda,betab)
n1=1.5; n2=1; z0=120*pi;
d1=1; d2=1; a=1;
k0=2*pi/lambda;
u= sqrt(n1^2-betab^2);
wb= sqrt(n2^2-betab^2);
uu=k0*u*d1;
wwb=k0*wb*d2 ;
z1=z0/u; z1_b=z1/z0;
a0_b=tan(wwb)/u+tan(uu)/wb;
b0_b=(1/u^2-1/wb^2)*tan(uu)*tan(wwb);
c0_b=1/(u*wb)*(tan(uu)/u+tan(wwb)/wb);
uu0= k0*u*a; m=0;
y=(a0_b*z1_b^2+c0_b)+(a0_b*z1_b^2-c0_b)*...
cos(2*uu0+m*pi)+b0_b*z1_b*sin(2*uu0+m*pi);
end
fzero cant find roots; it says "Function value must be real and finite".
anyway, is it possible to eliminate discontinuity and only plot real zeros of y?
heretofore,for another function (namely fTE), which is :
function y=fTE(lambda,betab,s)
m=s;
n1=1.5; n2=1;
d1=1; d2=1; a=1;
z0=120*pi;
k0=2*pi/lambda;
u = sqrt(n1^2-betab^2);
w = sqrt(betab^2-n2^2);
U = k0*u*d1;
W = k0*w*d2 ;
z1 = z0/u; z1_b = z1/z0;
a0_b = tanh(W)/u-tan(U)/w;
b0_b = (1/u^2+1/w^2)*tan(U)*tanh(W);
c0_b = -(tan(U)/u+tanh(W)/w)/(u*w);
U0 = k0*u*a;
y = (a0_b*z1_b^2+c0_b)+(a0_b*z1_b^2-c0_b)*cos(2*U0+m*pi)...
+ b0_b*z1_b*sin(2*U0+m*pi);
end
i'd plotted real zeros of "y" by these codes:
s=0; % s=0 for even modes and s=1 for odd modes.
lmin=0.8; lmax=1.8;
bmin=1; bmax=1.5;
lam=linspace(lmin,lmax,1000);
for n=1:length(lam)
increment=0.001; tolerence=1e-14; xstart=bmax-increment;
x=xstart;
dx=increment;
m=0;
while x > bmin
while dx/x >= tolerence
if fTE(lam(n),x,s)*fTE(lam(n),x-dx,s)<0
dx=dx/2;
else
x=x-dx;
end
end
if abs(real(fTE(lam(n),x,s))) < 1e-6 %because of discontinuity some answers are not correct.%
m=m+1;
r(n,m)=x;
end
dx=increment;
x=0.99*x;
end
end
figure
hold on,plot(lam,r(:,1),'k'),plot(lam,r(:,2),'c'),plot(lam,r(:,3),'m'),
xlim([lmin,lmax]);ylim([1,1.5]),
xlabel('\lambda(\mum)'),ylabel('\beta-bar')
you see i use matrix to save data for this plot.
![alt text][2]
because here lines start from left(axis) to rigth. but if the first line(upper) starts someplace from up to rigth(for the first figure and f1 function), then i dont know how to use matrix. lets improve this method.
[2]: http://www.mojoimage.com/free-image-hosting-05/2812untitled.pngFree Image Hosting
Sometimes EZPLOT will display discontinuities because there really are discontinuities or some form of complicated behavior of the function occurring there. You can see this by generating your plot in an alternative way using the CONTOUR function.
You should first modify your f1 function by replacing the arithmetic operators (*, /, and ^) with their element-wise equivalents (.*, ./, and .^) so that f1 can accept matrix inputs for lambda and betab. Then, run the code below:
lambda = linspace(0.8,1.8,500); %# Create a vector of 500 lambda values
betab = linspace(0.7,1,500); %# Create a vector of 500 betab values
[L,B] = meshgrid(lambda,betab); %# Create 2-D grids of values
y = f1(L,B); %# Evaluate f1 at every point in the grid
[c,h] = contour(L,B,y,[0 0]); %# Plot contour lines for the value 0
set(h,'Color','b'); %# Change the lines to blue
xlabel('\lambda'); %# Add an x label
ylabel('$\overline{\beta}$','Interpreter','latex'); %# Add a y label
title('y = 0'); %# Add a title
And you should see the following plot:
Notice that there are now additional lines in the plot that did not appear when using EZPLOT, and these lines are very jagged. You can zoom in on the crossing at the top left and make a plot using SURF to get an idea of what's going on:
lambda = linspace(0.85,0.95,100); %# Some new lambda values
betab = linspace(0.95,1,100); %# Some new betab values
[L,B] = meshgrid(lambda,betab); %# Create 2-D grids of values
y = f1(L,B); %# Evaluate f1 at every point in the grid
surf(L,B,y); %# Make a 3-D surface plot of y
axis([0.85 0.95 0.95 1 -5000 5000]); %# Change the axes limits
xlabel('\lambda'); %# Add an x label
ylabel('$\overline{\beta}$','Interpreter','latex'); %# Add a y label
zlabel('y'); %# Add a z label
Notice that there is a lot of high-frequency periodic activity going on along those additional lines, which is why they look so jagged in the contour plot. This is also why a very general utility like EZPLOT was displaying a break in the lines there, since it really isn't designed to handle specific cases of complicated and poorly behaved functions.
EDIT: (response to comments)
These additional lines may not be true zero crossings, although it is difficult to tell from the SURF plot. There may be a discontinuity at those lines, where the function shoots off to -Inf on one side of the line and Inf on the other side of the line. When rendering the surface or computing the contour, these points on either side of the line may be mistakenly connected, giving the false appearance of a zero crossing along the line.
If you want to find a zero crossing given a value of lambda, you can try using the function FZERO along with an anonymous function to turn your function of two variables f1 into a function of one variable fcn:
lambda_zero = 1.5; %# The value of lambda at the zero crossing
fcn = #(x) f1(lambda_zero,x); %# A function of one variable (lambda is fixed)
betab_zero = fzero(fcn,0.94); %# Find the value of betab at the zero crossing,
%# using 0.94 as an initial guess