MATLAB Answers

5

How can I save a figure within app designer?

Asked by J. Webster on 27 Apr 2016
Latest activity Answered by Adam Danz
on 24 Mar 2019
I've developed an application using the new App Designer. I'd like to have users be able to click a button and save a figure to a .fig file, or some other image format.
function ButtonSaveFigureButtonPushed(app)
newfigure = figure;
copyobj(app.UIAxesAP, newfigure);
hgsave(newfigure, 'testFIgure.fig');
end
But that gave me the error...
Error using matlab.ui.control.UIAxes/copyElement (line 1219)
Functionality not supported with UIAxes. For more information, see Graphics Support in App Designer.
What's the best way to go about this?

  1 Comment

Based on the number of recent views this is still an open issue. I have the same problem/question using R2017a.

Sign in to comment.

11 Answers

Answer by David
on 4 Apr 2018
Edited by David
on 4 Apr 2018
 Accepted Answer

I spent some time on this for my own purposes. The trick is to save the individual values from the figure into local variables to be used in a figure as follows:
h = figure;
h.Visible = 'off';
x = UIAxes.XAxis.Parent.Children.XData;
y = UIAxes.XAxis.Parent.Children.YData;
plot(x,y)
lgndName1 = UIAxes.Legend.String{1};
lgd = legend(lgndName1);
lgd.Box = UIAxes.Legend.Box;
lgd.Location = UIAxes.Legend.Location;
h.CurrentAxes.YLabel.String = UIAxes.YLabel.String;
h.CurrentAxes.YLabel.FontSize = UIAxes.YLabel.FontSize;
h.CurrentAxes.XLabel.String = UIAxes.XLabel.String;
h.CurrentAxes.XLabel.FontSize = UIAxes.XLabel.FontSize;
h.CurrentAxes.Title.String = UIAxes.Title.String;
h.CurrentAxes.Title.FontSize = UIAxes.Title.FontSize;
h.CurrentAxes.XLim = [0 max(x)];
h.CurrentAxes.XLim = [0 max(y)+1];
saveas(h,SaveName,'jpg')
savefig(h,SaveName)
delete(h)
Notice I have the visibility off, because I don't want the user to see this going in the background.
Note: You will have to change "UIAxes" to whatever you've named your UI figure
You could also add more properties, but you will have to go into your figure and find the object name to use.
I hope this helps.
Edit: I should also mention that to get this to work as function, I had to make it a call function in a separate .m file. I made a function SaveFigures(UIAxes, SaveName) that is called when ButtonSaveFigureButtonPushed. I have multiple possible plots, which is why I allow the UIAxes to vary. (I use a switch case to make sure I save the correct plot.)

  6 Comments

David, would it be possible to see more of this code? I am close to getting my app to do the same thing (I believe) that you wrote yours to do, but am missing something fairly minor.
Eric, it might be easier to see your code. (Sorry for the delay, I did not get an email update on your comment.)
Just a quick remark on otherwise very useful reply:
h.CurrentAxes.XLim = [0 max(y)+1];
Shouldn't that be
h.CurrentAxes.YLim = [0 max(y)+1];

Sign in to comment.


Answer by Joost
on 2 Oct 2018
Edited by Joost
on 3 Oct 2018

Inspired by David's answer , I came up with this solution which I believe is more generic. My UIAxes contains a lot of graphics objects (mostly patch objects) which are all copied to a temporary figure and then saved. I took over some UIAxes properties (axes limits and data aspect ratio), but you can add any other property you need there. Specify fileName yourself. I put a button called 'Snapshot' in the app with a callback that contains the code below. Matlab R2018a was used.
% Create a temporary figure with axes.
fig = figure;
fig.Visible = 'off';
figAxes = axes(fig);
% Copy all UIAxes children, take over axes limits and aspect ratio.
allChildren = app.UIAxes.XAxis.Parent.Children;
copyobj(allChildren, figAxes)
figAxes.XLim = app.UIAxes.XLim;
figAxes.YLim = app.UIAxes.YLim;
figAxes.ZLim = app.UIAxes.ZLim;
figAxes.DataAspectRatio = app.UIAxes.DataAspectRatio;
% Save as png and fig files.
saveas(fig, fileName, 'png');
savefig(fig, fileName);
% Delete the temporary figure.
delete(fig);

  2 Comments

