I need to write a script that load some data file which contains variables x and y and fit first, second, third, fourth, and fifth degree polynomials to it. Plot the data as blue dots on a figure, and plot all five polynomial fits using lines of different colors on the same axes. This is how it should be:
Instead I get my polynomials separated from the data. The Data axis are([100 200 -0.2 0.2]), while my polinoms are at axis ([0 100 -0.2 0.2]).
My script:
%Fitting Polynomials
Dat=load('randomData.mat');
[p1,S1,mu] = polyfit(x,y,1)
[Y1,delta]= polyval(p1,x,S1,mu)
[p2,S2,mu] = polyfit(x,y,2)
[Y2,delta]= polyval(p2,x,S2,mu)
[p3,S3,mu] = polyfit(x,y,3)
[Y3,delta]= polyval(p3,x,S3,mu)
[p4,S4,mu] = polyfit(x,y,4)
[Y4,delta]= polyval(p4,x,S4,mu)
[p5,S5,mu] = polyfit(x,y,5)
[Y5,delta]= polyval(p5,x,S5,mu)
figure;
plot(x,y,'b.','MarkerSize',10)
hold on
plot(Y1,'r')
plot(Y2,'g')
plot(Y3,'m')
plot(Y4,'c')
plot(Y5,'k')
xlabel('X');
ylabel('Y');
title('Polynomial fitting to noisy data');
legend('Data','order 1','order 2','order 3','order 4','order 5')
hold off
plot(Y1,'r')
should be
plot(x, Y1,'r');
and so on
Remember that Y1 doesn't actually represent a polynomial relationship, it is just a vector of samples of the polynomial p1 evaluated (via polyval) at the points x.
Related
I want to represent data with 2 variables in 2D format. The value is represented by color and the 2 variables as the 2 axis. I am using the contourf function to plot my data:
clc; clear;
load('dataM.mat')
cMap=jet(256); %set the colomap using the "jet" scale
F2=figure(1);
[c,h]=contourf(xrow,ycol,BDmatrix,50);
set(h, 'edgecolor','none');
xlim([0.0352 0.3872]);
ylim([0.0352 0.3872]);
colormap(cMap);
cb=colorbar;
caxis([0.7 0.96]);
% box on;
hold on;
Both xrow and ycol are 6x6 matrices representing the coordinates. BDmatrix is the 6x6 matrix representing the corresponding data. However, what I get is this:
The following is the xrow and yrow matices:
The following is the BDmatrix matices:
Would it be possible for the contour color to vary smoothly rather than appearing as straight lines joining the data points? The problem of this figure is the coarse-granularity which is not appealing. I have tried to replace contourf with imagec but it seems not working. I am using MATLAB R2015b.
You can interpolate your data.
newpoints = 100;
[xq,yq] = meshgrid(...
linspace(min(min(xrow,[],2)),max(max(xrow,[],2)),newpoints ),...
linspace(min(min(ycol,[],1)),max(max(ycol,[],1)),newpoints )...
);
BDmatrixq = interp2(xrow,ycol,BDmatrix,xq,yq,'cubic');
[c,h]=contourf(xq,yq,BDmatrixq);
Choose the "smoothness" of the new plot via the parameter newpoints.
To reduce the Color edges, you can increase the number of value-steps. By default this is 10. The following code increases the number of value-steps to 50:
[c,h]=contourf(xq,yq,BDmatrixq,50);
A 3D-surf plot would be more suitable for very smooth color-shading. Just rotate it to a top-down view. The surf plot is also much faster than the contour plot with a lot of value-steps.
f = figure;
ax = axes('Parent',f);
h = surf(xq,yq,BDmatrixq,'Parent',ax);
set(h, 'edgecolor','none');
view(ax,[0,90]);
colormap(Jet);
colorbar;
Note 1: Cubic interpolation is not shape-preserving. That means, the interpolated shape can have maxima which are greater than the maximum values of the original BDmatrix (and minima which are less). If BDmatrix has noisy values, the interpolation might be bad.
Note 2: If you generated xrow and yrow by yourself (and know the limits), than you do not need that min-max-extraction what I did.
Note 3: After adding screenshots of your data matrices to your original posting, one can see, that xrow and ycol come from an ndgrid generator. So we also must use this here in order to be consistent. Since interp2 needs meshgrid we have to switch to griddedInterpolant:
[xq,yq] = ndgrid(...
linspace(min(min(xrow,[],1)),max(max(xrow,[],1)),newpoints ),...
linspace(min(min(ycol,[],2)),max(max(ycol,[],2)),newpoints )...
);
F = griddedInterpolant(xrow,ycol,BDmatrix,'cubic');
BDmatrixq = F(xq,yq);
I'm trying to plot two lines (data and linear fit) in a single graph with logarithmic scale. My code:
Iots = I_An./Temp.^2; % I Over T Squared
Oot = 1./Temp; % One Over T
[p,~] = polyfit(Oot,Iots,1);
linfit = polyval(p,Oot);
figure('color','w','units','normalized','outerposition',[0 0 1 1]);
hold on
loglog(Oot,Iots,'.','LineWidth',2);
loglog(Oot,linfit,':r','LineWidth',2);
The result is not a logarithmic scale graph:
If I run just one of the plot lines, it works on its own. What should I do? Are there any contradicting commands?
You want to call hold on after creating your first loglog plot. Also, you only need to use loglog on the first plot to create the logarithmic axes. After than you can just call normal plot and it will use the logarithmic axes.
x = linspace(0, 100);
loglog(x, x, '.', 'LineWidth', 2);
hold on
plot(x, x.^2, '.r', 'LineWidth',2);
I'm using the Matlab function "hist" to estimate the probability density function of a realization of a random process I have.
I'm actually:
1) taking the histogram of h0
2) normalizing its area in order to get 1
3) plotting the normalized curve.
The problem is that, no matter how many bins I use, the histogram never start from 0 and never go back to 0 whereas I would really like that kind of behavior.
The code I use is the following:
Nbin = 36;
[n,x0] = hist(h0,Nbin);
edge = find(n~=0,1,'last');
Step = x0(edge)/Nbin;
Scale_factor = sum(Step*n);
PDF_h0 = n/Scale_factor;
hist(h0 ,Nbin) %plot the histogram
figure;
plot(a1,p_rice); %plot the theoretical curve in blue
hold on;
plot(x0, PDF_h0,'red'); %plot the normalized curve obtained from the histogram
And the plots I get are:
If your problem is that the plotted red curve does not go to zero: you can solve that adding initial and final points with y-axis value 0. It seems from your code that the x-axis separation is Step, so it would be:
plot([x0(1)-Step x0 x0(end)+Step], [0 PDF_h0 0], 'red')
With the following code I'm able to draw the plot of a single 2D-Gaussian function:
x=linspace(-3,3,1000);
y=x';
[X,Y]=meshgrid(x,y);
z=exp(-(X.^2+Y.^2)/2);
surf(x,y,z);shading interp
This is the produced plot:
However, I'd like to plot a grid having a specified number x of these 2D-Gaussians.
Think of the following picture as an above view of the plot I'd like to produce (where in particular the grid is made of 5x5 2D-Gaussians). Each Gaussian should be weighed by a coefficient such that if it's negative the Gaussian is pointing towards negative values of the z axis (black points in the grid below) and if it's positive it's as in the above image (white points in the grid below).
Let me provide some mathematical details. The grid corresponds to a mixture of 2D-Gaussians summed as in the following equation:
In which each Gaussian has its own mean and deviation.
Note that each Gaussian of the mixture should be put in a determined (X,Y) coordinate, in such a way that they are equally distant from each other. e.g think of the central Gaussian in (0,0) then the other ones should be in (-1,1) (0,1) (1,1) (-1,0) (1,0) (-1,-1) (0,-1) (1,-1) in the case of a grid with dimension 3x3.
Can you provide me (and explain to me) how can I do such a plot?
Thanks in advance for the help.
Indeed you said yourself, put (as an example just for the means)
[X,Y]=meshgrid(x,y); % //mesh
g_centers = -3:3;
[x_g,y_g] = meshgrid(g_centers,g_centers); % //grid of centers (coarser)
mu = [x_g(:) , y_g(:)]; % // mesh of centers in column
z = zeros(size(X));
for i = 1:size(mu,1)
z= z + exp(-((X-mu(i,1)).^2+(Y-mu(i,2)).^2)/( 2* .001) );
end
surf(X,Y,z);shading interp
I have a problem dealing with 3rd dimension plot for three variables.
I have three matrices: Temperature, Humidity and Power. During one year, at every hour, each one of the above were measured. So, we have for each matrix 365*24 = 8760 points. Then, one average point is taken every day. So,
Tavg = 365 X 1
Havg = 365 X 1
Pavg = 365 X 1
In electrical point of veiw, the power depends on the temperature and humidity. I want to discover this relation using a three dimensional plot.
I tried using mesh, meshz, surf, plot3, and many other commands in MATLAB but unfortunately I couldn't get what I want. For example, let us take first 10 days. Here, every day is represented by average temperature, average humidity and average power.
Tavg = [18.6275
17.7386
15.4330
15.4404
16.4487
17.4735
19.4582
20.6670
19.8246
16.4810];
Havg = [75.7105
65.0892
40.7025
45.5119
47.9225
62.8814
48.1127
62.1248
73.0119
60.4168];
Pavg = [13.0921
13.7083
13.4703
13.7500
13.7023
10.6311
13.5000
12.6250
13.7083
12.9286];
How do I represent these matrices by three dimension plot?
The challenge is that the 3-D surface plotting functions (mesh, surf, etc.) are looking for a 2-D matrix of z values. So to use them you need to construct such a matrix from the data.
Currently the data is sea of points in 3-D space, so, you have to map these points to a surface. A simple approach to this is to divide up the X-Y (temperature-humidity) plane into bins and then take the average of all of the Z (power) data. Here is some sample code for this that uses accumarray() to compute the averages for each bin:
% Specify bin sizes
Tbin = 3;
Hbin = 20;
% Create binned average array
% First create a two column array of bin indexes to use as subscripts
subs = [round(Havg/Hbin)+1, round(Tavg/Tbin)+1];
% Now create the Z (power) estimate as the average value in each bin
Pest = accumarray(subs,Pavg,[],#mean);
% And the corresponding X (temp) & Y (humidity) vectors
Tval = Tbin/2:Tbin:size(Pest,2)*Tbin;
Hval = Hbin/2:Hbin:size(Pest,1)*Hbin;
% And create the plot
figure(1)
surf(Tval, Hval, Pest)
xlabel('Temperature')
ylabel('Humidity')
zlabel('Power')
title('Simple binned average')
xlim([14 24])
ylim([40 80])
The graph is a bit coarse (can't post image yet, since I am new) because we only have a few data points. We can enhance the visualization by removing any empty bins by setting their value to NaN. Also the binning approach hides any variation in the Z (power) data so we can also overlay the orgional point cloud using plot3 without drawing connecting lines. (Again no image b/c I am new)
Additional code for the final plot:
%% Expanded Plot
% Remove zeros (useful with enough valid data)
%Pest(Pest == 0) = NaN;
% First the original points
figure(2)
plot3(Tavg, Havg, Pavg, '.')
hold on
% And now our estimate
% The use of 'FaceColor' 'Interp' uses colors that "bleed" down the face
% rather than only coloring the faces away from the origin
surfc(Tval, Hval, Pest, 'FaceColor', 'Interp')
% Make this plot semi-transparent to see the original dots anb back side
alpha(0.5)
xlabel('Temperature')
ylabel('Humidity')
zlabel('Power')
grid on
title('Nicer binned average')
xlim([14 24])
ylim([40 80])
I think you're asking for a surface fit for your data. The Curve Fitting Toolbox handles this nicely:
% Fit model to data.
ft = fittype( 'poly11' );
fitresult = fit( [Tavg, Havg], Pavg, ft);
% Plot fit with data.
plot( fitresult, [xData, yData], zData );
legend( 'fit 1', 'Pavg vs. Tavg, Havg', 'Location', 'NorthEast' );
xlabel( 'Tavg' );
ylabel( 'Havg' );
zlabel( 'Pavg' );
grid on
If you don't have the Curve Fitting Toolbox, you can use the backslash operator:
% Find the coefficients.
const = ones(size(Tavg));
coeff = [Tavg Havg const] \ Pavg;
% Plot the original data points
clf
plot3(Tavg,Havg,Pavg,'r.','MarkerSize',20);
hold on
% Plot the surface.
[xx, yy] = meshgrid( ...
linspace(min(Tavg),max(Tavg)) , ...
linspace(min(Havg),max(Havg)) );
zz = coeff(1) * xx + coeff(2) * yy + coeff(3);
surf(xx,yy,zz)
title(sprintf('z=(%f)*x+(%f)*y+(%f)',coeff))
grid on
axis tight
Both of these fit a linear polynomial surface, i.e. a plane, but you'll probably want to use something more complicated. Both of these techniques can be adapted to this situation. There's more information on this subject at mathworks.com: How can I determine the equation of the best-fit line, plane, or N-D surface using MATLAB?.
You might want to look at Delaunay triangulation:
tri = delaunay(Tavg, Havg);
trisurf(tri, Tavg, Havg, Pavg);
Using your example data, this code generates an interesting 'surface'. But I believe this is another way of doing what you want.
You might also try the GridFit tool by John D'Errico from MATLAB Central. This tool produces a surface similar to interpolating between the data points (as is done by MATLAB's griddata) but with cleaner results because it smooths the resulting surface. Conceptually multiple datapoints for nearby or overlapping X,Y coordinates are averaged to produce a smooth result rather than noisy "ripples." The tool also allows for some extrapolation beyond the data points. Here is a code example (assuming the GridFit Tool has already been installed):
%Establish points for surface
num_points = 20;
Tval = linspace(min(Tavg),max(Tavg),num_points);
Hval = linspace(min(Havg),max(Havg),num_points);
%Do the fancy fitting with smoothing
Pest = gridfit(Tavg, Havg, Pavg, Tval, Hval);
%Plot results
figure(5)
surfc(XI,YI,Pest, 'FaceColor', 'Interp')
To produce an even nicer plot, you can add labels, some transparancy and overlay the original points:
alpha(0.5)
hold on
plot3(Tavg,Havg,Pavg,'.')
xlabel('Temperature')
ylabel('Humidity')
zlabel('Power')
grid on
title('GridFit')
PS: #upperBound: Thanks for the Delaunay triangulation tip. That seems like the way to go if you want to go through each of the points. I am a newbie so can't comment yet.
Below is your solution:
Save/write the Myplot3D function
function [x,y,V]=Myplot3D(X,Y,Z)
x=linspace(X(1),X(end),100);
y=linspace(Y(1),Y(end),100);
[Xt,Yt]=meshgrid(x,y);
V=griddata(X,Y,Z,Xt,Yt);
Call the following from your command line (or script)
[Tavg_new,Pavg_new,V]=Myplot3D(Tavg,Pavg,Havg);
surf(Tavg_new,Pavg_new,V)
colormap jet;
xlabel('Temperature')
ylabel('Power/Pressure')
zlabel('Humidity')