Mercurial > octave
changeset 24498:5865d2fef424
legend.m: Clean up implementation.
* legend.m: Rename variable "fig" to "hfig" for clarity. Remove unnecessary
error() that should never happen (someone will always report it if it does).
Add more comments to try and explain code. Rename property "handle" to
"__axes_handle__" which points from legend to associated axes. Add new
property "__legend_handle__" to associated axes which points back to legend.
Replace complicated searches for an existing legend object with try/catch
block looking for "__legend_handle__" property. Remove redundanc code.
Rename "oldfig" to "origfig" for clarity. Rename "curaxes" to "origaxes"
for clarity. Important: Make new legend object's parent the same as the
parent of the associated axes. This makes legends work for things like uipanel,
not just figures. For performance, limit search for htdel text object to
a depth of 1.
* legend.m (cb_legend_update): Rename "handle" to "__axes_handle__". Remove
unnecessarily complicated code to get hplots from existing legend.
* legend.m (cb_restore_axes): Set "__legend_handle__" on associated axes
to [] when deleting legend.
* __getlegenddata__.m, axes.m: Rename property "handle" to "__axes_handle__".
* __errplot__.m: Remove unnecessary ancestor() call to find axes.
Replace search for legend with try/catch on "__legend_handle__" property.
* __plt__.m: Replace search for legend with try/catch on "__legend_handle__"
property.
* hdl2struct.m: Replace search for legend with try/catch on "__legend_handle__"
property. Replace search for colorbar with try/catch on "__colorbar_handle__"
* __gnuplot_draw_figure__.m: Rename property "handle" to "__axes_handle__".
Replace search for legend with try/catch on "__legend_handle__" property.
* __gnuplot_print__.m (get_figure_text): Simplify determination of legend,
it is just an axes object with tag set to legend.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 03 Jan 2018 08:10:48 -0800 |
parents | 1c96b44feb7a |
children | 941ea3da921f |
files | scripts/plot/appearance/__getlegenddata__.m scripts/plot/appearance/legend.m scripts/plot/draw/private/__errplot__.m scripts/plot/draw/private/__plt__.m scripts/plot/util/axes.m scripts/plot/util/hdl2struct.m scripts/plot/util/private/__gnuplot_draw_figure__.m scripts/plot/util/private/__gnuplot_print__.m |
diffstat | 8 files changed, 88 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/plot/appearance/__getlegenddata__.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/appearance/__getlegenddata__.m Wed Jan 03 08:10:48 2018 -0800 @@ -25,7 +25,7 @@ hplots = []; text_strings = {}; - ca = getappdata (hlegend, "handle"); + ca = getappdata (hlegend, "__axes_handle__"); if (numel (ca) == 1) kids = get (ca, "children"); else
--- a/scripts/plot/appearance/legend.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/appearance/legend.m Wed Jan 03 08:10:48 2018 -0800 @@ -133,9 +133,9 @@ ## @code{FontSize} to which it is attached. Use @code{set} to override this ## if necessary. ## -## A legend is implemented as an additional axes object of the current figure -## with the @code{tag} property set to @qcode{"legend"}. Properties of the -## legend object may be manipulated directly by using @code{set}. +## A legend is implemented as an additional axes object with the @code{tag} +## property set to @qcode{"legend"}. Properties of the legend object may be +## manipulated directly by using @code{set}. ## @end deftypefn function [hleg, hleg_obj, hplot, labels] = legend (varargin) @@ -148,11 +148,11 @@ if (isempty (ca)) ca = gca (); endif - fig = ancestor (ca, "figure"); + hfig = ancestor (ca, "figure"); else - fig = get (0, "currentfigure"); - if (isempty (fig)) - fig = gcf (); + hfig = get (0, "currentfigure"); + if (isempty (hfig)) + hfig = gcf (); endif ca = gca (); endif @@ -160,9 +160,6 @@ ## Special handling for plotyy which has two axes objects if (isprop (ca, "__plotyy_axes__")) plty = get (ca, "__plotyy_axes__"); - if (! all (ishghandle (plty))) - error ("legend.m: This should not happen. File a bug report."); - endif ca = [ca, plty.']; ## Remove duplicates while preserving order [~, n] = unique (ca, "first"); @@ -170,9 +167,11 @@ endif if (nargin > 0 && all (ishghandle (varargin{1}))) + ## List of plot objects to label given as first argument kids = flipud (varargin{1}(:)); varargin(1) = []; else + ## Find list of plot objects from axes "children" kids = ca; kids(strcmp (get (ca, "tag"), "legend")) = []; if (isscalar (kids)) @@ -184,17 +183,15 @@ nargs = numel (varargin); nkids = numel (kids); - ## Find any existing legend object on figure + ## Find any existing legend object associated with axes hlegend = []; - fkids = get (fig, "children"); - for i = 1 : numel (fkids) - if (strcmp (get (fkids(i), {"type", "tag"}), {"axes", "legend"})) - handle = getappdata (fkids(i), "handle"); - if (any (ismember (handle, ca))) - hlegend = fkids(i); + for hax = ca + try + hlegend = get (hax, "__legend_handle__"); + if (! isempty (hlegend)) break; endif - endif + end_try_catch endfor orientation = "default"; @@ -397,9 +394,6 @@ endif else ## Create or modify legend object - hobjects = []; - hplots = []; - text_strings = {}; if (! isempty (hlegend)) ## Disable callbacks while modifying an existing legend @@ -503,8 +497,7 @@ if (isempty (hplots)) ## Nothing to label if (! isempty (hlegend)) - fkids = get (fig, "children"); - delete (fkids(fkids == hlegend)); + delete (hlegend); hlegend = []; hobjects = []; hplots = []; @@ -582,28 +575,36 @@ linelength = 15; - ## Create the axes object first - oldfig = get (0, "currentfigure"); - if (oldfig != fig) - set (0, "currentfigure", fig); + ## Preamble code to restore figure and axes after legend creation + origfig = get (0, "currentfigure"); + if (origfig != hfig) + set (0, "currentfigure", hfig); else - oldfig = []; + origfig = []; endif - curaxes = get (fig, "currentaxes"); + origaxes = get (hfig, "currentaxes"); unwind_protect ud = ancestor (hplots, "axes"); if (! isscalar (ud)) ud = unique ([ud{:}]); endif + hpar = get (ud(1), "parent"); + if (isempty (hlegend)) ## Create a legend object (axes + new properties) addprops = true; - hlegend = axes ("tag", "legend", + hlegend = axes ("parent", hpar, "tag", "legend", "box", box, "xtick", [], "ytick", [], "xlim", [0, 1], "ylim", [0, 1], "activepositionproperty", "position"); - setappdata (hlegend, "handle", ud); + setappdata (hlegend, "__axes_handle__", ud); + try + addproperty ("__legend_handle__", ud(1), "handle", hlegend); + catch + set (ud(1), "__legend_handle__", hlegend); + end_try_catch + ## Inherit fontsize from current axis ## "fontunits" should be first because it affects interpretation ## of "fontsize" property. @@ -618,11 +619,12 @@ axes (hlegend); delete (get (hlegend, "children")); ## Hack: get list of hplots for which addlistener has been called. - old_hplots = [ get(hlegend, "deletefcn"){6:end} ]; + old_hplots = get (hlegend, "deletefcn"){6}; endif if (addprops) ## Only required for a newly created legend object + ## FIXME: "autoupdate" is not implemented. addproperty ("autoupdate", hlegend, "radio", "{on}|off"); addproperty ("edgecolor", hlegend, "color", [0.15, 0.15, 0.15]); addproperty ("textcolor", hlegend, "color", [0, 0, 0]); @@ -720,7 +722,7 @@ lpos = [0, 0, num1 * xstep, num2 * ystep]; endif - gnuplot = strcmp (get (fig, "__graphics_toolkit__"), "gnuplot"); + gnuplot = strcmp (get (hfig, "__graphics_toolkit__"), "gnuplot"); if (gnuplot) ## gnuplot places the key (legend) at edge of the figure window. ## OpenGL places the legend box at edge of the unmodified axes @@ -984,13 +986,13 @@ ## Add an invisible text object to original axis ## that, when it is destroyed, will remove the legend. - props = {"parent", ca(1), "tag", "deletelegend", ... - "visible", "off", "handlevisibility", "off", ... - "xliminclude", "off", "yliminclude", "off", ... - "zliminclude", "off"}; - htdel = findall (ca(1), "tag", "deletelegend", "type", "text"); + htdel = findall (ca(1), "-depth", 1, "tag", "deletelegend", + "type", "text"); if (isempty (htdel)) - htdel = text (0, 0, "", props{:}); + htdel = text (0, 0, "", "parent", ca(1), "tag", "deletelegend", + "visible", "off", "handlevisibility", "off", + "xliminclude", "off", "yliminclude", "off", + "zliminclude", "off"); set (htdel, "deletefcn", {@cb_axes_deleted, ca, hlegend}); endif if (isprop (hlegend, "unmodified_axes_position")) @@ -1094,10 +1096,11 @@ addlistener (hlegend, "string", @cb_legend_update); addlistener (hlegend, "textposition", @cb_legend_update); endif + unwind_protect_cleanup - set (fig, "currentaxes", curaxes); - if (! isempty (oldfig)) - set (0, "currentfigure", oldfig); + set (hfig, "currentaxes", origaxes); + if (! isempty (origfig)) + set (0, "currentfigure", origfig); endif end_unwind_protect endif @@ -1122,9 +1125,9 @@ if (! recursive) recursive = true; unwind_protect - hax = getappdata (hleg, "handle"); + hax = getappdata (hleg, "__axes_handle__"); ## Hack. Maybe store this somewhere else such as appdata. - hplots = [ get(hleg, "deletefcn"){6:end} ]; + hplots = get (hleg, "deletefcn"){6}; text_strings = get (hleg, "string"); position = get (hleg, "unmodified_axes_position"); outerposition = get (hleg, "unmodified_axes_outerposition"); @@ -1200,6 +1203,7 @@ endif endfunction + ## Axes to which legend was attached is being deleted/reset. Delete legend. function cb_axes_deleted (~, ~, ca, hlegend) if (isaxes (hlegend)) @@ -1257,6 +1261,9 @@ endif endfor + ## Nullify legend link (can't delete properties yet) + set (ca(1), "__legend_handle__", []); + endfunction ## Update legend item because underlying plot line object has changed. @@ -1748,10 +1755,10 @@ %! hax2 = subplot (1,2,2); %! plot (1:10); %! hleg1 = legend (hax1, "foo"); -%! assert (getappdata (hleg1, "handle"), hax1); +%! assert (getappdata (hleg1, "__axes_handle__"), hax1); %! assert (gca (), hax2); %! hleg2 = legend ("bar"); -%! assert (getappdata (hleg2, "handle"), gca ()); +%! assert (getappdata (hleg2, "__axes_handle__"), gca ()); %! unwind_protect_cleanup %! close (h); %! end_unwind_protect
--- a/scripts/plot/draw/private/__errplot__.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/draw/private/__errplot__.m Wed Jan 03 08:10:48 2018 -0800 @@ -242,7 +242,6 @@ addlistener (hg, "xudata", fcn); addlistener (hg, "format", fcn); - hax = ancestor (hg, "axes"); addlistener (hax, "xscale", fcn); addlistener (hax, "yscale", fcn); @@ -252,17 +251,11 @@ ## Process legend key if (! isempty (fmt.key) && nplots > 0) - hlegend = []; - fkids = get (gcf (), "children"); - for i = 1 : numel (fkids) - if (strcmp (get (fkids(i), {"type", "tag"}), {"axes", "legend"})) - leghandle = getappdata (fkids(i), "handle"); - if (! isempty (intersect (leghandle, gca ()))) - hlegend = fkids(i); - break; - endif - endif - endfor + try + hlegend = get (hax, "__legend_handle__"); + catch + hlegend = []; + end_try_catch if (isempty (hlegend)) hlgnd = [];
--- a/scripts/plot/draw/private/__plt__.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/draw/private/__plt__.m Wed Jan 03 08:10:48 2018 -0800 @@ -37,17 +37,12 @@ property_set = false; properties = {}; - hlegend = []; - fkids = get (gcf (), "children"); - for i = 1 : numel (fkids) - if (strcmp (get (fkids(i), {"type", "tag"}), {"axes", "legend"})) - leghandle = getappdata (fkids(i), "handle"); - if (! isempty (intersect (leghandle, gca ()))) - hlegend = fkids(i); - break; - endif - endif - endfor + ## Find any legend associated with this axes + try + hlegend = get (h, "__legend_handle__"); + catch + hlegend = []; + end_try_catch setlgnd = false; if (isempty (hlegend))
--- a/scripts/plot/util/axes.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/util/axes.m Wed Jan 03 08:10:48 2018 -0800 @@ -108,9 +108,9 @@ if (any (hleg)) ## Get axes handles associated with legend if (isscalar (hleg)) - hlegaxes = getappdata (hleg, "handle"); + hlegaxes = getappdata (hleg, "__axes_handle__"); else - hlegaxes = [getappdata(hleg, "handle"){:}](:); + hlegaxes = [getappdata(hleg, "__axes_handle__"){:}](:); endif hleg = hleg(hlegaxes == h); h = [hleg; h];
--- a/scripts/plot/util/hdl2struct.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/util/hdl2struct.m Wed Jan 03 08:10:48 2018 -0800 @@ -79,33 +79,31 @@ if (strcmp (s.type, "axes") && isempty (get (h, "tag"))) ## look for legends and colorbars among axes brothers and add them ## to the children list - - par = get (h, "parent"); - lg = findobj (par, "-depth", 1, "tag", "legend"); - if (! isempty (lg)) - ## identify legends which are attached to this axes. - idx = ([[get(lg).userdata].handle] == h); - lg = lg(idx); - endif + try + lg = get (h, "__legend_handle__"); + catch + lg = []; + end_try_catch nlg = length (lg); if (nlg == 1) ii += 1; s.children(ii) = hdl2struct (lg); elseif (nlg > 1) + ## FIXME: Unreachable code now. Delete? error ("hdl2struct: more than one legend found"); endif - cb = findobj (par, "-depth", 1, "tag", "colorbar"); - if (! isempty (cb)) - ## identify colorbars which are attached to this axes. - idx = ([get(cb).axes] == h); - cb = cb(idx); - endif + try + cb = get (h, "__colorbar_handle__"); + catch + cb = []; + end_try_catch ncb = length (cb); if (ncb == 1) ii += 1; s.children(ii) = hdl2struct (cb); elseif (ncb > 1) + ## FIXME: Unreachable code now. Delete? error ("hdl2struct: more than one colorbar found"); endif endif
--- a/scripts/plot/util/private/__gnuplot_draw_figure__.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/util/private/__gnuplot_draw_figure__.m Wed Jan 03 08:10:48 2018 -0800 @@ -49,11 +49,11 @@ type = get (kids(i), "type"); switch (type) case "axes" - if (strcmpi (get (kids (i), "tag"), "legend")) + if (strcmp (get (kids(i), "tag"), "legend")) ## This is so ugly. If there was a way of getting ## gnuplot to give us the text extents of strings ## then we could get rid of this mess. - lh = getappdata (kids(i), "handle"); + lh = getappdata (kids(i), "__axes_handle__"); if (isscalar (lh)) ## We have a legend with a single parent. It'll be handled ## below as a gnuplot key to the axis it corresponds to. @@ -155,19 +155,12 @@ endif ## Find if this axes has an associated legend axes and pass it ## to __gnuplot_draw_axes__ - hlegend = []; - fkids = get (h, "children"); - for j = 1 : numel (fkids) - if (ishghandle (fkids (j)) - && strcmp (get (fkids(j), {"type", "tag"}), - {"axes", "legend"})) - leghandle = getappdata (fkids(j), "handle"); - if (! isempty (intersect (leghandle, kids(i)))) - hlegend = get (fkids(j)); - break; - endif - endif - endfor + try + hlegend = get (kids(i), "__legend_handle__"); + hlegend = get (hlegend); + catch + hlegend = []; + end_try_catch __gnuplot_draw_axes__ (kids(i), plot_stream, enhanced, bg_is_set, fg_is_set, hlegend); unwind_protect_cleanup
--- a/scripts/plot/util/private/__gnuplot_print__.m Tue Jan 02 15:39:25 2018 -0800 +++ b/scripts/plot/util/private/__gnuplot_print__.m Wed Jan 03 08:10:48 2018 -0800 @@ -354,9 +354,7 @@ ## Do not change the text objects fontsizes for the children of a ## legend axes. These will be handled by the fontsize listener. is_legend_key_string = strcmp (get (hp, "tag"), "legend") ... - & isprop (hp, "string") ... - & isprop (hp, "location") ... - & strcmp (get (hp, "type"), "axes"); + & strcmp (get (hp, "type"), "axes"); h(is_legend_key_string) = []; fontsize = get (h, "fontsize"); switch (numel (fontsize))