# HG changeset patch # User Rik # Date 1390502664 28800 # Node ID 097202cbe564387af64a0dfcc5d24003707d5ad3 # Parent 02b349ccf0eca29065c953acb4d9977aa4f8f29d plotyy.m: Overhaul function to use updated newplot(). * plotyy.m: Improve docstring. Accept a single axis handle input as the first argument into which to put the left-hand axis. Validate number of input arguments. Match function output variable names to documentation. Make left-hand axis the active axis according to gca when leaving the function. Remove 3rd %!demo which was not testing new functionality. Add titles to %!demo plots. * plotyy.m (__plotyy__): Use function defaults to simplify input processing. Correctly set color of second plot even when 'hold on' is used. Combine multiple get/set calls into one call to reduce function calling overhead. diff -r 02b349ccf0ec -r 097202cbe564 scripts/plot/draw/plotyy.m --- a/scripts/plot/draw/plotyy.m Thu Jan 23 10:38:10 2014 -0500 +++ b/scripts/plot/draw/plotyy.m Thu Jan 23 10:44:24 2014 -0800 @@ -22,7 +22,7 @@ ## @deftypefnx {Function File} {} plotyy (@dots{}, @var{fun1}, @var{fun2}) ## @deftypefnx {Function File} {} plotyy (@var{hax}, @dots{}) ## @deftypefnx {Function File} {[@var{ax}, @var{h1}, @var{h2}] =} plotyy (@dots{}) -## Plot two sets of data with independent y-axes. +## Plot two sets of data with independent y-axes and a common x-axis. ## ## The arguments @var{x1} and @var{y1} define the arguments for the first plot ## and @var{x1} and @var{y2} for the second. @@ -40,7 +40,7 @@ ## the principal axis in which to plot the @var{x1} and @var{y1} data. ## ## The return value @var{ax} is a vector with the axis handles of the two -## y axes. @var{h1} and @var{h2} are handles to the objects generated by the +## y-axes. @var{h1} and @var{h2} are handles to the objects generated by the ## plot commands. ## ## @example @@ -57,113 +57,66 @@ ## @seealso{plot} ## @end deftypefn -function [Ax, H1, H2] = plotyy (varargin) +function [ax, h1, h2] = plotyy (varargin) - ## Don't use __plt_get_axis_arg__ here as ax is a two vector for plotyy - if (nargin > 1 && length (varargin{1}) == 2 && ishandle (varargin{1}(1)) - && ishandle (varargin{1}(2)) - && all (floor (varargin{1}) != varargin{1})) - obj1 = get (varargin{1}(1)); - obj2 = get (varargin{1}(2)); - if (strcmp (obj1.type, "axes") || strcmp (obj2.type, "axes")) - ax = [obj1, obj2]; - varargin(1) = []; - if (isempty (varargin)) - varargin = {}; - endif - else - error ("plotyy: expecting first argument to be axes handle"); - endif - oldh = gca (); - else - f = get (0, "currentfigure"); - if (isempty (f)) - f = figure (); - endif - ca = get (f, "currentaxes"); - if (isempty (ca)) - ax = []; - elseif (ishandle (ca) && isprop (ca, "__plotyy_axes__")) - ax = get (ca, "__plotyy_axes__"); - else - ax = ca; - endif - if (length (ax) > 2) - for i = 3 : length (ax) - delete (ax (i)); - endfor - ax = ax(1:2); - elseif (length (ax) == 1) - ax(2) = axes (); - set (ax(2), "nextplot", get (ax(1), "nextplot")); - elseif (isempty (ax)) - ax(1) = axes (); - ax(2) = axes (); - ca = ax(2); - endif - if (nargin < 2) - varargin = {}; - endif - oldh = ca; - endif + [hax, varargin] = __plt_get_axis_arg__ ("plotyy", varargin{:}); - if (nargin < 4) + nargin = numel (varargin); + if (nargin < 4 || nargin > 6) print_usage (); endif + oldfig = []; + if (! isempty (hax)) + oldfig = get (0, "currentfigure"); + endif unwind_protect - [ax, h1, h2] = __plotyy__ (ax, varargin{:}); + hax = newplot (hax); + + ## FIXME: Second conditional test shouldn't be required. + ## 'cla reset' needs to delete user properties like __plotyy_axes__. + if (isprop (hax, "__plotyy_axes__") + && isaxes (get (hax, "__plotyy_axes__")) == [true true]) + hax = get (hax, "__plotyy_axes__"); + else + hax(2) = axes ("nextplot", get (hax(1), "nextplot")); + endif + + [axtmp, h1tmp, h2tmp] = __plotyy__ (hax, varargin{:}); + + set (gcf, "currentaxes", hax(1)); + unwind_protect_cleanup - ## Only change back to the old axis if we didn't delete it - if (isaxes (oldh)) - axes (oldh); + if (! isempty (oldfig)) + set (0, "currentfigure", oldfig); endif end_unwind_protect if (nargout > 0) - Ax = ax; - H1 = h1; - H2 = h2; + ax = axtmp; + h1 = h1tmp; + h2 = h2tmp; endif endfunction -function [ax, h1, h2] = __plotyy__ (ax, x1, y1, x2, y2, varargin) - if (nargin > 5) - fun1 = varargin{1}; - else - fun1 = @plot; - endif - if (nargin > 6) - fun2 = varargin{2}; - else +function [ax, h1, h2] = __plotyy__ (ax, x1, y1, x2, y2, fun1 = @plot, fun2) + + if (nargin < 7) fun2 = fun1; endif xlim = [min([x1(:); x2(:)]), max([x1(:); x2(:)])]; - if (isaxes (ax(1))) - axes (ax(1)); - else - ax(1) = axes (); - endif - newplot (); + axes (ax(1)); + h1 = feval (fun1, x1, y1); - set (ax(1), "ycolor", getcolor (h1(1))); - set (ax(1), "xlim", xlim); - set (ax(1), "color", "none"); - - cf = gcf (); - set (cf, "nextplot", "add"); + set (ax(1), "color", "none", "ycolor", getcolor (h1(1)), "xlim", xlim); - if (isaxes (ax(2))) - axes (ax(2)); - else - ax(2) = axes (); - set (ax(2), "nextplot", get (ax(1), "nextplot")); - endif - newplot (); + set (gcf (), "nextplot", "add"); + + axes (ax(2)); colors = get (ax(1), "colororder"); set (ax(2), "colororder", [colors(2:end,:); colors(1,:)]); @@ -174,35 +127,38 @@ set (ax, "activepositionproperty", "position"); endif - ## Kluge, until __plt_get_axis_arg__ and newplot are reworked. - set (ax(2), "nextplot", "replacechildren"); + ## Don't replace axis which has colororder property already modified + if (strcmp (get (ax(1), "nextplot"), "replace")) + set (ax(2), "nextplot", "replacechildren"); + endif h2 = feval (fun2, ax(2), x2, y2); - set (ax(2), "yaxislocation", "right"); - set (ax(2), "ycolor", getcolor (h2(1))); + + set (ax(2), "yaxislocation", "right", "color", "none", + "ycolor", getcolor (h2(1)), "box", "off", "xlim", xlim); if (strcmp (get(ax(1), "activepositionproperty"), "position")) set (ax(2), "position", get (ax(1), "position")); else - set (ax(2), "outerposition", get (ax(1), "outerposition")); - set (ax(2), "looseinset", get (ax(1), "looseinset")); + set (ax(2), {"outerposition", "looseinset"}, + get (ax(1), {"outerposition", "looseinset"})); endif - set (ax(2), "xlim", xlim); - set (ax(2), "color", "none"); - set (ax(2), "box", "off"); + ## Restore nextplot value by copying value from axis #1 + set (ax(2), "nextplot", get (ax(1), "nextplot")); ## Add invisible text objects that when destroyed, ## also remove the other axis t1 = text (0, 0, "", "parent", ax(1), "tag", "plotyy", - "handlevisibility", "off", "visible", "off", + "visible", "off", "handlevisibility", "off", "xliminclude", "off", "yliminclude", "off"); t2 = text (0, 0, "", "parent", ax(2), "tag", "plotyy", - "handlevisibility", "off", "visible", "off", + "visible", "off", "handlevisibility", "off", "xliminclude", "off", "yliminclude", "off"); set (t1, "deletefcn", {@deleteplotyy, ax(2), t2}); set (t2, "deletefcn", {@deleteplotyy, ax(1), t1}); + ## Add cross-listeners so a change in one axes' attributes updates the other. addlistener (ax(1), "position", {@update_position, ax(2)}); addlistener (ax(2), "position", {@update_position, ax(1)}); addlistener (ax(1), "outerposition", {@update_position, ax(2)}); @@ -235,6 +191,80 @@ endif endfunction +function deleteplotyy (h, ~, ax2, t2) + if (isaxes (ax2) + && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"), "off")) + && strcmp (get (ax2, "beingdeleted"), "off")) + set (t2, "deletefcn", []); + delete (ax2); + endif +endfunction + +function update_nextplot (h, ~, ax2) + persistent recursion = false; + if (! recursion) + unwind_protect + recursion = true; + set (ax2, "nextplot", get (h, "nextplot")); + unwind_protect_cleanup + recursion = false; + end_unwind_protect + endif +endfunction + +function update_position (h, ~, ax2) + persistent recursion = false; + + ## Don't allow recursion + if (! recursion) + unwind_protect + recursion = true; + view = get (h, "view"); + oldview = get (ax2, "view"); + plotboxaspectratio = get (h, "plotboxaspectratio"); + oldplotboxaspectratio = get (ax2, "plotboxaspectratio"); + plotboxaspectratiomode = get (h, "plotboxaspectratiomode"); + oldplotboxaspectratiomode = get (ax2, "plotboxaspectratiomode"); + + if (strcmp (get (h, "activepositionproperty"), "position")) + position = get (h, "position"); + oldposition = get (ax2, "position"); + if (! (isequal (position, oldposition) && isequal (view, oldview))) + set (ax2, "position", position, "view", view); + endif + else + outerposition = get (h, "outerposition"); + oldouterposition = get (ax2, "outerposition"); + if (! (isequal (outerposition, oldouterposition) + && isequal (view, oldview))) + set (ax2, "outerposition", outerposition, "view", view); + endif + endif + + if (! (isequal (plotboxaspectratio, oldplotboxaspectratio) + && isequal (plotboxaspectratiomode, oldplotboxaspectratiomode))) + set (ax2, "plotboxaspectratio", plotboxaspectratio, + "plotboxaspectratiomode", plotboxaspectratiomode); + endif + unwind_protect_cleanup + recursion = false; + end_unwind_protect + endif +endfunction + +function color = getcolor (ax) + obj = get (ax); + if (isfield (obj, "color")) + color = obj.color; + elseif (isfield (obj, "facecolor") && ! ischar (obj.facecolor)) + color = obj.facecolor; + elseif (isfield (obj, "edgecolor") && ! ischar (obj.edgecolor)) + color = obj.edgecolor; + else + color = [0, 0, 0]; + endif +endfunction + %!demo %! clf; @@ -245,12 +275,11 @@ %! xlabel ('X'); %! ylabel (ax(1), 'Axis 1'); %! ylabel (ax(2), 'Axis 2'); -%! axes (ax(1)); %! text (0.5, 0.5, 'Left Axis', ... -%! 'color', [0 0 1], 'horizontalalignment', 'center'); -%! axes (ax(2)); +%! 'color', [0 0 1], 'horizontalalignment', 'center', 'parent', ax(1)); %! text (4.5, 80, 'Right Axis', ... -%! 'color', [0 0.5 0], 'horizontalalignment', 'center'); +%! 'color', [0 0.5 0], 'horizontalalignment', 'center', 'parent', ax(2)); +%! title ({"plotyy() example"; "Left axis uses @plot, Right axis uses @semilogy"}); %!demo %! clf; @@ -267,14 +296,6 @@ %! axis square; %!demo -%! clf; -%! x = linspace (-1, 1, 201); -%! hax = plotyy (x, sin (pi*x), x, cos (pi*x)); -%! ylabel (hax(1), 'Blue on the Left'); -%! ylabel (hax(2), 'Green on the Right'); -%! xlabel ('xlabel'); - -%!demo %! clf %! hold on %! t = (0:0.1:9); @@ -284,81 +305,7 @@ %! [~, h3, h4] = plotyy (t+1, x, t+1, y); %! set ([h3, h4], 'linestyle', '--'); %! xlabel (hax(1), 'xlabel'); -%! title (hax(2), 'title'); +%! title (hax(2), 'Two plotyy graphs on same figure using "hold on"'); %! ylabel (hax(1), 'Left axis is Blue'); %! ylabel (hax(2), 'Right axis is Green'); -function deleteplotyy (h, d, ax2, t2) - if (isaxes (ax2) - && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"),"off")) - && strcmp (get (ax2, "beingdeleted"), "off")) - set (t2, "deletefcn", []); - delete (ax2); - endif -endfunction - -function update_nextplot (h, d, ax2) - persistent recursion = false; - prop = "nextplot"; - if (! recursion) - unwind_protect - recursion = true; - set (ax2, prop, get (h, prop)); - unwind_protect_cleanup - recursion = false; - end_unwind_protect - endif -endfunction - -function update_position (h, d, ax2) - persistent recursion = false; - - ## Don't allow recursion - if (! recursion) - unwind_protect - recursion = true; - view = get (h, "view"); - oldview = get (ax2, "view"); - plotboxaspectratio = get (h, "plotboxaspectratio"); - oldplotboxaspectratio = get (ax2, "plotboxaspectratio"); - plotboxaspectratiomode = get (h, "plotboxaspectratiomode"); - oldplotboxaspectratiomode = get (ax2, "plotboxaspectratiomode"); - - if (strcmp (get(h, "activepositionproperty"), "position")) - position = get (h, "position"); - oldposition = get (ax2, "position"); - if (! (isequal (position, oldposition) && isequal (view, oldview))) - set (ax2, "position", position, "view", view); - endif - else - outerposition = get (h, "outerposition"); - oldouterposition = get (ax2, "outerposition"); - if (! (isequal (outerposition, oldouterposition) && isequal (view, oldview))) - set (ax2, "outerposition", outerposition, "view", view); - endif - endif - - if (! (isequal (plotboxaspectratio, oldplotboxaspectratio) - && isequal (plotboxaspectratiomode, oldplotboxaspectratiomode))) - set (ax2, "plotboxaspectratio", plotboxaspectratio); - set (ax2, "plotboxaspectratiomode", plotboxaspectratiomode); - endif - unwind_protect_cleanup - recursion = false; - end_unwind_protect - endif -endfunction - -function color = getcolor (ax) - obj = get (ax); - if (isfield (obj, "color")) - color = obj.color; - elseif (isfield (obj, "facecolor") && ! ischar (obj.facecolor)) - color = obj.facecolor; - elseif (isfield (obj, "edgecolor") && ! ischar (obj.edgecolor)) - color = obj.edgecolor; - else - color = [0, 0, 0]; - endif -endfunction -