Copy figure AND legend in matlab gui - matlab

I got a GUI showing several plots. now i'd like to get one of these... "main_plot" for example (the entire figure with title, axes-descriptions AND the legend) and export it to a file. this is what i got so far:
function main_plot_exp_Callback(hObject, eventdata, handles)
f_tmp = figure('visible','off');
set(f_tmp,'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
copyobj(handles.main_plot,f_tmp);
set(gca,'Position',[0.16125 0.09 0.684375 0.84],...
'GridLineStyle','--');
print(f_tmp, '-djpeg', 'name', '-r300');
close(f_tmp);
generally works like a charm EXCEPT for the damn legend, which appears to get lost in the process. any suggestions or ideas? thanks in advance!
(side question: is there anything like "gcf" only for a CERTAIN and not the current figure?)

I tried your procedure and faced no problem (my matlab: 8.2.0.701 (R2013b))
The best you could do as follow
hSome = findobj(handles.main_plot);
get(hSome,'Tag')
Results should yield one "legend" string. If not, replace findobj with findall. Otherwise your legend handle is stocked somewhere else and you need to look deeper into your GUI.

I had the same problem with the legend being lost in the process. The best I could do to overcome this was to re-create the legend in the new figure before saving it. Here an example of the code I used:
% find the legend(s) - I suppose in the following that there is only one legend in the GUI
L1 = findobj(handles.figure1,'tag','legend'); % where handles.figure1 is the GUI figure handle
% retrieve the legend strings and location
legendstr=get(L1,'String');
legendloc=get(L1,'Location');
% handle to the GUI axes to be saved
ax = handles.axes1;
% create a new figure
fig = figure('Units','centimeters','outerposition',[2 2 17 17]);
% copy the GUI axes into the new figure
new_axes = copyobj(ax, fig);
set(new_axes,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
% recreate the legend
legend(new_axes,legendstr,'Location',legendloc);
%save the files in .fig and .format files (.format = .jpg, .png, ...)
hgsave(fig,[pname '\' filename]);
hgexport(fig, fname, hgexport('factorystyle'),'Format', format)
close(fig);

Assuming the axes is called main_plot, I found that the legend is referenced by:
legend(handles.main_plot)
So you would need to copy the legend with its parent axes (as a vector input) to the new figure:
copyobj([handles.main_plot legend(handles.main_plot],f_tmp);

Related

Two saved figures, want them to show in a single graph in MATLAB

Let's say I have two figures stored in separate files A.fig and B.fig which contain two separate plots. Is there a way to load A.fig and then do something like hold on and then load B.fig in the figure created for A.fig so that I have both plots in the same axes?
I think the question is not really a duplicate of this one. The OP does not ask for a way to extract the data but for a way to combine the two stored figures. Admittedly, he could extract the data and plot it again. But there is a more elegant solution...
The actual plots are children of axes which is a child of figure. Therefore you can achieve what you want by copying the children of the second axes into the first axes with copyobj. Before that, load the figures with openfig. This method has the advantage to copy different types of 'plots' (line, area, ...).
The code to copy from B.fig to A.fig is as follows and works starting from R2014b:
fig1 = openfig('A');
fig2 = openfig('B', 'invisible');
copyobj(fig2.Children.Children, fig1.Children);
If you have a Matlab version prior to R2014b, you need to use the set and get functions since you cannot use .-notation. More information can be found here. You can either use gca to get the current axes after loading the figure like this:
fig1 = openfig('A');
ax1 = gca;
fig2 = openfig('B', 'invisible');
ax2 = gca;
copyobj(get(ax2,'children'), ax1);
... or get them manually from the figure-handle like this:
fig1 = openfig('A');
fig2 = openfig('B', 'invisible');
copyobj(get(get(fig2,'children'),'children'), get(fig1,'children'));
The following script creates two figures and then applies the above code to combine them.
If you are have Matlab version R2013b or higher, replace hgsave with savefig as suggested in the documentation.
%% create two figure files
x = linspace(0,2*pi,100);
figure; hold on;
plot(x,sin(x),'b');
area(x,0.5*sin(x));
set(gca,'xlim',[0,2*pi]);
hgsave('A');
figure; hold on;
plot(x,cos(x),'r');
area(x,0.5*cos(x),'FaceColor','r');
hgsave('B');
%% clear and close all
clear;
close all;
%% copy process
fig1 = openfig('A');
fig2 = openfig('B', 'invisible');
copyobj(get(get(fig2,'children'),'children'), get(fig1,'children'));
close(fig2);
This gives the following result if manually combined in subplots:

How do I resize a figure window to cover the entire screen on MATLAB 2014 (b) +? [duplicate]

I am creating some figures in MATLAB and automatically save them to files. The problem that by definition the images are small. A good way to solve my problem by hand is to create an image (figure), maximize it, and save to a file.
I am missing this step of automatically maximize a figure.
Any suggestions?
Up till now I only found this:
http://answers.yahoo.com/question/index?qid=20071127135551AAR5JYh
http://www.mathworks.com/matlabcentral/newsreader/view_thread/238699
but none are solving my problem.
This worked for me:
figure('units','normalized','outerposition',[0 0 1 1])
or for current figure:
set(gcf,'units','normalized','outerposition',[0 0 1 1])
I have also used MAXIMIZE function on FileExchange that uses java. This is true maximization.
For an actual Maximize (exactly like clicking the maximize button in the UI of OS X and Windows)
You may try the following which calls a hidden Java handle
figure;
pause(0.00001);
frame_h = get(handle(gcf),'JavaFrame');
set(frame_h,'Maximized',1);
The pause(n) is essential as the above reaches out of the Matlab scape and is situated on a separate Java thread. Set n to any value and check the results. The faster the computer is at the time of execution the smaller n can be.
Full "documentation" can be found here
As of R2018a, figure as well as uifigure objects contain a property called WindowState. This is set to 'normal' by default, but setting it to 'maximized' gives the desired result.
In conclusion:
hFig.WindowState = 'maximized'; % Requires R2018a
Furthermore, as mentioned in Unknown123's comments:
Making figures maximized by default is possible using:
set(groot, 'defaultFigureWindowState', 'maximized');
Maximizing all open figures is possible using:
set(get(groot, 'Children'), 'WindowState', 'maximized');
More information about 'WindowState' as well as other properties controlling figure appearance can be found in this documentation page.
Finally, to address your original problem - if you want to export the contents of figures to images without having to worry about the results being too small - I would highly recommend the export_fig utility.
To maximize the figure, you can mimic the sequence of keys you would actually use:
ALT-SPACE (as indicated here) to access the window menu; and then
X to maximize (this may vary in your system).
To send the keys programmatically, you can use a Java-based procedure similar to this answer, as follows:
h = figure; %// create figure and get handle
plot(1:10); %// do stuff with your figure
figure(h) %// make it the current figure
robot = java.awt.Robot;
robot.keyPress(java.awt.event.KeyEvent.VK_ALT); %// send ALT
robot.keyPress(java.awt.event.KeyEvent.VK_SPACE); %// send SPACE
robot.keyRelease(java.awt.event.KeyEvent.VK_SPACE); %// release SPACE
robot.keyRelease(java.awt.event.KeyEvent.VK_ALT); %// release ALT
robot.keyPress(java.awt.event.KeyEvent.VK_X); %// send X
robot.keyRelease(java.awt.event.KeyEvent.VK_X); %// release X
Voilà! Window maximized!
As it is proposed by an author above, if you want to simulate clicking the "maximize" windows button, you can use the code that follows. The difference with the mentionned answer is that using "drawnow" instead of "pause" seems more correct.
figure;
% do your job here
drawnow;
set(get(handle(gcf),'JavaFrame'),'Maximized',1);
imho maximizing the figure window is not the best way to save a figure as an image in higher resolution.
There are figure properties for printing and saving. Using these properties you can save files in any resolution you want. To save the files you have to use the print function, because you can set an dpi value. So, firstly set the following figure properties:
set(FigureHandle, ...
'PaperPositionMode', 'manual', ...
'PaperUnits', 'inches', ...
'PaperPosition', [0 0 Width Height])
and secondly save the file (for example) as png with 100dpi ('-r100')
print(FigureHandle, Filename, '-dpng', '-r100');
To get a file with 2048x1536px set Width = 2048/100 and Height 1536/100, /100 because you save with 100dpi. If you change the dpi value you also have to change the divisor to the same value.
As you can see there is no need for any extra function from file exchange or java-based procedure. In addition you can choose any desired resolution.
you can try this:
screen_size = get(0, 'ScreenSize');
f1 = figure(1);
set(f1, 'Position', [0 0 screen_size(3) screen_size(4) ] );
%% maximizeFigure
%
% Maximizes the current figure or creates a new figure. maximizeFigure() simply maximizes the
% current or a specific figure
% |h = maximizeFigure();| can be directly used instead of |h = figure();|
%
% *Examples*
%
% * |maximizeFigure(); % maximizes the current figure or creates a new figure|
% * |maximizeFigure('all'); % maximizes all opened figures|
% * |maximizeFigure(hf); % maximizes the figure with the handle hf|
% * |maximizeFigure('new', 'Name', 'My newly created figure', 'Color', [.3 .3 .3]);|
% * |hf = maximizeFigure(...); % returns the (i.e. new) figure handle as an output|
%
% *Acknowledgements*
%
% * Big thanks goes out to Yair Altman from http://www.undocumentedmatlab.com/
%
% *See Also*
%
% * |figure()|
% * |gcf()|
%
% *Authors*
%
% * Daniel Kellner, medPhoton GmbH, Salzburg, Austria, 2015-2017
%%
function varargout = maximizeFigure(varargin)
warning('off', 'MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame')
% Check input variables
if isempty(varargin)
hf = gcf; % use current figure
elseif strcmp(varargin{1}, 'new')
hf = figure(varargin{2:end});
elseif strcmp(varargin{1}, 'all')
hf = findobj('Type', 'figure');
elseif ~isa(varargin{1}, 'char') && ishandle(varargin{1}) &&...
strcmp(get(varargin{1}, 'Type'), 'figure')
hf = varargin{1};
else
error('maximizeFigure:InvalidHandle', 'Failed to find a valid figure handle!')
end
for cHandle = 1:length(hf)
% Skip invalid handles and plotbrowser handles
if ~ishandle(cHandle) || strcmp(get(hf, 'WindowStyle'), 'docked')
continue
end
% Carry the current resize property and set (temporarily) to 'on'
oldResizeStatus = get(hf(cHandle), 'Resize');
set(hf(cHandle), 'Resize', 'on');
% Usage of the undocumented 'JavaFrame' property as described at:
% http://undocumentedmatlab.com/blog/minimize-maximize-figure-window/
jFrame = get(handle(hf(cHandle)), 'JavaFrame');
% Due to an Event Dispatch thread, the pause is neccessary as described at:
% http://undocumentedmatlab.com/blog/matlab-and-the-event-dispatch-thread-edt/
pause(0.05)
% Don't maximize if the window is docked (e.g. for plottools)
if strcmp(get(cHandle, 'WindowStyle'), 'docked')
continue
end
% Don't maximize if the figure is already maximized
if jFrame.isMaximized
continue
end
% Unfortunately, if it is invisible, it can't be maximized with the java framework, because a
% null pointer exception is raised (java.lang.NullPointerException). Instead, we maximize it the
% straight way so that we do not end up in small sized plot exports.
if strcmp(get(hf, 'Visible'), 'off')
set(hf, 'Units', 'normalized', 'OuterPosition', [0 0 1 1])
continue
end
jFrame.setMaximized(true);
% If 'Resize' will be reactivated, MATLAB moves the figure slightly over the screen borders.
if strcmp(oldResizeStatus, 'off')
pause(0.05)
set(hf, 'Resize', oldResizeStatus)
end
end
if nargout
varargout{1} = hf;
end
This is the shortest form
figure('Position',get(0,'ScreenSize'))
I recommend the set command to change MenuBar and Toolbar properties of your figure. The set command is more versatile because it works for older and newer versions of Matlab.
fig = figure(1);
set(fig, 'MenuBar', 'none');
set(fig, 'ToolBar', 'none');
Now you can use set again to make your figure full screen.
set(fig, 'Position', get(0,'Screensize'));
Note that if you make the figure full screen first, and then remove the MenuBar and Toolbar, the figure will not be full screen, so make sure to run these in the correct order.

Match legend to axes objects

Context:
I have a (programmatic) GUI which contains several axes objects inside some uipanel parenting structure. Some of these axes have legend objects associated, some don't.
I want to include a button in my GUI which copies the currently visible plot into a new figure including its legend if it has one.
I know how to get the handles to the currently visible uipanel and all axes objects inside it. I also know how to tell the axes apart from the legends.
Question:
How can I match the legends to the axes?
For example, in one case my GUI shows 2 axes with some plots, each of which has its own legend. When I click the 'export' button, I want 2 new figures to be created, each containing one axes with its corresponding legend.
What I'm currently able to do is
put everything in one figure (they overlap in that case because their positions in the original uipanels are the same),
put each axes and each legend into their own respective figures,
put all axes in one and all legends in another figure and
put all axes in their own figure with all legends within the same panel.
split it up by panel, that is, put all subplots into the same figure and each group of plots in their own figure.
Problem:
The problem is, I don't have the handles to either of those objects. I only have the handles to the uipanel objects. The graphics inside the panels are built by another function which contains all sorts of tricky stuff, but doesn't return handles. Also the parenting structure of said panels makes it rather hard to do this with tricks like get(handles.panels{1},'Children') because it will work in some, but not all cases.
I thought about simply exporting the panels (and have actually a working version which does this), but this has several problems, mainly related to figure tools and resizing. I want to get rid of the panels when I use the "Export" button.
Code Snippet / Example:
The following code snippet will create an example GUI with access to all handles I have access to in my complete GUI. Clicking the buttons will show the different versions I got to "work". What I want is one figure for each axes including its legend, if it has one. the 4th version (same parent) comes close, but breaks if it encounters subplots, the 5th version (by panel) simply puts entire subplot groups into one window (in which case, at least, they don't overlap). Copy the code into a new .mfile to try it.
function test
figure(1)
clf
t=(0:0.1:10)'; %'// dummy comment
p2 = uipanel('Visible','off','Position',[0 0 1 1]);
p1 = uipanel('position',[0 0 1 1]);
p11 = uipanel('Parent',p1,'Position',[0 0 0.5 0.9]);
p12 = uipanel('Parent',p1,'Position',[0.5 0 0.5 0.9]);
uicontrol('Style','push','String','all in one','Units','norm',...
'Position',[0.05 0.91 0.14 0.06],'Callback',#export1);
uicontrol('Style','push','String','all in own','Units','norm',...
'Position',[0.24 0.91 0.14 0.06],'Callback',#export2);
uicontrol('Style','push','String','by type','Units','norm',...
'Position',[0.43 0.91 0.14 0.06],'Callback',#export3);
uicontrol('Style','push','String','same parent','Units','norm',...
'Position',[0.62 0.91 0.14 0.06],'Callback',#export4);
uicontrol('Style','push','String','same panel','Units','norm',...
'Position',[0.81 0.91 0.14 0.06],'Callback',#export5);
subplot(1,1,1,'Parent',p11)
plot(t,[sin(t) cos(t)])
legend('Sine','Cosine')
subplot(2,1,1,'Parent',p12)
plot(t,[polyval([0.05 -1 2],t) exp(-t) abs(t-3)])
subplot(2,1,2,'Parent',p12)
plot(t,erf(t))
legend('Error function')
function export1(~,~)
current = findobj('Type','uipanel','Parent',1,'Visible','on');
visible_axes = findobj(current,'Type','axes');
copyobj(visible_axes,figure);
end
function export2(~,~)
current = findobj('Type','uipanel','Parent',1,'Visible','on');
visible_axes = findobj(current,'Type','axes');
for i=1:length(visible_axes)
copyobj(visible_axes(i),figure);
end
end
function export3(~,~)
current = findobj('Type','uipanel','Parent',1,'Visible','on');
visible_axes = findobj(current,'Type','axes','Tag','');
visible_legends = findobj(current,'Tag','legend');
copyobj(visible_axes,figure);
copyobj(visible_legends,figure);
end
function export4(~,~)
current = findobj('Type','uipanel','Parent',1,'Visible','on');
visible_axes = findobj(current,'Type','axes','Tag','');
visible_legends = findobj(current,'Tag','legend');
for i=1:length(visible_axes)
par = get(visible_axes(i),'Parent');
same = findobj(visible_legends,'Parent',par);
h=figure;
copyobj(visible_axes(i),h)
copyobj(same,h)
end
end
function export5(~,~)
current = findobj('Type','uipanel','Parent',1,'Visible','on');
visible_axes = findobj(current,'Type','axes');
parents = cell2mat(get(visible_axes,'Parent'));
uparents = unique(parents);
for i=1:length(uparents)
copyobj(visible_axes(parents==uparents(i)),figure)
end
end
end
In a figure, graphical objects are organized hierarchically and can all be handled individually. For instance, axes is a child of a figure, plot is a child of an axes, and legends are build as axes.
The following example plots 2 lines (red and blue, with legends), then mixes plots and legends using copyobj.
figure;
subplot(1,2,1)
hp1 = plot(1:10,'r')
hl1 = legend('red')
subplot(1,2,2)
hp2 = plot(1:10,'b')
hl2 = legend('blue')
hf = figure;
hax = axes;
copyobj(hp1, hax); %copy plot to axes
copyobj(hl2, hf); %copy legend to figure
Not tested with a GUI though.
I think the simpler solution is to save the axes of the figure you're about to save as a fig file.
h = figure(1);
x = linspace(1,100);
y = 2*x;
ax = findall(h,'type','axes');
plot(x,y);
save('youraxes', 'ax');
hgsave(h, 'yourfig.fig');
I'm using Matlab R2012a, alternatively in R2013a or b the function to save the fig is now savefig.
Once you have obtained the axes handle you can find the corresponding legend handle using
legend_handle = legend(axes_handle)

Plotting an existing MATLAB plot into another figure

I used the plot command to plot a figure and then changed lots of its properties using set command. I also store the handle of the plot (say h1).
What I need is to use the handle to plot the same figure again later in my code. I checked the plot command and did not find any version that accepts handle. I also thought of getting the Xdata and Ydata and use them to re-plot the same figure.
What is the simplest solution?
Edit 1: A working sample code based on copyobj that PeterM suggested.
hf(1) = figure(1);
plot(peaks);
hf(2) = figure(2);
plot(membrane);
hf(3) = figure(3);
ha(1) = subplot(1,2,1);
ha(2) = subplot(1,2,2);
for i = 1:2
hc = get(hf(i),'children');
hgc = get(hc, 'children');
copyobj(hgc,ha(i));
end
Edit 2: I also found this function that can copy figures (including legend) into a subplot.
I have run into this situation before. Depending on what you are trying to do the function copyobj may be appropriate. This function lets you take the contents of one axes and copy it to a new figure.
Improving #PeterM nice answer, one easier way would be:
fig2H=copy(gcf) % or change gcf to your figure handle
But it depends on what you want, if you want only the axes, or the whole figure… (btw, it doesn't seem to copy the legend handle).
You can use saveas to save the figure in a file, and the open to load the exact same figure from this file.
This would be the laziest way to accomplish what you want.
% Sample plot
f1 = figure(1);
plot(0:0.1:2*pi, sin(0:0.1:2*pi));
f2 = figure(2);
% The code you need
saveas(f1, 'temp.fig')
f2 = hgload('temp.fig')
delete('temp.fig')
I have used the function figs2subplots (given in Edit2 in the original question) - it does the work and is very easy to use.

Save exact image output from imagesc in matlab

Hi , I want to save this image produced from imagesc(magic(3)), the exact rainbow representation, is it possible?
Thanks.
This question might look like a duplicate , but it is not . I looked at the solution to the similar question at this site , but it did not satisfy me .
I have looked into the Matlab help center and the close answer that I got was this one , at the bottom of http://goo.gl/p907wR
To save the figure as a file (don't matter how it was created), one should do:
saveas(figureHandle,'filename','format')
where figureHandle could be the gcf handle, which means: get current figure.
As pointed in the discussion, if someone doesn't want the ticks to be shown, the person can add:
set(gca,'XTick',[])
set(gca,'YTick',[])
where gca is the handle to the current axis, just as gcf. If you have more than one axis, don't forget to "handle the handles". They are returned to you when you create them, i.e.:
hFig = figure(pairValuedProperties); % Create and get the figure handle
hAxes1 = suplot(2,1,1,pairValuedProperties); % Create and get the upper axes handle
hAxes2 = suplot(2,1,2,pairValuedProperties); % Create and get the bottom axes handle
where the pair value are the figure or axes properties declared in the following syntax:
'PropertyName1',PropertyValue1,'PropertyName2',PropertyValue2,…
Here are the matlab documentation about the Figure and Axes Properties, and about the saveas method.
Example:
The image saved with the following code:
figure
imagesc(magic(3))
set(gca,'XTick',[]) % Remove the ticks in the x axis!
set(gca,'YTick',[]) % Remove the ticks in the y axis
set(gca,'Position',[0 0 1 1]) % Make the axes occupy the hole figure
saveas(gcf,'Figure','png')
You can use:
print -djpeg99 'foo.jpg'
This will save it as 'foo.jpg' as you need.
You can use the following code
imagesc(A);
%%saving the image
hgexport(gcf, 'figure1.jpg', hgexport('factorystyle'), 'Format', 'jpeg');
set(gcf,'PaperUnits','inches','PaperPosition',[0 0 4 4]);
print -djpeg filename.jpg -r10
Here A will be the matrix from which you will have an image. And the image will be saved as filename.jpg in the directory.