1######################################################################## 2## 3## Copyright (C) 2005-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {} axes () 28## @deftypefnx {} {} axes (@var{property}, @var{value}, @dots{}) 29## @deftypefnx {} {} axes (@var{hpar}, @var{property}, @var{value}, @dots{}) 30## @deftypefnx {} {} axes (@var{hax}) 31## @deftypefnx {} {@var{h} =} axes (@dots{}) 32## Create a Cartesian axes object and return a handle to it, or set the current 33## axes to @var{hax}. 34## 35## Called without any arguments, or with @var{property}/@var{value} pairs, 36## construct a new axes. The optional argument @var{hpar} is a graphics handle 37## specifying the parent for the new axes and may be a figure, uipanel, or 38## uitab. 39## 40## Called with a single axes handle argument @var{hax}, the function makes 41## @var{hax} the current axes (as returned by @code{gca}). It also makes 42## the figure which contains @var{hax} the current figure (as returned by 43## @code{gcf}). Finally, it restacks the parent object's @code{children} 44## property so that the axes @var{hax} appears before all other axes handles 45## in the list. This causes @var{hax} to be displayed on top of any other axes 46## objects (Z-order stacking). In addition it restacks any legend or colorbar 47## objects associated with @var{hax} so that they are also visible. 48## 49## Programming Note: The full list of properties is documented at 50## @ref{Axes Properties}. 51## @seealso{gca, set, get} 52## @end deftypefn 53 54function h = axes (varargin) 55 56 htmp = hpar = []; 57 if (nargin > 0) 58 if (ishghandle (varargin{1}(1))) 59 htmp = varargin{1}; 60 if (! isscalar (htmp)) 61 error ("axes: H must be a scalar handle"); 62 endif 63 typ = get (htmp, "type"); 64 if (strcmp (typ, "axes") && nargin == 1) 65 cf = ancestor (htmp, "figure"); 66 if (__is_handle_visible__ (htmp)) 67 set (0, "currentfigure", cf); 68 set (cf, "currentaxes", htmp); 69 endif 70 restack_axes (htmp, get (htmp, "parent")); 71 72 if (nargout > 0) 73 h = htmp; 74 endif 75 return; 76 77 elseif (any (strcmp (typ, {"figure", "uipanel", "uitab"}))) 78 hpar = htmp; 79 htmp = []; 80 varargin(1) = []; 81 82 else 83 error ("axes: H must be a handle to an axes or container"); 84 endif 85 endif 86 endif 87 88 if (isempty (hpar)) 89 ## Find a parent if not given as first argument. 90 idx = find (strcmpi (varargin(1:2:end), "parent"), 1, "first"); 91 if (! isempty (idx) && numel (varargin) >= 2*idx) 92 hpar = varargin{2*idx}; 93 varargin([2*idx-1, 2*idx]) = []; 94 else 95 hpar = gcf (); 96 endif 97 endif 98 99 ## If there is an annotation axes currently on top of the children stack, 100 ## then it must be placed back on top. 101 ## FIXME: It may be necessary to keep uiXXX objects above all axes objects 102 ## including even the transparent scribe axes layer. 103 ch = allchild (hpar); 104 h_annotation = ch(strcmp (get (ch, "tag"), "scribeoverlay")); 105 106 ## Create an axes object. 107 htmp = __go_axes__ (hpar, varargin{:}); 108 if (__is_handle_visible__ (htmp)) 109 set (ancestor (hpar, "figure"), "currentaxes", htmp); 110 endif 111 112 ## Restack annotation object if necessary 113 if (! isempty (h_annotation)) 114 ## FIXME: This will put annotation layer first, above even uicontrol 115 ## objects. May need to keep annotation layer above all axes only. 116 shh = get (0, "ShowHiddenHandles"); 117 unwind_protect 118 set (0, "ShowHiddenHandles", "on"); 119 ch(ch == h_annotation) = htmp; 120 ch = [h_annotation; ch]; 121 set (hpar, "children", ch); 122 unwind_protect_cleanup 123 set (0, "ShowHiddenHandles", shh); 124 end_unwind_protect 125 endif 126 127 if (nargout > 0) 128 h = htmp; 129 endif 130 131endfunction 132 133function restack_axes (h, hpar) 134 135 shh = get (0, "ShowHiddenHandles"); 136 unwind_protect 137 set (0, "ShowHiddenHandles", "on"); 138 ch = get (hpar, "children"); 139 axidx = strcmp (get (ch, "type"), "axes"); 140 ## Strip out any annotation axes layer, unless h itself is annotation axes. 141 if (! strcmp (get (h, "tag"), "scribeoverlay")) 142 axidx(axidx) = ! strcmp (get (ch(axidx), "tag"), "scribeoverlay"); 143 endif 144 hax = ch(axidx); # List of axes 145 146 ## Find and stack any legend belonging to this axes above this axes. 147 try 148 hleg = get (h, "__legend_handle__"); 149 catch 150 hleg = false; 151 end_try_catch 152 153 ## Find and stack any colorbar belonging to this axes above this axes. 154 try 155 hcb = get (h, "__colorbar_handle__"); 156 catch 157 hcb = false; 158 end_try_catch 159 160 ## Preserve order of colorbars and legends above this axes 161 if (hleg || hcb) 162 if (hleg && ! hcb) 163 h = [hleg; h]; 164 elseif (hcb && ! hleg) 165 h = [hcb; h]; 166 else 167 hcb_idx = find (hcb == hax); 168 hleg_idx = find (hleg == hax); 169 if (hleg_idx < hcb_idx) 170 h = [hleg; hcb; h]; 171 else 172 h = [hcb; hleg; h]; 173 endif 174 endif 175 endif 176 177 ## FIXME: ismember call is very slow (2/3rds of runtime for function) 178 ch(axidx) = [h; hax(! ismember (hax, h))]; 179 set (hpar, "children", ch); 180 181 unwind_protect_cleanup 182 set (0, "ShowHiddenHandles", shh); 183 end_unwind_protect 184 185endfunction 186 187 188## FIXME: These demos actually just show how axes objects behave. 189## They do not show how the axes() function itself works. 190%!demo 191%! clf; 192%! x = -10:10; 193%! plot (x,x, x,-x); 194%! set (gca, "yscale", "log"); 195%! legend ({"x >= 1", "x <= 1"}, "location", "north"); 196%! title ({"log axes discard negative data", "ylim = [1, 10]"}); 197 198%!demo 199%! clf; 200%! x = -10:0.1:10; 201%! y = sin (x)./(1 + abs (x)) + 0.1*x - 0.4; 202%! plot (x, y); 203%! set (gca, "xaxislocation", "origin"); 204%! set (gca, "yaxislocation", "origin"); 205%! box off; 206%! title ({"no plot box", "xaxislocation = origin, yaxislocation = origin"}); 207 208%!demo 209%! clf; 210%! x = -10:0.1:10; 211%! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; 212%! plot (x, y); 213%! set (gca, "xaxislocation", "origin"); 214%! set (gca, "yaxislocation", "left"); 215%! box off; 216%! title ({"no plot box", "xaxislocation = origin, yaxislocation = left"}); 217 218%!demo 219%! clf; 220%! x = -10:0.1:10; 221%! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; 222%! plot (x, y); 223%! title ("no plot box"); 224%! set (gca, "xaxislocation", "origin"); 225%! set (gca, "yaxislocation", "right"); 226%! box off; 227%! title ({"no plot box", "xaxislocation = origin, yaxislocation = right"}); 228 229%!demo 230%! clf; 231%! x = -10:0.1:10; 232%! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; 233%! plot (x, y); 234%! set (gca, "xaxislocation", "bottom"); 235%! set (gca, "yaxislocation", "origin"); 236%! box off; 237%! title ({"no plot box", "xaxislocation = bottom, yaxislocation = origin"}); 238 239%!demo 240%! clf; 241%! x = -10:0.1:10; 242%! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; 243%! plot (x, y); 244%! set (gca, "xaxislocation", "top"); 245%! set (gca, "yaxislocation", "origin"); 246%! box off; 247%! title ({"no plot box", "xaxislocation = top, yaxislocation = origin"}); 248 249%!test 250%! hf = figure ("visible", "off"); 251%! unwind_protect 252%! hax1 = axes ("tag", "axes1"); 253%! plot (1:10, "b"); 254%! hleg1 = legend ("leg1", "location", "east"); 255%! hcb1 = colorbar ("location", "east"); 256%! hanno = annotation ("arrow"); 257%! hscribe = get (hanno, "parent"); 258%! 259%! hax2 = axes ("tag", "axes2"); 260%! plot (10:-1:1, "r"); 261%! hcb2 = colorbar ("location", "east"); 262%! hleg2 = legend ("hax2"); 263%! 264%! ## Verify base configuration 265%! ch = allchild (hf); 266%! hax = ch(isaxes (ch)); 267%! hax1pos = find (hax1 == hax); 268%! hax2pos = find (hax2 == hax); 269%! hleg1pos = find (hleg1 == hax); 270%! hleg2pos = find (hleg2 == hax); 271%! hcb1pos = find (hcb1 == hax); 272%! hcb2pos = find (hcb2 == hax); 273%! hscribepos = find (hscribe == hax); 274%! 275%! assert (all (hscribepos < ... 276%! [hax1pos, hax2pos, hleg1pos, hleg2pos, hcb1pos, hcb2pos])); 277%! assert (hax2pos < hax1pos); 278%! assert (hleg2pos < hcb2pos && hcb2pos < hax2pos); 279%! assert (hcb1pos < hleg1pos && hleg1pos < hax1pos); 280%! 281%! ## Restack axes1 on top 282%! axes (hax1); 283%! ch = allchild (hf); 284%! hax = ch(isaxes (ch)); 285%! hax1pos = find (hax1 == hax); 286%! hax2pos = find (hax2 == hax); 287%! hleg1pos = find (hleg1 == hax); 288%! hleg2pos = find (hleg2 == hax); 289%! hcb1pos = find (hcb1 == hax); 290%! hcb2pos = find (hcb2 == hax); 291%! hscribepos = find (hscribe == hax); 292%! 293%! assert (all (hscribepos < ... 294%! [hax1pos, hax2pos, hleg1pos, hleg2pos, hcb1pos, hcb2pos])); 295%! assert (hax1pos < hax2pos); 296%! assert (hcb1pos < hleg1pos && hleg1pos < hax1pos); 297%! assert (hleg2pos < hcb2pos && hcb2pos < hax2pos); 298%! 299%! ## Restack axes2 on top 300%! axes (hax2); 301%! ch = allchild (hf); 302%! hax = ch(isaxes (ch)); 303%! hax1pos = find (hax1 == hax); 304%! hax2pos = find (hax2 == hax); 305%! hleg1pos = find (hleg1 == hax); 306%! hleg2pos = find (hleg2 == hax); 307%! hcb1pos = find (hcb1 == hax); 308%! hcb2pos = find (hcb2 == hax); 309%! hscribepos = find (hscribe == hax); 310%! 311%! assert (all (hscribepos < ... 312%! [hax1pos, hax2pos, hleg1pos, hleg2pos, hcb1pos, hcb2pos])); 313%! assert (hax2pos < hax1pos); 314%! assert (hleg2pos < hcb2pos && hcb2pos < hax2pos); 315%! assert (hcb1pos < hleg1pos && hleg1pos < hax1pos); 316%! 317%! unwind_protect_cleanup 318%! close (hf); 319%! end_unwind_protect 320 321%!error <H must be a scalar handle> axes ([0, 0]) 322%!error <H must be a handle to an axes or container> axes (0) 323