-
Notifications
You must be signed in to change notification settings - Fork 368
/
isolate_axes.m
175 lines (158 loc) · 6.43 KB
/
isolate_axes.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
function fh = isolate_axes(ah, vis)
%ISOLATE_AXES Isolate the specified axes in a figure on their own
%
% Examples:
% fh = isolate_axes(ah)
% fh = isolate_axes(ah, vis)
%
% This function will create a new figure containing the axes/uipanels
% specified, and also their associated legends and colorbars. The objects
% specified must all be in the same figure, but they will generally only be
% a subset of the objects in the figure.
%
% IN:
% ah - An array of axes and uipanel handles, which must come from the
% same figure.
% vis - A boolean indicating whether the new figure should be visible.
% Default: false.
%
% OUT:
% fh - The handle of the created figure.
% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015-
%{
% Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs
% 16/03/12: Moved copyfig to its own function. Thanks to Bob Fratantonio
% for pointing out that the function is also used in export_fig.m
% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it
% 08/10/13: Bug fix to allchildren suggested by Will Grant (many thanks!)
% 05/12/13: Bug fix to axes having different units. Thanks to Remington Reid for reporting
% 21/04/15: Bug fix for exporting uipanels with legend/colorbar on HG1 (reported by Alvaro
% on FEX page as a comment on 24-Apr-2014); standardized indentation & help section
% 22/04/15: Bug fix: legends and colorbars were not exported when exporting axes handle in HG2
% 02/02/21: Fix axes, figure size to preserve input axes image resolution (thanks @Optecks)
% 25/10/21: Bug fix: subplots were not isolated properly leading to print error (issue #347)
% 24/03/23: Remove any non-legendable objects from the legend (workaround for copyobj bug)
%}
% Make sure we have an array of handles
if ~all(ishandle(ah))
error('ah must be an array of handles');
end
% Check that the handles are all for axes or uipanels, and are all in the same figure
fh = ancestor(ah(1), 'figure');
nAx = numel(ah);
for a = 1:nAx
if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'})
error('All handles must be axes or uipanel handles.');
end
if ~isequal(ancestor(ah(a), 'figure'), fh)
error('Axes must all come from the same figure.');
end
end
% Tag the objects so we can find them in the copy
old_tag = get(ah, 'Tag');
if nAx == 1
old_tag = {old_tag};
end
set(ah, 'Tag', 'ObjectToCopy');
% Mark all non-legendable objects in the original figure (if any legend shown)
% a workaround to the copyobj bug of not copying the ApplicationData property
lh = findall(fh, 'Tag','legend');
if ~isempty(lh)
ax = arrayfun(@(h) get(h,'Axes'), lh);
c = findall(ax);
hb = ~arrayfun(@(h)hasbehavior(h,'legend'), c);
c = c(hb);
oldTags = get(c,'Tag');
set(c,'Tag','non-legendable!')
end
% Create a new figure exactly the same as the old one
fh = copyfig(fh); %copyobj(fh, 0);
% Fix Axes & Figure size for image catpuring to have almost exact resolution
% of the Input Axes (thanks @Optecks)
allaxes = findall(fh, 'type', 'axes');
if ~isempty(ah)
sz = get(ah(1), 'OuterPosition');
un = get(ah(1), 'Units');
set(allaxes(1), 'Units',un, 'OuterPosition', [0 0 sz(3) sz(4)]);
set(allaxes(1), 'Units','pixels');
sz = get(allaxes(1), 'OuterPosition');
set(fh, 'Units','pixels', 'Position',[0 0 sz(3) sz(4)]+1);
end
if nargin < 2 || ~vis
set(fh, 'Visible', 'off');
end
% Restore the axes tags in the original figure back to their original values
for a = 1:nAx
set(ah(a), 'Tag', old_tag{a});
end
% Find the objects to save
ah = findall(fh, 'Tag', 'ObjectToCopy');
if numel(ah) ~= nAx
close(fh);
error('Incorrect number of objects found.');
end
% Set the axes tags in the new figure to what they should be
for a = 1:nAx
set(ah(a), 'Tag', old_tag{a});
end
% Keep any legends and colorbars which overlap the subplots
% Note: in HG1 these are axes objects; in HG2 they are separate objects, therefore we
% don't test for the type, only the tag (hopefully nobody but Matlab uses them!)
lh = findall(fh, 'Tag','legend', '-or', 'Tag','Colorbar');
nLeg = numel(lh);
if nLeg > 0
% Remove any non-legendable objects from the legend (if previously set)
c2 = findall(ah,'Tag','non-legendable!');
if ~isempty(c2)
arrayfun(@(h)hasbehavior(h,'legend',false), c2);
arrayfun(@(h,t)set(h,'Tag',t{1}),c,oldTags); %restore object tags to orig values
end
set([ah(:); lh(:)], 'Units', 'normalized');
try
ax_pos = get(ah, 'OuterPosition'); % axes and figures have the OuterPosition property
catch
ax_pos = get(ah, 'Position'); % uipanels only have Position, not OuterPosition
end
if nAx > 1
ax_pos = cell2mat(ax_pos(:));
end
ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2);
try
leg_pos = get(lh, 'OuterPosition');
catch
leg_pos = get(lh, 'Position'); % No OuterPosition in HG2, only in HG1
end
if nLeg > 1
leg_pos = cell2mat(leg_pos);
end
leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2);
ax_pos = shiftdim(ax_pos, -1);
% Overlap test
M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ...
bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ...
bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ...
bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2));
ah = [ah; lh(any(M, 2))];
end
% Get all the objects in the figure
axs = findall(fh);
% Delete everything except for the input objects and associated items
delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)])));
end
function ah = allchildren(ah)
ah = findall(ah);
if iscell(ah)
ah = cell2mat(ah);
end
ah = ah(:);
end
function ph = allancestors(ah)
ph = [];
for a = 1:numel(ah)
h = get(ah(a), 'parent');
while h ~= 0
ph = [ph; h]; %#ok<AGROW>
h = get(h, 'parent');
end
end
end