Mercurial > hg > octave-nkf
changeset 17036:08dd9458684a
Overhaul __plt_get_axis_arg__ and newplot functions to avoid creating unnecessary axes.
* scripts/plot/__plt_get_axis_arg__.m: Only return an axis handle if found in
argument list. Do not create any figures or axes.
* scripts/plot/newplot.m: Overhaul to allow specifying an axis handle input.
Prepare figure and axes according to Matlab conventions.
* scripts/plot/line.m: Never call newplot() for a core graphic object.
Always plot into gca.
* scripts/plot/plot.m: Update to use new __plt_get_axis_arg__ and newplot
functions.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 24 Jul 2013 23:05:37 -0700 |
parents | 08f0e372d006 |
children | f694f791709b |
files | scripts/plot/__plt_get_axis_arg__.m scripts/plot/line.m scripts/plot/newplot.m scripts/plot/plot.m |
diffstat | 4 files changed, 169 insertions(+), 87 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/plot/__plt_get_axis_arg__.m +++ b/scripts/plot/__plt_get_axis_arg__.m @@ -25,17 +25,7 @@ function [h, varargin, narg] = __plt_get_axis_arg__ (caller, varargin) - ## First argument can be a boolean which determines whether a new - ## axis will be created if none exists. - if (islogical (caller)) - nogca = caller; - caller = varargin{1}; - varargin(1) = []; - else - nogca = false; - endif - - ## Search for parent property + h = []; parent = find (strcmpi (varargin, "parent"), 1); ## Look for numeric scalar which is a graphics handle but not the @@ -65,28 +55,6 @@ else error ("%s: expecting parent value to be axes handle", caller); endif - else - ## No axis specified. Use current axis or create one as necessary. - f = get (0, "currentfigure"); - if (isempty (f)) - h = []; - else - h = get (f, "currentaxes"); - endif - if (isempty (h)) - if (nogca) - h = NaN; - else - h = gca (); - endif - endif - if (nargin < 2) - varargin = {}; - endif - endif - - if (ishandle (h) && strcmp (get (h, "nextplot"), "new")) - h = axes (); endif narg = length (varargin);
--- a/scripts/plot/line.m +++ b/scripts/plot/line.m @@ -40,9 +40,13 @@ function h = line (varargin) - ## Get any axis argument which may be in a 'parent' PROP/VAL pair + ## Get axis argument which may be in a 'parent' PROP/VAL pair [hax, varargin] = __plt_get_axis_arg__ ("line", varargin{:}); + if (isempty (hax)) + hax = gca (); + endif + htmp = __line__ (hax, varargin{:}); if (nargout > 0)
--- a/scripts/plot/newplot.m +++ b/scripts/plot/newplot.m @@ -18,56 +18,165 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} newplot () -## @deftypefnx {Function File} {@var{h} =} newplot () -## Prepare graphics engine to produce a new plot. This function is -## called at the beginning of all high-level plotting functions. -## It is not normally required in user programs. +## @deftypefnx {Function File} {} newplot (@var{hfig}) +## @deftypefnx {Function File} {} newplot (@var{hax}) +## @deftypefnx {Function File} {@var{hax} =} newplot (@dots{}) +## Prepare graphics engine to produce a new plot. +## +## This function is called at the beginning of all high-level plotting +## functions. It is not normally required in user programs. @code{newplot} +## queries the "NextPlot" field of the current figure and axis to determine +## what to do. +## +## @multitable @columnfractions .25 .75 +## @headitem Figure NextPlot @tab Action +## @item "new" @tab Create a new figure and make it the current figure. +## +## @item "add" (default) @tab Add new graphic objects to the current figure. +## +## @item "replacechildren" @tab Delete child objects whose HandleVisibility is +## set to "on". Set NextPlot property to "add". This typically clears a +## figure, but leaves in place hidden objects such as menubars. This is +## equivalent to @code{clf}. +## +## @item "replace" @tab Delete all child objects of the figure and reset all +## figure properties to their defaults. However, the following four properties +## are not reset: Position, Units, PaperPosition, PaperUnits. This is +## equivalent to @code{clf reset}. ## -## The optional return value @var{h} is a graphics handle to the created -## axes (not figure). +## @end multitable +## +## @multitable @columnfractions .25 .75 +## @headitem Axis NextPlot @tab Action +## @item "add" @tab Add new graphic objects to the current axes. This is +## equivalent to @code{hold on}. +## +## @item "replacechildren" @tab Delete child objects whose HandleVisibility is +## set to "on", but leave axis properties unmodified. This typically clears a +## plot, but preserves special settings such as log scaling for axes. +## This is equivalent to @code{cla}. +## +## @item "replace" (default) @tab Delete all child objects of the axis and reset all axis +## properties to their defaults. However, the following properties +## are not reset: Position, Units. This is equivalent to @code{cla reset}. +## +## @end multitable +## +## If the optional input @var{hfig} or @var{hax} is given then prepare the +## specified figure or axes rather than the current figure and axes. +## +## The optional return value @var{hax} is a graphics handle to the created +## axes object (not figure). +## +## @strong{Caution:} Calling @code{newplot} may change the current figure and +## current axis. ## @end deftypefn -function h = newplot () +## FIXME: The Matlab function takes an optional list of file handles, hsave, +## which are not deleted when the figure and axes are prepared. +## I'm sure there is a good reason for that, but coding such +## compatibility is really tricky and doesn't serve much purpose since +## newplot is nearly exclusively used by Octave internal plotting +## functions. In Octave's case the argument is almost always null, +## or occasionally the axis handle to plot into. + +function hax = newplot (hsave = []) + + if (nargin > 1) + print_usage (); + endif - if (nargin == 0) + cf = []; + ca = []; + + if (! isempty (hsave)) + ## Find the first valid axes + ca = ancestor (hsave, "axes", "toplevel"); + ca = ca(find (ca, 1)); + ## Next, find the figure associated with any axis found + if (! isempty (ca)) + cf = ancestor (ca, "figure", "toplevel"); + else + cf = ancestor (hsave, "figure", "toplevel"); + cf = cf(find (cf, 1)); + endif + endif + + if (isempty (cf)) + ## get current figure, or create a new one if necessary cf = gcf (); - fnp = get (cf, "nextplot"); - switch (fnp) - ## FIXME -- probably we should do more than validate the nextplot - ## property value... - case "new" - case "add" - case "replacechildren" - delete (get (cf, "children")); - case "replace" - otherwise - error ("newplot: unrecognized nextplot property for current figure"); - endswitch + else + ## switch to figure provided without causing other updates + set (0, "currentfigure", cf); + endif + + fnp = get (cf, "nextplot"); + switch (fnp) + case "add" + ## Default case. Doesn't require action. + case "new" + ## Ordinarily, create a new figure to hold plot. + ## But, if user has requested preparing a specific axis, then + ## use the existing figure to hold the requested axis. + if (isempty (ca)) + cf = figure (); + endif + case "replacechildren" + kids = get (cf, "children"); + if (! isempty (ca)) + kids(kids == ca) = []; + endif + delete (kids); + case "replace" + kids = allchild (cf); + if (! isempty (ca)) + kids(kids == ca) = []; + endif + delete (kids); + reset (cf); + endswitch + set (cf, "nextplot", "add"); # Matlab compatibility + + if (isempty (ca)) ca = gca (); - anp = get (ca, "nextplot"); - if (strcmp (get (ca, "__hold_all__"), "off")) - __next_line_color__ (true); - __next_line_style__ (true); - else - __next_line_color__ (false); - __next_line_style__ (false); - endif - switch (anp) - case "new" - case "add" - case "replacechildren" - delete (get (ca, "children")); - case "replace" - __go_axes_init__ (ca, "replace"); - __request_drawnow__ (); - otherwise - error ("newplot: unrecognized nextplot property for current axes"); - endswitch - if (nargout > 0) - h = ca; - endif + else + set (cf, "currentaxes", ca); + endif + + ## FIXME: Is this necessary anymore? + ## It seems like a kluge that belongs somewhere else. + if (strcmp (get (ca, "__hold_all__"), "off")) + __next_line_color__ (true); + __next_line_style__ (true); else - print_usage (); + __next_line_color__ (false); + __next_line_style__ (false); + endif + + anp = get (ca, "nextplot"); + switch (anp) + case "add" + ## Default case. Doesn't require action. + case "replacechildren" + delete (get (ca, "children")); + case "replace" + __go_axes_init__ (ca, "replace"); + __request_drawnow__ (); + ## FIXME: The code above should perform the following: + ########################### + ## delete (allchild (ca)); + ## reset (ca); + ########################### + ## Actually, __go_axes_init__ does both less and more. + ## It doesn't really remove all children since it re-instantiates + ## xlabel, ylabel, zlabel, and title text objects. + ## Also it preserves font properties like fontsize. + ## For the time being, in order to have axis labels and title work, + ## the above code is is required. + endswitch + + if (nargout > 0) + hax = ca; endif endfunction @@ -77,8 +186,8 @@ %! hf = figure ("visible", "off"); %! unwind_protect %! p = plot ([0, 1]); -%! ha = newplot (); -%! assert (ha, gca); +%! hax = newplot (); +%! assert (hax, gca); %! assert (isempty (get (gca, "children"))); %! unwind_protect_cleanup %! close (hf);
--- a/scripts/plot/plot.m +++ b/scripts/plot/plot.m @@ -181,25 +181,26 @@ ## Author: jwe -function retval = plot (varargin) +function h = plot (varargin) - [h, varargin, nargs] = __plt_get_axis_arg__ ("plot", varargin{:}); + [hax, varargin, nargs] = __plt_get_axis_arg__ ("plot", varargin{:}); if (nargs < 1) print_usage (); endif - oldh = gca (); + oldfig = ifelse (isempty (hax), [], get (0, "currentfigure")); unwind_protect - axes (h); - newplot (); - tmp = __plt__ ("plot", h, varargin{:}); + hax = newplot (hax); + htmp = __plt__ ("plot", hax, varargin{:}); unwind_protect_cleanup - axes (oldh); + if (! isempty (oldfig)) + set (0, "currentfigure", oldfig); + endif end_unwind_protect if (nargout > 0) - retval = tmp; + h = htmp; endif endfunction