I would like to develop some intuition for this language. Specifically about plotting functions on some interval. Here is a concrete example I am trying to work out. Plot exp(x) over the closed interval [-2,2]. Here exp(x) is Matlab notation for e^x, I think. This is the script based on a guide I just read :
x = [ -2 , 2 ];
y = exp(x);
plot(x,y)
The result is not an exponential curve, but a straight line. What is wrong with this script? And also, if anyone can recommend a good guide for this, I would appreciate it very much. Google results I found only have worked examples.
Two methods of adjusting the number of points plotted (samples) of the function are to either specify the interval between the points or the number of points to be plotted. The plot() function will plot the vectors x and y which will plot the number of points equal to the length of vector x. Similar idea to an Excel sheet scatter plot that is joined with line.
Setting the Interval Between the Plotting Points
X_Minimum = -2;
X_Maximum = 2;
Plotting_Interval = 0.25;
x = (X_Minimum: Plotting_Interval: X_Maximum);
y = exp(x);
plot(x,y,'o-');
title(num2str(Plotting_Interval) + " Interval Between Points");
Setting the Number of Plotting Points
X_Minimum = -2;
X_Maximum = 2;
Number_Of_Points = 18;
x = linspace(X_Minimum,X_Maximum,Number_Of_Points);
y = exp(x);
plot(x,y,'o-');
title(num2str(Number_Of_Points) + " Points Plotted");
Ran using MATLAB R2019b
This is because you only input two point into the function plot():(-2,exp(-2)),(2,exp(2))
.In matlab,the x &y of plot(x,y) are vector of the points you have but not their intervals.
Related
I am plotting 2 multivariate gaussians in MATLAB, and my decision line as a result will be parabolic in shape, which I can see by looking at the contour or surf of the data. However, I need a way to quantify the pparabola that represents the decisionline. Taking the local minima seems like a good idea, but I dont know if that is possible for a contour plot.
decision line is where difference of two gaussian function becomes zero.
so using fcontour from symbolic toolbox:
syms x y
mu_x = 10;
mu_y = 10;
mu_x1 = 60;
mu_y1 = 10;
sigma = 20;
sigma1 = 30;
f = 1/(2*pi*sigma^2) * exp(-(x-mu_x)^2+(y-mu_y)^2)/(2*sigma^2)...
-( 1/(2*pi*sigma1^2) * exp(-(x-mu_x1)^2+(y-mu_y1)^2)/(2*sigma1^2));
fcontour(f ,'LevelList', [0])
but I do not have tested
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,'-')
I'm trying to plot multiple Fourier series approximations for the function f(x)=(x^2-pi^2)^3, but for some reason my MATLAB will only plot maximum two of the approximations (along with the original f). How can I get it to plot 4 or more? My code for the series is
function [Y]=fourier(X)
N=input('enter the value of N:' )
SN=-16*pi^6/35;
for n=1:N
SN=SN+96*(-1)^n/n^5*(15/n-pi^2).*cos(n*X);
end
Y=SN;
and using
plot(X,Y1,'b',X,Y2,'r',X,Y3,'m',X,Y4,'g')
(where Yi=fourier(X), X=[-pi:0.01:pi] are the various approximations for different N) isn't working; nor is plotting them one by one.
Many thanks in advance for any help that anyone can offer - as you may have noticed I'm a very amateur programmer!!
I have no problems.
I modified your fourier function to accept input N:
function Y = fourier(X,N)
SN = -16*pi^6/35;
for n = 1:N
SN = SN+96*(-1)^n/n^5*(15/n-pi^2).*cos(n*X);
end
Y = SN;
Then, I get the 4 lines:
X = (-pi:0.01:pi)';
Y = [fourier(X,1), fourier(X,2), fourier(X,3), fourier(X,4)];
plot(X,Y)
legend 1 2 3 4
set(gca, 'Xlim',[-3.3, -2.3], 'Ylim',[-60,79])
I want to plot the area above and below a particular value in x axis.
The problem i am facing is with discrete values. The code below for instance has an explicit X=10 so i have written it in such a way that i can find the index and calculate the values above and below that particular value but if i want to find the area under the curve above and below 4 this program will now work.
Though in the plot matlab does a spline fitting(or some sort of fitting for connecting discrete values) there is a value for y corresponding to x=4 that matlab computes i cant seem to store or access it.
%Example for Area under the curve and partial area under the curve using Trapezoidal rule of integration
clc;
close all;
clear all;
x=[0,5,10,15,20];% domain
y=[0,25,50,25,0];% Values
LP=log2(y);
plot(x,y);
full = trapz(x,y);% plot of the total area
I=find(x==10);% in our case will be the distance value up to which we want
half = trapz(x(1:I),y(1:I));%Plot of the partial area
How can we find the area under the curve for a value of ie x = 2 or 3 or 4 or 6 or 7 or ...
This is an elaboration of patrik's comment, "first interpolate and then integrate".
For the purpose of this answer I'll assume that the area in question is the area that can be seen in the plot, and since plot connects points by straight lines I assume that linear interpolation is adequate. Moreover, since the trapezoidal rule itself is based on linear interpolation, we only need interpolated values at the beginning and end of the interval.
Starting from the given points
x = [0, 5, 10, 15, 20];
y = [0, 25, 50, 25, 0];
and the integration interval limits, say
xa = 4;
xb = 20;
we first select the data points within the limits
ind = (x > xa) & (x < xb);
xw = x(ind);
yw = y(ind);
and then complete them by interpolation values at the edges:
ya = interp1(x, y, xa);
yb = interp1(x, y, xb);
xw = [xa, xw, xb];
yw = [ya, yw, yb];
Now we can simply apply trapezoidal integration:
area = trapz(xw, yw);
I think that you either need more samples, or to interpolate the data. Another alternative is to use a function handle. Then you need to know the function though. Example using linear interpolation follows.
x0 = [0;5;10;15;20];
y0 = [0,25,50,25,0];
x1 = 0:20;
y1 = interp1(x0,y0,x1,'linear');
xMax = 4;
partInt = trapz(x1(x1<=xMax),y1(x1<=xMax));
Some other kind of interpolation may be suitable, but that is hard to say without more information. Also, this interpolates from the beginning to x. However, I guess figuring out how to change the limits should be easy from here. This solution is different than the former, since it is less depending on the pyramid shape of the data. So to say, it is more general.
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.)