MATLAB: polyval function graphs multiple lines for N>1 - matlab

I am trying to graph a polynomial function using the following code:
y = polyfit(P,C,3);
Line = polyval(y, P);
y =
2.0372e-14 -4.0614e-09 0.0002 2.6060
figure
plot(P,C,'.')
hold on
plot(P, Line, '-')
legend('Observations','y')
axis([0 90000 0 10])
The problem is, it produces multiple lines like this:
This problem does not occur if I set N = 1 or y = polyfit(P,C,1);. In that case I get a proper graph with one line:
How can I graph just 1 line for N = 3?
Here is an Excel version of what I am trying to produce in Matlab:

This is because your observations P are in an arbitrary order: Matlab is going from point to point in that order. You don't actually need to plot the fitted curve at each value P, you just need to plot the fitted curve over the range of P:
Pfitted = linspace(min(P),max(P),1000) % Generate 1000 equally spaced points
Cfitted = polyval(y,Pfitted) % Fit to these points
plot(Pfitted,Cfitted,'-')

Related

Generate 2d plot on Matlab on given range

Im trying to plot the following on MATLAB not sure how to do it?
Y-axis ranges from -200 to 200
X-axis ranges from 0 to 10
Now the function is
x = linspace (0,10,100);
Yin = 10*sin (2*pi*x);
Ym = Yin*4*cos(2*pi*x);
I'm trying to plot graph for (Yin, Ym) that will show me the range of 0 to 10 on X-axis and -200 to 200 and Y-axis
For the plotting part the answer is:
plot(x,Yin,x,Ym);
axis([min(x),max(x),-200,200]);
But be careful with Ym = Yin*4*cos(2*pi*x); since Yin and x (thus cos(2*pi*x)) are vectors, * is the matrix multiplication. Since both Yin and x have the same shape, it may raise an error. Depending on what you want, you may need the elment-wise multiplication operator .* instead: Ym = 4*Yin.*cos(2*pi*x);

In Matlab, how to draw lines from the curve to specific xaxis position?

I have a spectral data (1000 variables on xaxis, and peak intensities as y) and a list of peaks of interest at various specific x locations (a matrix called Peak) which I obtained from a function I made. Here, I would like to draw a line from the maximum value of each peaks to the xaxis - or, eventually, place a vertical arrow above each peaks but I read it is quite troublesome, so just a vertical line is welcome. However, using the following code, I get "Error using line Value must be a vector of numeric type". Any thoughts?
X = spectra;
[Peak,intensity]=PeakDetection(X);
nrow = length(Peak);
Peak2=Peak; % to put inside the real xaxis value
plot(xaxis,X);
hold on
for i = 1 : nbrow
Peak2(:,i) = round(xaxis(:,i)); % to get the real xaxis value and round it
xline = Peak2(:,i);
line('XData',xline,'YData',X,'Color','red','LineWidth',2);
end
hold off
Simple annotation:
Here is a simple way to annotate the peaks:
plot(x,y,x_peak,y_peak+0.1,'v','MarkerFaceColor','r');
where x and y is your data, and x_peak and y_peak is the coordinates of the peaks you want to annotate. The add of 0.1 is just for a better placing of the annotation and should be calibrated for your data.
For example (with some arbitrary data):
x = 1:1000;
y = sin(0.01*x).*cos(0.05*x);
[y_peak,x_peak] = PeakDetection(y); % this is just a sketch based on your code...
plot(x,y,x_peak,y_peak+0.1,'v','MarkerFaceColor','r');
the result:
Line annotation:
This is just a little bit more complicated because we need 4 values for each line. Again, assuming x_peak and y_peak as before:
plot(x,y);
hold on
ax = gca;
ymin = ax.YLim(1);
plot([x_peak;x_peak],[ymin*ones(1,numel(y_peak));y_peak],'r')
% you could write instead:
% line([x_peak;x_peak],[ymin*ones(1,numel(y_peak));y_peak],'Color','r')
% but I prefer the PLOT function.
hold off
and the result:
Arrow annotation:
If you really want those arrows, then you need to first convert the peak location to the normalized figure units. Here how to do that:
plot(x,y);
ylim([-1.5 1.5]) % only for a better look of the arrows
peaks = [x_peak.' y_peak.'];
ax = gca;
% This prat converts the axis unites to the figure normalized unites
% AX is a handle to the figure
% PEAKS is a n-by-2 matrix, where the first column is the x values and the
% second is the y values
pos = ax.Position;
% NORMPEAKS is a matrix in the same size of PEAKS, but with all the values
% converted to normalized units
normpx = pos(3)*((peaks(:,1)-ax.XLim(1))./range(ax.XLim))+ pos(1);
normpy = pos(4)*((peaks(:,2)-ax.YLim(1))./range(ax.YLim))+ pos(2);
normpeaks = [normpx normpy];
for k = 1:size(normpeaks,1)
annotation('arrow',[normpeaks(k,1) normpeaks(k,1)],...
[normpeaks(k,2)+0.1 normpeaks(k,2)],...
'Color','red','LineWidth',2)
end
and the result:

Extract trajectory at a contour level from streamline in MATLAB

When plotting streamlines in MATLAB using quiver, streamslice or similar, is it possible to extract the contour line at given contour level?
Take this example (I have numerical data in my case, but I will use analytical functions in the example):
[X,Y] = meshgrid(0:.02:1);
Z = X.*exp(-X.^2 - Y.^2);
[DX,DY] = gradient(Z,.2,.2);
figure
imagesc([0 1], [0 1], Z)
hold on
streamslice(X,Y,DX,DY) %how to extract a trajectory at a given contour level C?
hold off
colorbar
If not, is it possible to obtain them otherwise? I was thinking of using contour in this way,
contour(X,Y,sqrt(DX.*DX+DY.*DY), [1 1]*0.07)
but this is clearly wrong when I compare to the streamlines above.
hs = streamslice(X,Y,DX,DY); as result you obtain a vector with handles to the traject lines. For example, you can get the coordinates of the first traject line:
N_trajects = length(hs); % the number of all trajectories
n = 1; % the chosen trajectory
X_traject = get(hs(n),'XData');
Y_traject = get(hs(n),'YData');
or using new version of MATLAB:
X_traject = hs(n).XData;
Y_traject = hs(n).YData;
To extract countour lines data:
C = contour(X,Y,sqrt(DX.*DX+DY.*DY), [1 1]*0.07);
where C consits data with the contour lines. In your case there is one contour line only (X_contour = C(1,:), Y_contour = C(2,:)). In the case of many contour levels, to extract them see here or here or using this.
Now we know the coordinates of the trajectory and contour level. Thus you can find the point(s) of intersection between the trajectory and the contour level.

Matlab - How can I get the expression of the level curves of a function?

I would like to obtain the level curves of a given function z=f(x,y) without using the countours function in the Matlab environment.
By letting Z equal to some constant 'c' we get a single level curve. I would like to obtain an expression of the resulting function of the form y=f(x) to be able to study other properties of it.
Basic: Example 1: Easy game
Let's consider the problem of plotting level curves of z=-x^2-y^2+100 for x,y:-10;10 and z=1.
[X,Y] = meshgrid(-10:.1:10);
Z = -X.^2+-(Y).^2+100;
surf(X,Y,Z)
we obtain the following figure:
The countour function gives me what I was looking for:
h=[1,1]
contour(X,Y,Z,h)
I can get the same result by solving the equation with respect to x
syms x y;
soly = solve(1==-x.^2-y^2+100, y)
t=soly(1)
x=-10:0.1:10;
figure;
plot(x,(99-x.^2).^(1/2));
hold on
plot(x,-(99-x.^2).^(1/2));
soly =
(99 - x^2)^(1/2)
-(99 - x^2)^(1/2)
The Problem: Example 2
Let's consider the following 3D function.
This function is the sum of guassians with random centers, variances and peaks. You can get it with the following code:
%% Random Radial Basis functions in space
disp('3D case with random path - 10 rbf:');
N = 10 % number of random functions
stepMesh = 0.1;
Z = zeros((XMax-XMin)/stepMesh+1,(XMax-XMin)/stepMesh+1);
[X,Y] = meshgrid(XMin:stepMesh:XMax);
% random variance in [a;b] = [0.3;1.5]
variances = 0.3 + (1.5-0.3).*rand(N,1);
% random amplitude [0.1;1]
amplitudes = 0.1 + (1-0.1).*rand(N,1);
% Random Xcenters in [-XMin;xMax]
Xcenters = XMin+ (XMax-XMin).*rand(N,1);
Ycenters = YMin+ (YMax-YMin).*rand(N,1);
esp=zeros(N,1);
esp=1./(2*(variances).^2);
for i=1:1:N
disp('step:')
disp(i)
Xci=Xcenters(i,1)*ones((XMax-XMin)/stepMesh+1,((XMax-XMin)/stepMesh+1)*2);
Yci=Ycenters(i,1)*ones((YMax-YMin)/stepMesh+1,((YMax-YMin)/stepMesh+1)*2);
disp('Radial Basis Function: [amplitude,variance,center]');
disp(amplitudes(i,1))
disp(variances(i,1))
disp(Xcenters(i,1))
disp(Ycenters(i,1))
Z = Z + 1*exp(-((X-Xci(:,1:((XMax-XMin)/stepMesh+1))).^2+(Y-Yci(:,((XMax-XMin)/stepMesh+2):((YMax-YMin)/stepMesh+1)*2)).^2)*esp(i,1).^2);
end
surf(X,Y,Z)
The countour3 function draws a contour plot of matrix Z in a 3-D view, which is really nice, but it doesn't give me the expression of these functions in 2D.
figure;
contour3(X,Y,Z);
grid on
box on
view([130,30])
xlabel('x-axis')
ylabel('y-axis')
zlabel('z-axis')
The Question:
How can I get an explicit expression of the level curves of the second example?

How to fit a curve by a series of segmented lines in Matlab?