Hi Joost,
thanks for sharing your code. If i understand you right, it addresses my problem of multiple graphical objects like two plots in the same UIAxes.
So i copied your Code and choose the 'add' option on 'NextPlot' on the chosen UIAxes in the 'Multiple Plots' Tab within the poperties (I don't know, if it makes a difference, though).
After running it, it came out to be like the result of David's Code, as you can see in the pictures.
In the programming, i used the yyaxis (left/right) command for plotting those two data with their own axis and it clearly just took the last data (yyaxis right) to be saved in the .png.
Can you help me?
Hello Frederic,
I looked into it but unfortunately I cannot figure out the data structure hierarchy in case of multiple y axes using yyaxis. I hope someone else can help you.
Best regards, Joost

Sign in to comment.


Answer by Guilherme Salgado Braga on 24 Feb 2018

According to the R2017b documentation on: https://www.mathworks.com/help/matlab/creating_guis/graphics-support-in-app-designer.html
Functions saveas and savefig are not yet supported.

  0 Comments

Sign in to comment.


Answer by Dharmendra Sharma on 15 Jun 2018
Edited by Dharmendra Sharma on 15 Jun 2018

This is the one potential solution which works for me. First, plot the figure/figures in normal way without using uifigure for example see code below. Visibility is on in the following example-
figure('Name','Acc','NumberTitle','off','units','normalized','outerposition',[0 0 1 1])
Then create a separate matlab function file (and call that matlab function from matlab ui). the function may include code to extract figure properties and save the figures as png file. The following link explains the saving all the figures and the code as well-- see the link--
It just need some modifications and I included these in follwoing code-
function [] = handleFigures()
result = isfolder('figures');
if result==0
mkdir figures;
else
delete('figures/*.*')
end
FolderName = 'figures'; % Your destination folder
FigList = findobj(allchild(0), 'flat', 'Type', 'figure');
for iFig = 1:length(FigList)-1
FigHandle = FigList(iFig);
FigName = get(FigHandle, 'Name');
saveas(FigHandle, fullfile(FolderName, [FigName, '.png']))
end
disp('closing figures');
close all
end

  0 Comments

Sign in to comment.


Answer by J. Webster on 28 Apr 2016

anybody??

  1 Comment

did u get a solution yet? I was looking to do the same

Sign in to comment.


Answer by Tobias Daßler on 20 Dec 2017

I used a workaround:
saveas(gca,uiputfile({'*.png'; '*.fig'; '*.jpg'}));
close Plot;
Maybe you could adapt this for your problem.

  2 Comments

Was this used in App Designer?
Functionality not supported with figures created with the uifigure function. So, this doesn't work with axes created in app designer.

Sign in to comment.


Answer by Craig Pearson on 8 Jan 2018

I'm having a similar problem and would like a solution. I was trying to use the print function to copy a figure to the clipboard.
Annoyingly, if I use debugging mode, once the figure is created I can quit debugging mode then use
print -dmeta
from the command window and it proceeds fine - I can then paste this into Excel from the command line (which is what I'm aiming to do from within the app).
Why can this not be achieved from within the App?

  0 Comments

Sign in to comment.


Answer by Blanca Larraga on 4 Jun 2018

Is there a solution for saving the axes plot in a .jpeg format or not yet? I am trying to insert what I got un an axes figure within a report automatically in app designer but I don't manage to do so. Thanks.

  0 Comments

Sign in to comment.


Answer by Jyothi Karri on 20 Jul 2018

I have the same issue. Cannot export a UIAxes from gui created from app designer. copyobj did not work either.

  1 Comment

I have the same issue. It would help if there would be a nice option just to map an UIAxes element into a normal (pop-up) figure. Then the figure could be saved with the common tools.

Sign in to comment.


Answer by Paramjeet Panwar on 15 Oct 2018

My current workaround is identifying the pixel position of the UIFigure and UIAxes on the screen and taking a snapshot using Java libraries.
Refer to these links -
2 Using Java library for screenshot - this link

  0 Comments

Sign in to comment.


Answer by Adam Danz
on 24 Mar 2019

Here's a more general solution that 1) copies all objects onto new external axes and then 2) copies most of the UIAxes properties on to the new axes. This last step is what's missing from the solutions proposed to date.
Some axes properties are read-only so we can't copy those over to the new axes. Also, there are some axes properties that you don't want to copy over such as parent, children, X/Y/ZAxis, which will cause errors. In addition to those, you'll see in the code below where I added the "Position" and "OuterPosition" properties to the list of properties not to copy. In your app, the axes are probably small and if you want your new axes to also be the same size, you could remove the two positoin properties from the 'badFields' list.
% Create new figure and new axes
figure
axNew = axes;
% Copy all opjects from UIAxes to new axis
copyobj(app.UIAxes.Children, axNew)
% Save all parameters of the UIAxes
uiAxParams = get(app.UIAxes);
uiAxParamNames = fieldnames(uiAxParams);
% Get list of editable params in new axis
editableParams = fieldnames(set(axNew));
% Remove the UIAxes params that aren't editable in the new axes (add others you don't want)
badFields = uiAxParamNames(~ismember(uiAxParamNames, editableParams));
badFields = [badFields; 'Parent'; 'Children'; 'XAxis'; 'YAxis'; 'ZAxis';'Position';'OuterPosition'];
uiAxGoodParams = rmfield(uiAxParams,badFields);
% set editable params on new axes
set(axNew, uiAxGoodParams)
For trouble shooting, or to loop through each property rather then setting them all at once, replace the last line of the code above with this for-loop below which indicates the property being edited in the command window.
% Set new axis params
allf = fieldnames(uiAxGoodParams);
for i = 1:length(allf)
fprintf('Property #%d: %s\n', i, allf{i});
set(axNew, allf{i}, uiAxGoodParams.(allf{i}))
end
One alternative worth mentioning: Instead of your app hosting the axes, you could program your app to plot the data onto an external figure and then you wouldn't have this problem.

  0 Comments

Sign in to comment.