Write Equation from Fit in Legend, Matlab - matlab

So, I've fitted an exponential curve to some data points using 'fit' and now I want to get the equation of the fitted curve in the Legend in the graph. How can I do that? I want to have an equation on the form y=Ce^-xt in the legend. Can I get the coefficients, C and x from the fitted curve and then put the equation inside the legend? Or can I get the whole equation written out in some way? I have many plotted graphs so I would be grateful if the method is not so much time consuming.
Edit: Perhaps I was unclear. The main problem is how I should get out the coefficients from the fitted line I've plotted. Then I want to have the equation inside the legend in my graph. Do I have to take out the coefficients by hand (and how can it be done?) or can Matlab write it straight out like in, for example, excel?

The documentation explains that you can obtain the coefficients derived from a fit executed as c = fit(...), as
coef=coeffvalues(c)
C=coef(1)
x=coef(2)
You can create your own legend as illustrated by the following example.
Defining C and x as the parameters from your fits,
% simulate and plot some data
t= [0:0.1:1];
C = 0.9;
x = 1;
figure, hold on
plot(t,C*exp(-x*t)+ 0.1*randn(1,length(t)),'ok', 'MarkerFaceColor','k')
plot(t,C*exp(-x*t),':k')
axis([-.1 1.2 0 1.2])
% here we add the "legend"
line([0.62 0.7],[1 1],'Linestyle',':','color','k')
text(0.6,1,[ ' ' num2str(C,'%.2f'),' exp(-' num2str(x,'%.2f') ' t) ' ],'EdgeColor','k')
set(gca,'box','on')
Example output:
You may have to adjust number formatting and the size of the text box to suit your needs.

Here is a piece of code that will display the fitted equation in the legend box. You can reduce the amount of digits in the legend by manipulating the sprintf option: %f to %3.2f for example.
%some data
load census
s = fitoptions('Method','NonlinearLeastSquares','Lower',[0,0],'Upper',[Inf,max(cdate)],'Startpoint',[1 1]);
f = fittype('a*(x-b)^n','problem','n','options',s);
%fit, plot and legend
[c2,gof2] = fit(cdate,pop,f,'problem',2)
plot(c2,'m');
legend(sprintf('%f * (x - %f)^%d',c2.a,c2.b,c2.n));
The command disp(c2) will display in the command window what is stored in the fit object. Also, by enabling the "datatip in edit mode" option (Matlab preferences, then Editor, then Display), you will have an instant view on the data stored by putting your mouse cursor over an object.

function [S]=evaFit(ffit)
S=sprintf('y=%s',formula(ffit));
S2='';
N=coeffnames(ffit);
V=coeffvalues(ffit);
for i= 1:numcoeffs(ffit)
S2=sprintf('%s %c=%f',S2, string(N(i)), V(i));
end
S=sprintf('%s%s',S, S2);
end

Related

Calclulating a set of lines slopes after using Xlim in Matlab

