Power function fitting graph: problem with tiledlayout

3 views (last 30 days)
Hello,
I have used the curve fitting tool to fit 3 different sets of data. So I proceeded to make a graph for each of the three sets of data as follows:
C1=[5e-3 2e-4 5e-5 1.25e-5]';
C2=[5e-3 2e-4 5e-5 1.25e-5 3e-6]';
l3070=[1703.125 37875 68893.75 69006.25]';
l7030=[22915.625 49525 42953.125 101265.625 156909.375]';
l8515=[26353.125 36665.625 79937.5 94287.5 89846.875]';
%%
[fit7030,data7030] = fit(C2,l7030,"power2");
figure(2)=plot(fit7030,'k-');
set(figure(2),'lineWidth',3);
hold on
plot(C2,l7030,'r*',MarkerSize=10);
legend('Location', 'northeast','FontSize',16,'NumColumns',1);
legend("Experimental Data","Power Fitting");
ylim([0 160000]);
xlim([0 0.005]);
%export as 600 dpi
filename = 'cf7030.png';
resolution = 600;
set(gcf, 'PaperUnits', 'inches', 'PaperPosition', [0 0 10 8]);
print(gcf, filename, '-dpng', ['-r', num2str(resolution)]);
hold off
%%
[fit8515,data8515]=fit(C2,l8515,"power2");
figure(3)=plot(fit8515,'k-');
Warning: Power functions require x to be positive. Nonpositive values are treated as NaN.
set(figure(3),'lineWidth',3)
hold on
plot(C2,l8515,'r*',MarkerSize=10);
legend('Location', 'northeast','FontSize',16,'NumColumns',1);
legend("Experimental Data","Power Fitting");
ylim([0 160000]);
xlim([0 0.005]);
%export as 600 dpi
filename = 'cf8515.png';
resolution = 600;
set(gcf, 'PaperUnits', 'inches', 'PaperPosition', [0 0 10 8]);
print(gcf, filename, '-dpng', ['-r', num2str(resolution)]);
hold off
%%
[fit3070,data3070]=fit(C1,l3070,"power2");
figure(4)=plot(fit3070,'k-');
Warning: Power functions require x to be positive. Nonpositive values are treated as NaN.
set(figure(4),'lineWidth',3);
hold on
plot(C1,l3070,'r*',MarkerSize=10);
legend('Location', 'northeast','FontSize',16,'NumColumns',1);
legend("Experimental Data","Power Fitting");
ax = gca;
ax.FontSize = 20;
ylim([0 160000]);
xlim([0 0.005]);
%export as 600 dpi
filename = 'cf3070.png';
resolution = 600;
set(gcf, 'PaperUnits', 'inches', 'PaperPosition', [0 0 10 8]);
print(gcf, filename, '-dpng', ['-r', num2str(resolution)]);
hold off
As you can see, I get a fitted curve that approximates good enough for my needs. It's clear that I get an error for each of the graph, saying that non positive values are treated as NaNs. Although, I cannot seem to find any non positive values in my input data.
The problem arises when I try to make a tiled layout, and display these three graphs in a row. I have tried this:
x=10;
C1=[5e-3 2e-4 5e-5 1.25e-5]';
C2=[5e-3 2e-4 5e-5 1.25e-5 3e-6]';
l3070=[1703.125 37875 68893.75 69006.25]';
l7030=[22915.625 49525 42953.125 101265.625 156909.375]';
l8515=[26353.125 36665.625 79937.5 94287.5 89846.875]';
%%
t=tiledlayout(1,3);
[fit7030,data7030] = fit(C2,l7030,"power2");
nexttile
figure(2)=plot(fit7030,'k-');
Warning: Power functions require x to be positive. Nonpositive values are treated as NaN.
set(figure(2),'lineWidth',3);
hold on
plot(C2,l7030,'r*',MarkerSize=10);
legend('Location', 'northeast','FontSize',x-2,'NumColumns',1);
legend("Experimental Data","Line Fitting");
ax = gca;
ax.FontSize = x-2;
ylim([0 160000]);
xlim([0 0.005]);
%%
[fit8515,data8515]=fit(C2,l8515,"power2");
nexttile
figure(3)=plot(fit8515,'k-');
Warning: Power functions require x to be positive. Nonpositive values are treated as NaN.
set(figure(3),'lineWidth',3)
hold on
plot(C2,l8515,'r*',MarkerSize=10);
legend('Location', 'northeast','FontSize',x-2,'NumColumns',1);
legend("Experimental Data","Line Fitting");
ax = gca;
ax.FontSize = x-2;
ylim([0 160000]);
xlim([0 0.005]);
hold off
%%
[fit3070,data3070]=fit(C1,l3070,"power2");
nexttile
figure(4)=plot(fit3070,'k-');
Warning: Power functions require x to be positive. Nonpositive values are treated as NaN.
set(figure(4),'lineWidth',3);
hold on
plot(C1,l3070,'r*',MarkerSize=10);
legend('Location', 'northeast','FontSize',x-2,'NumColumns',1);
legend("Experimental Data","Line Fitting");
ax = gca;
ax.FontSize = x-2;
ylim([0 160000]);
xlim([0 0.005]);
hold off
%export as 600 dpi
filename = 'tiled.png';
resolution = 600;
set(gcf, 'PaperUnits', 'inches', 'PaperPosition', [0 0 14 8]);
print(gcf, filename, '-dpng', ['-r', num2str(resolution)]);
As you can see, leaving the huge discrepancies in the legend size (my bad), the real problem is that the curves when using tiledlayout are cut between 0 and 1 on the x-axis. Any idea why this is happening?
Thank you in advance.
Stefano

