######################################################################## ## ## Copyright (C) 2005-2021 The Octave Project Developers ## ## See the file COPYRIGHT.md in the top-level directory of this ## distribution or . ## ## This file is part of Octave. ## ## Octave is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## ######################################################################## ## -*- texinfo -*- ## @deftypefn {} {} axes () ## @deftypefnx {} {} axes (@var{property}, @var{value}, @dots{}) ## @deftypefnx {} {} axes (@var{hpar}, @var{property}, @var{value}, @dots{}) ## @deftypefnx {} {} axes (@var{hax}) ## @deftypefnx {} {@var{h} =} axes (@dots{}) ## Create a Cartesian axes object and return a handle to it, or set the current ## axes to @var{hax}. ## ## Called without any arguments, or with @var{property}/@var{value} pairs, ## construct a new axes. The optional argument @var{hpar} is a graphics handle ## specifying the parent for the new axes and may be a figure, uipanel, or ## uitab. ## ## Called with a single axes handle argument @var{hax}, the function makes ## @var{hax} the current axes (as returned by @code{gca}). It also makes ## the figure which contains @var{hax} the current figure (as returned by ## @code{gcf}). Finally, it restacks the parent object's @code{children} ## property so that the axes @var{hax} appears before all other axes handles ## in the list. This causes @var{hax} to be displayed on top of any other axes ## objects (Z-order stacking). In addition it restacks any legend or colorbar ## objects associated with @var{hax} so that they are also visible. ## ## Programming Note: The full list of properties is documented at ## @ref{Axes Properties}. ## @seealso{gca, set, get} ## @end deftypefn function h = axes (varargin) htmp = hpar = []; if (nargin > 0) if (ishghandle (varargin{1}(1))) htmp = varargin{1}; if (! isscalar (htmp)) error ("axes: H must be a scalar handle"); endif typ = get (htmp, "type"); if (strcmp (typ, "axes") && nargin == 1) cf = ancestor (htmp, "figure"); if (__is_handle_visible__ (htmp)) set (0, "currentfigure", cf); set (cf, "currentaxes", htmp); endif restack_axes (htmp, get (htmp, "parent")); if (nargout > 0) h = htmp; endif return; elseif (any (strcmp (typ, {"figure", "uipanel", "uitab"}))) hpar = htmp; htmp = []; varargin(1) = []; else error ("axes: H must be a handle to an axes or container"); endif endif endif if (isempty (hpar)) ## Find a parent if not given as first argument. idx = find (strcmpi (varargin(1:2:end), "parent"), 1, "first"); if (! isempty (idx) && numel (varargin) >= 2*idx) hpar = varargin{2*idx}; varargin([2*idx-1, 2*idx]) = []; else hpar = gcf (); endif endif ## If there is an annotation axes currently on top of the children stack, ## then it must be placed back on top. ## FIXME: It may be necessary to keep uiXXX objects above all axes objects ## including even the transparent scribe axes layer. ch = allchild (hpar); h_annotation = ch(strcmp (get (ch, "tag"), "scribeoverlay")); ## Create an axes object. htmp = __go_axes__ (hpar, varargin{:}); if (__is_handle_visible__ (htmp)) set (ancestor (hpar, "figure"), "currentaxes", htmp); endif ## Restack annotation object if necessary if (! isempty (h_annotation)) ## FIXME: This will put annotation layer first, above even uicontrol ## objects. May need to keep annotation layer above all axes only. shh = get (0, "ShowHiddenHandles"); unwind_protect set (0, "ShowHiddenHandles", "on"); ch(ch == h_annotation) = htmp; ch = [h_annotation; ch]; set (hpar, "children", ch); unwind_protect_cleanup set (0, "ShowHiddenHandles", shh); end_unwind_protect endif if (nargout > 0) h = htmp; endif endfunction function restack_axes (h, hpar) shh = get (0, "ShowHiddenHandles"); unwind_protect set (0, "ShowHiddenHandles", "on"); ch = get (hpar, "children"); axidx = strcmp (get (ch, "type"), "axes"); ## Strip out any annotation axes layer, unless h itself is annotation axes. if (! strcmp (get (h, "tag"), "scribeoverlay")) axidx(axidx) = ! strcmp (get (ch(axidx), "tag"), "scribeoverlay"); endif hax = ch(axidx); # List of axes ## Find and stack any legend belonging to this axes above this axes. try hleg = get (h, "__legend_handle__"); catch hleg = false; end_try_catch ## Find and stack any colorbar belonging to this axes above this axes. try hcb = get (h, "__colorbar_handle__"); catch hcb = false; end_try_catch ## Preserve order of colorbars and legends above this axes if (hleg || hcb) if (hleg && ! hcb) h = [hleg; h]; elseif (hcb && ! hleg) h = [hcb; h]; else hcb_idx = find (hcb == hax); hleg_idx = find (hleg == hax); if (hleg_idx < hcb_idx) h = [hleg; hcb; h]; else h = [hcb; hleg; h]; endif endif endif ## FIXME: ismember call is very slow (2/3rds of runtime for function) ch(axidx) = [h; hax(! ismember (hax, h))]; set (hpar, "children", ch); unwind_protect_cleanup set (0, "ShowHiddenHandles", shh); end_unwind_protect endfunction ## FIXME: These demos actually just show how axes objects behave. ## They do not show how the axes() function itself works. %!demo %! clf; %! x = -10:10; %! plot (x,x, x,-x); %! set (gca, "yscale", "log"); %! legend ({"x >= 1", "x <= 1"}, "location", "north"); %! title ({"log axes discard negative data", "ylim = [1, 10]"}); %!demo %! clf; %! x = -10:0.1:10; %! y = sin (x)./(1 + abs (x)) + 0.1*x - 0.4; %! plot (x, y); %! set (gca, "xaxislocation", "origin"); %! set (gca, "yaxislocation", "origin"); %! box off; %! title ({"no plot box", "xaxislocation = origin, yaxislocation = origin"}); %!demo %! clf; %! x = -10:0.1:10; %! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; %! plot (x, y); %! set (gca, "xaxislocation", "origin"); %! set (gca, "yaxislocation", "left"); %! box off; %! title ({"no plot box", "xaxislocation = origin, yaxislocation = left"}); %!demo %! clf; %! x = -10:0.1:10; %! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; %! plot (x, y); %! title ("no plot box"); %! set (gca, "xaxislocation", "origin"); %! set (gca, "yaxislocation", "right"); %! box off; %! title ({"no plot box", "xaxislocation = origin, yaxislocation = right"}); %!demo %! clf; %! x = -10:0.1:10; %! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; %! plot (x, y); %! set (gca, "xaxislocation", "bottom"); %! set (gca, "yaxislocation", "origin"); %! box off; %! title ({"no plot box", "xaxislocation = bottom, yaxislocation = origin"}); %!demo %! clf; %! x = -10:0.1:10; %! y = sin (x)./(1+abs (x)) + 0.1*x - 0.4; %! plot (x, y); %! set (gca, "xaxislocation", "top"); %! set (gca, "yaxislocation", "origin"); %! box off; %! title ({"no plot box", "xaxislocation = top, yaxislocation = origin"}); %!test %! hf = figure ("visible", "off"); %! unwind_protect %! hax1 = axes ("tag", "axes1"); %! plot (1:10, "b"); %! hleg1 = legend ("leg1", "location", "east"); %! hcb1 = colorbar ("location", "east"); %! hanno = annotation ("arrow"); %! hscribe = get (hanno, "parent"); %! %! hax2 = axes ("tag", "axes2"); %! plot (10:-1:1, "r"); %! hcb2 = colorbar ("location", "east"); %! hleg2 = legend ("hax2"); %! %! ## Verify base configuration %! ch = allchild (hf); %! hax = ch(isaxes (ch)); %! hax1pos = find (hax1 == hax); %! hax2pos = find (hax2 == hax); %! hleg1pos = find (hleg1 == hax); %! hleg2pos = find (hleg2 == hax); %! hcb1pos = find (hcb1 == hax); %! hcb2pos = find (hcb2 == hax); %! hscribepos = find (hscribe == hax); %! %! assert (all (hscribepos < ... %! [hax1pos, hax2pos, hleg1pos, hleg2pos, hcb1pos, hcb2pos])); %! assert (hax2pos < hax1pos); %! assert (hleg2pos < hcb2pos && hcb2pos < hax2pos); %! assert (hcb1pos < hleg1pos && hleg1pos < hax1pos); %! %! ## Restack axes1 on top %! axes (hax1); %! ch = allchild (hf); %! hax = ch(isaxes (ch)); %! hax1pos = find (hax1 == hax); %! hax2pos = find (hax2 == hax); %! hleg1pos = find (hleg1 == hax); %! hleg2pos = find (hleg2 == hax); %! hcb1pos = find (hcb1 == hax); %! hcb2pos = find (hcb2 == hax); %! hscribepos = find (hscribe == hax); %! %! assert (all (hscribepos < ... %! [hax1pos, hax2pos, hleg1pos, hleg2pos, hcb1pos, hcb2pos])); %! assert (hax1pos < hax2pos); %! assert (hcb1pos < hleg1pos && hleg1pos < hax1pos); %! assert (hleg2pos < hcb2pos && hcb2pos < hax2pos); %! %! ## Restack axes2 on top %! axes (hax2); %! ch = allchild (hf); %! hax = ch(isaxes (ch)); %! hax1pos = find (hax1 == hax); %! hax2pos = find (hax2 == hax); %! hleg1pos = find (hleg1 == hax); %! hleg2pos = find (hleg2 == hax); %! hcb1pos = find (hcb1 == hax); %! hcb2pos = find (hcb2 == hax); %! hscribepos = find (hscribe == hax); %! %! assert (all (hscribepos < ... %! [hax1pos, hax2pos, hleg1pos, hleg2pos, hcb1pos, hcb2pos])); %! assert (hax2pos < hax1pos); %! assert (hleg2pos < hcb2pos && hcb2pos < hax2pos); %! assert (hcb1pos < hleg1pos && hleg1pos < hax1pos); %! %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect %!error axes ([0, 0]) %!error axes (0)