I'm plotting a series of lines in MATLAB and the figure is like this:
As you can see the X-axis is Frequency, I want to limit the frequency spectrum so I use Xlim function in my code to select my desired bandwidth while plotting.
Now I want to calculate the slope of those lines in the chosen frequency bandwidth (what's in the plot window), not the entire band but if I choose the basic fitting option, it's clearly giving me a linear fit for the line over the entire frequency band.
Any advice?
Thanks.
You can do this in the matlab script:
% your data
f = linspace(2e7,11e7,100);
x = linspace(-0.5,-2.5,100)+0.1*rand(1,100);
% Linear fit in a specific range:
[~,i] = find( f>3e7 & f<9e7 ); % <= set your range here
p = polyfit(f(i),x(i),1); % <= note the (i) for both variables
figure;
hold all
plot(f,x,'r.-')
plot(f(i),polyval(p,f(i)),'k-','LineWidth',2) % <= polyval takes the 'p' from polyfit + the data on the x-axis
% the fit is y = p(1)*x+p(2)
You won't be able to use the basic fitting GUI for what you want to do. You will probably need to write a custom function that will "crop" the data in question to the x-limits of your current view. Then use polyfit or similar on those data segments to create the fit.

MATLAB: adding contour lines to points [duplicate]

I'd like to know how to draw a graph with 2 electric charges Q and -Q and their total E, for a specific point (eg (4,5)), with contour f..
My M-file actually scans the area (from -3x to 3x) and calculates E for every spot, stores it in a table, but after this, I don't know how to use contourf to draw it..
syms i
syms j
syms d
d=input('dwse thn timi tou d,ths apostashs')
j=0
i=0
for j=-d:d/1000:d
j=j+1
for i=-d:d/1000:d
i=i+1
z=(i,j)
end, end
Based on Coulomb's law, the electric field created by a single, discrete charge q at a distance r is given by:
E=q/(4*pi*e0*r.^2);
If you have several charges you can use the superposition principle and add the contribution of each charge.
The only thing left to do is to create a grid to compute the electrical field. For this you can use tha Matlab function meshgrid.
A simple example in Matlab would be:
k=1/4/pi/8.854e-12;
d=2;
q=[-1 1];
x=[-d/2 d/2];
y=[0 0];
dx=0.01;
X=(-d:dx:d);
Y=(-d:dx:d);
[X Y]=meshgrid(X,Y);
E=zeros(size(X));
for i=1:numel(q)
r=sqrt((X-x(i)).^2+(Y-y(i)).^2);
E=E+k*q(i)./r.^2;
end
E(isinf(E))=NaN;
figure;
contourf(X,Y,E);
axis image;
Hope it helps you. You can read the documentation of contourf to tweak the plot to your needs.
You need to give some more information in your question: What is the problem you are having? What have you tried?
However, assuming that z(i,j) is your electric field calculated on a 2d grid, just call contourf after your for loops as
contourf(z)

MATLAB Adding Gaussian fit to histogram

I am trying to add Gaussian fit to the histogram in MATLAB, but I do not know how to apply the fit to one particular peak only.
http://postimg.org/image/phms61rdh/ first plot
http://postimg.org/image/sindrn8er/ second plot
I am also posting part of the code I have been using:
data_Rb = (importdata('path\name.txt'));
counts_Rb = data_Rb.data(:,3);
figure
hist(counts_Rb, nbins);
xlim([0 120]);
title('Rubidium');
histfit(counts_Rb,1000);
pd=fitdist(counts_Rb(:),'normal')
x=0:0.001:120;
PDF=pdf(pd,x); %PDF is a vector of y values: it's our fit
PDF=PDF/max(PDF); %nor
y=ylim;
PDF=PDF*y(2);
hold on
plot(x,PDF,'r-','LineWidth',2);
hold off
These two blocks give me two different Gaussians as shown in the first picture. I do not understand why they fit data so badly: is it because of the tail on the RHS?
In the second plot I need to apply Gaussian fit to the last peak only. How should I do it?
And finally, after applying the fit, fit results are outputed onto the screen. Is there a function to save them into an array or so for later use?
Thanks in advance!
Regarding your last question, see How can I access the fitted distribution parameters from the HISTFIT function in Statistiics Toolbox ?
There is a workaround for this isssue by making a copy of the HISTFIT
function and modifying the code to pass out the "pd" variable. One way
to do this is to change the "h" output on the first line of the code
to "varargout" and add the following to the end of the file:
h = [hh; hh1];
argout={h,pd};
if nargout > length(argout)
error('Too many output arguments.');
end
[varargout{1:nargout}]=argout{1:nargout};

MATLAB going from Cart to Pol back to Cart coords for cylindrical plot

1. What I WANT to do:
(i) Use input n to generate an n*n cartesian grid
[x y] = meshgrid(linspace(-1,1,n));
(ii) Generate polar coordinates
[theta r] = cart2pol(x,y);
(iii) Evaluate a function in cylindrical coordinates
z = f(theta,r);
(iv) Plot the result using (say) pcolor (or surf, or anything)
pcolor(x,y,abs(z).^2) %The function is complex, a Laguerre-Gauss to be exact.
2. What I CAN do... The only way I can get the plots to work is by starting with my polar parameters and working back to cartesian from there:
(i) Define parameters
r=linspace(0,1,n); theta=linspace(0,2*pi,n);
(ii) Create both grids and evaluate f
[theta r]=meshgrid(theta,r);
[x y]=pol2cart(theta,r);
z=f(theta,r);
(iii) Plot
pcolor(x,y,abs(z).^2)
The PROBLEM is that now my grid is circular, and I would like to evaluate the function everywhere ON A RECTANGULAR grid (because my analysis depends on having square pixel arrays). The reiterate, using method 2 above, I get a circular plot circumscribed in a square; imagine a black circle with white along the edges... but I WANT to evaluate the function in this "white" region. HOWEVER, using method 1 does NOT work -- the function is all messed up when I plot (Just google Laguerre-Gauss modes to see what the plots should look like).
I want to be able to start with a rect grid and assign every point a polar coordinate, instead of start with polar coordinates and assign them all cartesian points.
I've been messing with this on an off for a long time, and I can't figure out how to get around this seemingly simple issue.
Edit 1
It seems that the problem lies in how the coordinate matrices are generated. Below I've posted screen-shots of a simple 3by3 example illustrating how approach 1 and approach 2 generate different numbers.
How to make these numbers compatible?
I have no reputation points so I cannot upload the images directly... links below show the 3by3 example... see comments for links to actual images of the Laguerre-Gauss plots I'm trying to make...
apply cart2pol
apply pol2cart
Edit 2
Currently, the result of approach (1.) gives wrong results, as shown here:
desired approach, wrong result
The second approach gives the right images, unfortunately it's only a circle and not the entire square. It is shown here:
implemented approach, limited result
3D plots of both approaches are shown here - only the colorful part of the top figure is correct.
Edit 3
Here is a screenshot of the function f which is being used above. Note, that it asks for more input parameters than just r,theta. Typical values are:
w0 = 0.5;
p = 0;
l = 5;
The function C gives a normalization and L are Laguerre polynomials. Both of these functions have been thoroughly tested and yield the expected results.
Edit 4
Here is enough code to run my example z=U(0,5,r,phi,w0)+U(0,-5,r,phi,w0); explicitly. The plot itself is given by pcolor(x,y,abs(z).^2).
Note that the Lpl() function is inserted as a comment. This will have to be saved as its own m-file for the U function to run properly.
%% Laguerre-Gauss Modes U = U(p,l,r,phi,w0)
% Source: OAM theory paper section 2.A eqn 1.
% Assuming POLAR coordinates and evaluating AT beam waist.
% -- That is, z=0 for w(z)=w0(sqrt(1+z/zR))
% ---- ie, w(0) = w0
% Assuming z=0 also renders the Gouy phase arctan(z/zR) irrelevant.
% Note: Rayleigh Range zR is not explicitly defined because z=0 --> it is irrelevant too.
% Since zR is the only wavelength dependent term, wavelength also doesn't
% matter.
function out = U(p,l,r,phi,w0)
%Function handles for clarity
e = #(x) exp(x);
C = #(p,l) sqrt((2*factorial(p))/(pi*factorial(p+abs(l))));
L = #(p,l,z) Lpl(p,l,z);
%% Lpl() FUNCTION
% function out = Lpl(p,l,z)
%
% l=abs(l);
% LL=0;
% for mm=1:p+1
% m=mm-1;
% L=LL;
% LL= L+((-1)^m)*(factorial(p+l)/(factorial(p-m)*factorial(l+m)*factorial(m)))*(z.^m);
% end
% out = LL;
%%
out = (C(p,l)/w0)*...
(((sqrt(2).*r)/w0)^abs(l))*...
(e((-r.^2)/w0^2))*...
(L(p,l,((2.*r.^2)/w0^2)))*...
(e((-1)*1i*l.*phi)); ``
Edit
The answer was rewritten based on the code provided in Edit 4 of the question.
I think the trouble stems from the function U. You don't apply element wise operations to all parts of the equation. If you change it to:
out = (C(p,l)./w0).* ... % here it's a .* instead of *
(((sqrt(2).*r)./w0).^abs(l)).* ... % here it's a .* instead of *
(e((-r.^2)./w0.^2)).* ... % here it's a .* instead of *
(L(p,l,((2.*r.^2)./w0.^2))).* ... % here it's a .* instead of *
(e((-1)*1i*l.*phi));
You get the following two results, shown below.
This figure used an input of cartesian coordinates:
And this figure used the polar coordinates:
The "coarser" resolution in the second figure is due to the less suitable resolution of the grid. But in essence you resolve the same features.

Matlab cdfplot: how to control the spacing of the marker spacing

I have a Matlab figure I want to use in a paper. This figure contains multiple cdfplots.
Now the problem is that I cannot use the markers because the become very dense in the plot.
If i want to make the samples sparse I have to drop some samples from the cdfplot which will result in a different cdfplot line.
How can I add enough markers while maintaining the actual line?
One method is to get XData/YData properties from your curves follow solution (1) from #ephsmith and set it back. Here is an example for one curve.
y = evrnd(0,3,100,1); %# random data
%# original data
subplot(1,2,1)
h = cdfplot(y);
set(h,'Marker','*','MarkerSize',8,'MarkerEdgeColor','r','LineStyle','none')
%# reduced data
subplot(1,2,2)
h = cdfplot(y);
set(h,'Marker','*','MarkerSize',8,'MarkerEdgeColor','r','LineStyle','none')
xdata = get(h,'XData');
ydata = get(h,'YData');
set(h,'XData',xdata(1:5:end));
set(h,'YData',ydata(1:5:end));
Another method is to calculate empirical CDF separately using ECDF function, then reduce the results before plotting with PLOT.
y = evrnd(0,3,100,1); %# random data
[f, x] = ecdf(y);
%# original data
subplot(1,2,1)
plot(x,f,'*')
%# reduced data
subplot(1,2,2)
plot(x(1:5:end),f(1:5:end),'r*')
Result
I know this is potentially unnecessary given MATLAB's built-in functions (in the Statistics Toolbox anyway) but it may be of use to other viewers who do not have access to the toolbox.
The empirical CMF (CDF) is essentially the cumulative sum of the empirical PMF. The latter is attainable in MATLAB via the hist function. In order to get a nice approximation to the empirical PMF, the number of bins must be selected appropriately. In the following example, I assume that 64 bins is good enough for your data.
%# compute a histogram with 64 bins for the data points stored in y
[f,x]=hist(y,64);
%# convert the frequency points in f to proportions
f = f./sum(f);
%# compute the cumulative sum of the empirical PMF
cmf = cumsum(f);
Now you can choose how many points you'd like to plot by using the reduced data example given by yuk.
n=20 ; % number of total data markers in the curve graph
M_n = round(linspace(1,numel(y),n)) ; % indices of markers
% plot the whole line, and markers for selected data points
plot(x,y,'b-',y(M_n),y(M_n),'rs')
verry simple.....
try reducing the marker size.
x = rand(10000,1);
y = x + rand(10000,1);
plot(x,y,'b.','markersize',1);
For publishing purposes I tend to use the plot tools on the figure window. This allow you to tweak all of the plot parameters and immediately see the result.
If the problem is that you have too many data points, you can:
1). Plot using every nth sample of the data. Experiment to find an n that results in the look you want.
2). I typically fit curves to my data and add a few sparsely placed markers to plots of the fits to differentiate the curves.
Honestly, for publishing purposes I have always found that choosing different 'LineStyle' or 'LineWidth' properties for the lines gives much cleaner results than using different markers. This would also be a lot easier than trying to downsample your data, and for plots made with CDFPLOT I find that markers simply occlude the stairstep nature of the lines.