I have a simple loglog curve as above. Is there some function in Matlab which can fit this curve by segmented lines and show the starting and end points of these line segments ? I have checked the curve fitting toolbox in matlab. They seems to do curve fitting by either one line or some functions. I do not want to curve fitting by one line only.
If there is no direct function, any alternative to achieve the same goal is fine with me. My goal is to fit the curve by segmented lines and get locations of the end points of these segments .
First of all, your problem is not called curve fitting. Curve fitting is when you have data, and you find the best function that describes it, in some sense. You, on the other hand, want to create a piecewise linear approximation of your function.
I suggest the following strategy:
Split manually into sections. The section size should depend on the derivative, large derivative -> small section
Sample the function at the nodes between the sections
Find a linear interpolation that passes through the points mentioned above.
Here is an example of a code that does that. You can see that the red line (interpolation) is very close to the original function, despite the small amount of sections. This happens due to the adaptive section size.
function fitLogLog()
x = 2:1000;
y = log(log(x));
%# Find section sizes, by using an inverse of the approximation of the derivative
numOfSections = 20;
indexes = round(linspace(1,numel(y),numOfSections));
derivativeApprox = diff(y(indexes));
inverseDerivative = 1./derivativeApprox;
weightOfSection = inverseDerivative/sum(inverseDerivative);
totalRange = max(x(:))-min(x(:));
sectionSize = weightOfSection.* totalRange;
%# The relevant nodes
xNodes = x(1) + [ 0 cumsum(sectionSize)];
yNodes = log(log(xNodes));
figure;plot(x,y);
hold on;
plot (xNodes,yNodes,'r');
scatter (xNodes,yNodes,'r');
legend('log(log(x))','adaptive linear interpolation');
end
Andrey's adaptive solution provides a more accurate overall fit. If what you want is segments of a fixed length, however, then here is something that should work, using a method that also returns a complete set of all the fitted values. Could be vectorized if speed is needed.
Nsamp = 1000; %number of data samples on x-axis
x = [1:Nsamp]; %this is your x-axis
Nlines = 5; %number of lines to fit
fx = exp(-10*x/Nsamp); %generate something like your current data, f(x)
gx = NaN(size(fx)); %this will hold your fitted lines, g(x)
joins = round(linspace(1, Nsamp, Nlines+1)); %define equally spaced breaks along the x-axis
dx = diff(x(joins)); %x-change
df = diff(fx(joins)); %f(x)-change
m = df./dx; %gradient for each section
for i = 1:Nlines
x1 = joins(i); %start point
x2 = joins(i+1); %end point
gx(x1:x2) = fx(x1) + m(i)*(0:dx(i)); %compute line segment
end
subplot(2,1,1)
h(1,:) = plot(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro');
title('Normal Plot')
subplot(2,1,2)
h(2,:) = loglog(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro');
title('Log Log Plot')
for ip = 1:2
subplot(2,1,ip)
set(h(ip,:), 'LineWidth', 2)
legend('Data', 'Piecewise Linear', 'Location', 'NorthEastOutside')
legend boxoff
end
This is not an exact answer to this question, but since I arrived here based on a search, I'd like to answer the related question of how to create (not fit) a piecewise linear function that is intended to represent the mean (or median, or some other other function) of interval data in a scatter plot.
First, a related but more sophisticated alternative using regression, which apparently has some MATLAB code listed on the wikipedia page, is Multivariate adaptive regression splines.
The solution here is to just calculate the mean on overlapping intervals to get points
function [x, y] = intervalAggregate(Xdata, Ydata, aggFun, intStep, intOverlap)
% intOverlap in [0, 1); 0 for no overlap of intervals, etc.
% intStep this is the size of the interval being aggregated.
minX = min(Xdata);
maxX = max(Xdata);
minY = min(Ydata);
maxY = max(Ydata);
intInc = intOverlap*intStep; %How far we advance each iteraction.
if intOverlap <= 0
intInc = intStep;
end
nInt = ceil((maxX-minX)/intInc); %Number of aggregations
parfor i = 1:nInt
xStart = minX + (i-1)*intInc;
xEnd = xStart + intStep;
intervalIndices = find((Xdata >= xStart) & (Xdata <= xEnd));
x(i) = aggFun(Xdata(intervalIndices));
y(i) = aggFun(Ydata(intervalIndices));
end
For instance, to calculate the mean over some paired X and Y data I had handy with intervals of length 0.1 having roughly 1/3 overlap with each other (see scatter image):
[x,y] = intervalAggregate(Xdat, Ydat, #mean, 0.1, 0.333)
x =
Columns 1 through 8
0.0552 0.0868 0.1170 0.1475 0.1844 0.2173 0.2498 0.2834
Columns 9 through 15
0.3182 0.3561 0.3875 0.4178 0.4494 0.4671 0.4822
y =
Columns 1 through 8
0.9992 0.9983 0.9971 0.9955 0.9927 0.9905 0.9876 0.9846
Columns 9 through 15
0.9803 0.9750 0.9707 0.9653 0.9598 0.9560 0.9537
We see that as x increases, y tends to decrease slightly. From there, it is easy enough to draw line segments and/or perform some other kind of smoothing.
(Note that I did not attempt to vectorize this solution; a much faster version could be assumed if Xdata is sorted.)