Accepted Answer

Voss
Voss on 4 Apr 2024
Edited: Voss on 4 Apr 2024
format long g
C1=[5e-3 2e-4 5e-5 1.25e-5]';
C2=[5e-3 2e-4 5e-5 1.25e-5 3e-6]';
l3070=[1703.125 37875 68893.75 69006.25]';
l7030=[22915.625 49525 42953.125 101265.625 156909.375]';
l8515=[26353.125 36665.625 79937.5 94287.5 89846.875]';
"the real problem is that the curves when using tiledlayout are cut between 0 and 1 on the x-axis. Any idea why this is happening?"
The documentation for cfit plot says:
"plot(cfit) plots the curve given in the cfit object cfit over the range of the current axes (gca). If no current axes exist, the function plots the curve over the range of the data used to create cfit."
That statement explains why the behavior when plotting not in a tiledlayout is different than when in a tiledlayout: When not in a tiledlayout, there is no current axes (at least, none is created in your code), so the range of C2 (3e-6 to 5e-3) is used; when in a tiledlayout there is a current axes (because nexttile creates it), so the range of that axes (0 to 1) is used.
You can inspect the XData of the plotted line in each case to see the difference:
First, the no-tiledlayout case:
figure()
[fit7030,data7030] = fit(C2,l7030,"power2");
fig(2)=plot(fit7030,'k-');
xlim([0 0.005]);
get(fig(2),'XData').'
ans = 1001x1
1.0e+00 * 3e-06 7.997e-06 1.2994e-05 1.7991e-05 2.2988e-05 2.7985e-05 3.2982e-05 3.7979e-05 4.2976e-05 4.7973e-05
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Now the tiledlayout case:
figure()
t=tiledlayout(1,3);
[fit7030,data7030] = fit(C2,l7030,"power2");
nexttile
fig(2)=plot(fit7030,'k-');
Warning: Power functions require x to be positive. Nonpositive values are treated as NaN.
xlim([0 0.005]);
get(fig(2),'XData').'
ans = 1001x1
0 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Note that the XData of the line in the tiledlayout has a zero element, which explains the warning about x is required to be positive. The warning also explains why the line is cut off below x=0.001: the y-coordinate of the point at x=0 is NaN, and NaNs don't render on plots.
get(fig(2),'YData').'
ans = 1001x1
1.0e+00 * NaN 29257.2346635438 26512.0907460756 25260.8598593661 24501.6504156697 23976.7624861268 23585.2958954993 23278.4398407047 23029.2794057556 22821.5773265359
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
So what to do about it? One way around the problem is to set the xlim of the tiledlayout axes before plotting:
figure()
t=tiledlayout(1,3);
[fit7030,data7030] = fit(C2,l7030,"power2");
nexttile
xlim([min(C2) max(C2)]) % setting xlim to range of C2
fig(2)=plot(fit7030,'k-');
xlim([0 0.005])
Now it looks like the no-tiledlayout case, and you can confirm that it is the same by checking the XData of the plotted line:
get(fig(2),'XData').'
ans = 1001x1
1.0e+00 * 3e-06 7.997e-06 1.2994e-05 1.7991e-05 2.2988e-05 2.7985e-05 3.2982e-05 3.7979e-05 4.2976e-05 4.7973e-05
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
  2 Comments
Stefano Russo
Stefano Russo on 4 Apr 2024
I guess it's "another day, another question already answered in the MATLAB documentation" type of question for you. One day I'll be mature enough to check that first. :) Thank you so much Voss.
Voss
Voss on 4 Apr 2024
You're welcome!
To be honest, I had to step through the code to see where the difference happens and only after that did I look into the documentation for cfit plot and found the explanation. It wasn't obvious to me at all at first.

Sign in to comment.

More Answers (1)

Emma Farnan
Emma Farnan on 4 Apr 2024
When you plot a curve fit, it generates a line with 1001 x-points. When you let it autogenerate these x values in the tiledlayout, it chose to make those points from 0 to 1 to match the default axes generated by nexttile. That meant the first point > 0 was 0.001.
You should be able to get around this by making your own linspace of points and evaluating the curve at those points.
C2=[5e-3 2e-4 5e-5 1.25e-5 3e-6]';
l7030=[22915.625 49525 42953.125 101265.625 156909.375]';
[fit7030,data7030] = fit(C2,l7030,"power2");
xfit = linspace(0,0.005,2001); % Generate the x-points to evaluate the fit at
xfit = xfit(2:end); % Cut off the 0 to avoid the warning about power functions and negative values
yfit = fit7030(xfit); % Get the corresponding y values.
% Repeat for other fits
% Use this as the curve fit plot in your tiled layout plots
tiledlayout(1,3);
nexttile;
plot(xfit,yfit,'k-',C2,l7030,'r*',MarkerSize=10)
% Adjust axis as needed and then repeat for other tiles

Categories

Find more on Fit Postprocessing in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!