Can sfit objects be plotted to specific axis in GUI (not a figure window)?

Hi,
I have been given a code that fits a surface to a 3D data set. My task is to add it to an existing GUI, that I have developed using App Designer in Matlab R2020a.
X=1:10; %Made-up data
Y=1:10;
Z=1:10;
n=(1:length(Z));
Ztop=(max(Z)+10).*ones(1,length(n));
plot3(app.Map, X(n),Y(n),Ztop,'.k','markersize',12); %plot datapoints
hold(app.Map, 'on')
options = fitoptions('Method','BiharmonicInterpolant');
[sf,gof] = fit([X', Y'],Z','biharmonicinterp',options); %create sfit obj
axis(app.Map,'equal')
caxis(app.Map,'auto')
%caxis([0 maxV]) ;
colormap(app.Map);
plot(app.Map, sf); %plot fitted surface - THAT'S THE ISSUE, IT WORKS UNTIL THIS LINE!
%shading interp
colorbar(app.Map);
%view(2)
hold(app.Map, 'off')
The code works just fine in a figure window but, when I try to display the output to a graphic axis (app.Map) integrated in the GUI, I get the following:
Error using plot
Data must be numeric, datetime, duration or an array convertible to double.
I read the help for plot() and it seems that plot(ax,_) is the right format. However, I also tried another common format, just in case:
H = plot(sf, 'Parent', app.Map )
This returns a long list of errors. At this point, I think I need some guidance.
Thank you!
PS: one work-around might be plotting to a figure window, set with visibility 'off'. Then export the result to jpg and display it with imshow inside the GUI. But I would still like to know what I am doing wrong, if possible.

 Accepted Answer

This is the solution:
X=[wL,wIN1,wIN2,wIN3,wIN1,wIN2,wIN3,wR,wL,wIN1,wIN2,wIN3,wR];
Y=[hIN,hB,hB,hB,hIN,hIN,hIN,hIN,hBC,hBC,hBC,hBC,hBC];
Z=[lL,lB1,lB2,lB3,lIN1,lIN2,lIN3,lR,BC1,BC2,BC3,BC4,BC5];
n=(1:length(Z));
Ztop=(max(Z)+10).*ones(1,length(n));
plot3(app.Map, X(n),Y(n),Ztop,'.k','markersize',12)
view(app.Map, 2)
hold(app.Map, 'on')
[x y] = meshgrid([min(X):1:max(X)],[min(Y):1:max(Y)]);
options = fitoptions('Method','BiharmonicInterpolant');
sf = fit([X',Y'],Z','biharmonicinterp',options);
z = sf(x,y);
surf(x,y,z,'Parent', app.Map,'FaceColor','interp', 'EdgeColor','None')
axis(app.Map, 'equal')
caxis(app.Map, 'auto')
app.Map.YLim = [hB hBC];
app.Map.XLim = [wL wR];
view(app.Map, 2)
colormap(app.Map);
colorbar(app.Map);
hold(app.Map, 'off')

More Answers (2)

Giorgio - from Plot cfit or sfit object, the code to plot the sf object would be
plot(sf, 'Parent', app.Map)
. When you try to plot as
plot(app.Map, sf);
then you are calling the 2-D line plot function.

7 Comments

I see.
But I tried that and it returns soooo many errors.
Especially the first warning (Input #2 expected to be a cell array, was double instead) makes no sense to me.
Warning: The following error was caught while executing 'curvefit.gui.FunctionSurface' class destructor:
Error using cellfun
Input #2 expected to be a cell array, was double instead.
Error in curvefit.gui.FunctionSurface/delete (line 160)
cellfun( @delete, obj.SurfaceListeners );
Error in curvefit.gui.FunctionSurface (line 78)
narginchk( 1, 1 );
Error in sfit/plot>iPlotSurface (line 96)
hFS = curvefit.gui.FunctionSurface( hParent );
Error in sfit/plot (line 52)
h1 = iPlotSurface( hParent, obj );
Error using event.proplistener
While adding a PostSet listener, property 'XLim' in class 'matlab.ui.control.UIAxes' is not defined to be SetObservable.
Error in curvefit.proplistener>iCreateEventListener (line 43)
listener = event.proplistener( Source, property, 'PostSet', Callback );
Error in makeListener (line 42)
listener = Factory.Matlab( Source, Event, Callback );
Error in curvefit.proplistener (line 25)
listener = makeListener(Factory, Source, PropName, Callback);
Error in curvefit.createListener>iCreateListener (line 39)
L = curvefit.proplistener(src, eventname, callback);
Error in curvefit.createListener (line 29)
L = iCreateListener(src, event, callback);
Error in curvefit.ListenerTarget/createListener (line 100)
L = curvefit.createListener(src, event, callback);
Error in curvefit.gui.FunctionSurface/createAxesLimitListeners (line 285)
obj.createListener( obj.Parent, 'XLim', @obj.redraw )
Error in curvefit.gui.FunctionSurface (line 104)
createAxesLimitListeners( obj );
Error in sfit/plot>iPlotSurface (line 96)
hFS = curvefit.gui.FunctionSurface( hParent );
Error in sfit/plot (line 52)
h1 = iPlotSurface( hParent, obj );
Which version of MATLAB are you using? What does it's documentation say about using plot for fit objects?
R2020a
It's the same link you provided, which is also where I got the idea of trying:
H = plot(sf, 'Parent', app.Map )
It isn't clear to me why this wouldn't work. Perhaps try creating an example outside of your GUI. You can take any of the examples from fit and then try to plot as
plot(sf, 'Parent', gca )
Does that work or do you see the same errors?
I have tried several variation but the errors are still there.
Here are the main two.
load franke
sf = fit([x, y],z,'poly23')
plot(sf, 'Parent', gca)
It runs but it isn't shown anywhere, unless I create a figure window beforehand.
I have tried to create a simple GUI with nothing other than a button and a UIAxes.
load franke
sf = fit([x, y],z,'poly23')
plot(sf, 'Parent', app.UIAxes)
It retuns the same long list of errors as before.
This is quite puzzling
Gorigio - it may be that the UIAxes is not compatible with the fit object (see this older post https://www.mathworks.com/matlabcentral/answers/274880-app-designer-uiaxes-doesn-t-show-results-of-fitting-curve). It suggests that you need to do something similar to
load census;
f=fit(cdate,pop,'poly2');
x = 1700:2000;
y = feval(f,x);
plot(app.UIAxes,x,y)
but I'm not sure if that is valid for your use case.
Geoff, thanks for all the help.
I actually had found the same post and I was already working on a similar solution.
In the end, that's what worked for me:
X=[wL,wIN1,wIN2,wIN3,wIN1,wIN2,wIN3,wR,wL,wIN1,wIN2,wIN3,wR];
Y=[hIN,hB,hB,hB,hIN,hIN,hIN,hIN,hBC,hBC,hBC,hBC,hBC];
Z=[lL,lB1,lB2,lB3,lIN1,lIN2,lIN3,lR,BC1,BC2,BC3,BC4,BC5];
n=(1:length(Z));
Ztop=(max(Z)+10).*ones(1,length(n));
plot3(app.Map, X(n),Y(n),Ztop,'.k','markersize',12)
view(app.Map, 2)
hold(app.Map, 'on')
[x y] = meshgrid([min(X):1:max(X)],[min(Y):1:max(Y)]);
options = fitoptions('Method','BiharmonicInterpolant');
sf = fit([X',Y'],Z','biharmonicinterp',options);
z = sf(x,y);
surf(x,y,z,'Parent', app.Map,'FaceColor','interp', 'EdgeColor','None')
axis(app.Map, 'equal')
caxis(app.Map, 'auto')
app.Map.YLim = [hB hBC];
app.Map.XLim = [wL wR];
view(app.Map, 2)
colormap(app.Map);
colorbar(app.Map);
hold(app.Map, 'off')

Sign in to comment.

Starting in MATLAB R2023b, provide the axis handle as the first input to plot the fit line in your app's axes.
plot(app.UIAxes, fitline, a, b)
For a workaround prior to R2023b, see this answer.

Categories

Find more on Graphics Performance in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!