Mercurial > hg > octave-nkf
diff scripts/plot/legend.m @ 11198:9f080d23396f
Fix multi-parented legends with the gnuplot backend (fixes #30461 and #31522)
author | David Bateman <dbateman@free.fr> |
---|---|
date | Sun, 07 Nov 2010 22:35:40 +0100 |
parents | fe3c3dfc07eb |
children | 91c606a68693 |
line wrap: on
line diff
--- a/scripts/plot/legend.m +++ b/scripts/plot/legend.m @@ -101,7 +101,7 @@ function [hlegend2, hobjects2, hplot2, text_strings2] = legend (varargin) if (! ishandle (varargin {1}) || (strcmp (get (varargin {1}, "type"), "axes") - && !strcmp (get (varargin {1}, "tag"), "legend"))) + && ! strcmp (get (varargin {1}, "tag"), "legend"))) [ca, varargin, nargs] = __plt_get_axis_arg__ ("legend", varargin{:}); fig = get (ca, "parent"); else @@ -109,6 +109,13 @@ ca = get (fig, "currentaxes"); endif + plty = get(ca (strcmp (get (ca, "tag"), "plotyy")), "userdata"); + if (isscalar (plty)) + ca = [ca, plty]; + else + ca = [ca, plty{:}]; + endif + if (all (ishandle (varargin{1}))) kids = flipud (varargin{1}(:)); varargin(1) = []; @@ -332,11 +339,15 @@ k = nkids; while (k > 0) typ = get (kids(k), "type"); - while (k > 0 + while (k > 1 && ! (strcmp (typ, "line") || strcmp (typ, "surface") || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) typ = get (kids(--k), "type"); endwhile + if (! (strcmp (typ, "line") || strcmp (typ, "surface") + || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) + break + endif if (k > 0) if (strcmp (get (kids(k), "type"), "hggroup")) hgkids = get (kids(k), "children"); @@ -392,7 +403,6 @@ endif box = get (hlegend, "box"); fkids = get (fig, "children"); - delete (fkids (fkids == hlegend)); else if (strcmp (textpos, "default")) textpos = "left"; @@ -436,13 +446,23 @@ ## FIXME hlegend should inherit properties from "ca" curaxes = get (fig, "currentaxes"); unwind_protect - hlegend = axes ("tag", "legend", "userdata", struct ("handle", ca), - "box", box, "outerposition", [0, 0, 0, 0], - "xtick", [], "ytick", [], "xticklabel", "", - "yticklabel", "", "zticklabel", "", - "xlim", [0, 1], "ylim", [0, 1], "visible", "off", - "activepositionproperty", "position"); - + ud = ancestor(hplots, "axes"); + if (!isscalar(ud)) + ud = unique ([ud{:}]); + endif + if (isempty (hlegend)) + addprops = true; + hlegend = axes ("tag", "legend", "userdata", struct ("handle", ud), + "box", box, "outerposition", [0, 0, 0, 0], + "xtick", [], "ytick", [], "xticklabel", "", + "yticklabel", "", "zticklabel", "", + "xlim", [0, 1], "ylim", [0, 1], "visible", "off", + "activepositionproperty", "position"); + else + addprops = false; + axes (hlegend); + delete (get (hlegend, "children")); + endif ## Add text label to the axis first, checking their extents nentries = numel (hplots); texthandle = []; @@ -451,10 +471,12 @@ for k = 1 : nentries if (strcmp (textpos, "right")) texthandle = [texthandle, text(0, 0, text_strings {k}, - "horizontalalignment", "left")]; + "horizontalalignment", "left", + "userdata", hplots(k))]; else texthandle = [texthandle, text(0, 0, text_strings {k}, - "horizontalalignment", "right")]; + "horizontalalignment", "right", + "userdata", hplots(k))]; endif units = get (texthandle (end), "units"); unwind_protect @@ -628,19 +650,29 @@ if (! strcmp (style, "none")) l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3), "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4), - "color", color, "linestyle", style); + "color", color, "linestyle", style, "marker", "none", + "userdata", hplots (k)); hobjects = [hobjects, l1]; endif marker = get (hplots(k), "marker"); if (! strcmp (marker, "none")) l1 = line ("xdata", (xoffset + 0.5 * linelength + xk * xstep) / lpos(3), "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4), - "color", color, "marker", marker, + "color", color, "linestyle", "none", "marker", marker, "markeredgecolor", get (hplots (k), "markeredgecolor"), "markerfacecolor", get (hplots (k), "markerfacecolor"), - "markersize", get (hplots (k), "markersize")); + "markersize", get (hplots (k), "markersize"), + "userdata", hplots (k)); hobjects = [hobjects, l1]; endif + + addlistener(hplots(k), "color", {@updateline, hlegend, linelength}); + addlistener(hplots(k), "linestyle", {@updateline, hlegend, linelength}); + addlistener(hplots(k), "marker", {@updateline, hlegend, linelength}); + addlistener(hplots(k), "markeredgecolor", {@updateline, hlegend, linelength}); + addlistener(hplots(k), "markerfacecolor", {@updateline, hlegend, linelength}); + addlistener(hplots(k), "markersize", {@updateline, hlegend, linelength}); + addlistener(hplots(k), "displayname", {@updateline, hlegend, linelength}); case "patch" case "surface" endswitch @@ -684,21 +716,25 @@ endfor set (hlegend, "deletefcn", {@deletelegend2, ca, ... - ca_pos, ca_outpos, t1}); + ca_pos, ca_outpos, t1, hplots}); addlistener (hlegend, "visible", {@hideshowlegend, ca, ... ca_pos, new_pos, ... ca_outpos, new_outpos}); else - set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1}); + set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1, hplots}); endif - addproperty ("edgecolor", hlegend, "color", [0, 0, 0]); - addproperty ("textcolor", hlegend, "color", [0, 0, 0]); - addproperty ("location", hlegend, "radio", "north|south|east|west|{northeast}|southeast|northwest|southwest|northoutside|southoutside|eastoutside|westoutside|northeastoutside|southeastoutside|northwestoutside|southwestoutside"); - - addproperty ("orientation", hlegend, "radio", "{vertical}|horizontal"); - addproperty ("string", hlegend, "any", text_strings); - addproperty ("textposition", hlegend, "radio", "{left}|right"); + if (addprops) + addproperty ("edgecolor", hlegend, "color", [0, 0, 0]); + addproperty ("textcolor", hlegend, "color", [0, 0, 0]); + addproperty ("location", hlegend, "radio", "north|south|east|west|{northeast}|southeast|northwest|southwest|northoutside|southoutside|eastoutside|westoutside|northeastoutside|southeastoutside|northwestoutside|southwestoutside"); + addproperty ("orientation", hlegend, "radio", + "{vertical}|horizontal"); + addproperty ("string", hlegend, "any", text_strings); + addproperty ("textposition", hlegend, "radio", "{left}|right"); + else + set (hlegend, "string", text_strings); + endif if (outside) set (hlegend, "location", strcat (position, "outside"), @@ -707,18 +743,15 @@ set (hlegend, "location", position, "orientation", orientation, "textposition", textpos); endif - - addlistener (hlegend, "edgecolor", @updatelegendtext); - addlistener (hlegend, "textcolor", @updatelegendtext); - addlistener (hlegend, "interpreter", @updatelegendtext); - - ## FIXME The listener function for these essentially has to - ## replace the legend with a new one. For now they are just - ## to stock the initial values (for the gnuplot backend) - ##addlistener (hlegend, "location", @updatelegend); - ##addlistener (hlegend, "orientation", @updatelegend); - ##addlistener (hlegend, "string", @updatelegend); - ##addlistener (hlegend, "textposition", @updatelegend); + if (addprops) + addlistener (hlegend, "edgecolor", @updatelegendtext); + addlistener (hlegend, "textcolor", @updatelegendtext); + addlistener (hlegend, "interpreter", @updatelegendtext); + addlistener (hlegend, "location", @updatelegend); + addlistener (hlegend, "orientation", @updatelegend); + addlistener (hlegend, "string", @updatelegend); + addlistener (hlegend, "textposition", @updatelegend); + endif unwind_protect_cleanup set (fig, "currentaxes", curaxes); end_unwind_protect @@ -734,6 +767,16 @@ endfunction +function updatelegend (h, d) + persistent recursive = false; + if (! recursive) + recursive = true; + [hplots, text_strings] = getlegenddata (h); + h = legend (fliplr (hplots), get (h, "string")); + recursive = false; + endif +endfunction + function updatelegendtext (h, d) kids = get (h, "children"); k = numel (kids); @@ -792,7 +835,7 @@ endif endfunction -function deletelegend2 (h, d, ca, pos, outpos, t1) +function deletelegend2 (h, d, ca, pos, outpos, t1, hplots) for i = 1 : numel (ca) if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") && (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) @@ -806,12 +849,136 @@ set (ca(i), "units", units); end_unwind_protect endif - if (i == 1) - set (t1, "deletefcn", ""); - delete (t1); + endif + endfor + set (t1, "deletefcn", ""); + delete (t1); + for i = 1 : numel (hplots) + if (strcmp (get (hplots (i), "type"), "line")) + dellistener (hplots (i), "color"); + dellistener (hplots (i), "linestyle"); + dellistener (hplots (i), "marker"); + dellistener (hplots (i), "markeredgecolor"); + dellistener (hplots (i), "markerfacecolor"); + dellistener (hplots (i), "markersize"); + dellistener (hplots (i), "displayname"); + endif + endfor +endfunction + +function updateline (h, d, hlegend, linelength) + lm = []; + ll = []; + kids = get (hlegend, "children"); + for i = 1 : numel (kids) + if (get (kids (i), "userdata") == h + && strcmp (get (kids(i), "type"), "line")) + if (strcmp (get (kids (i), "marker"), "none")) + ll = kids (i); + else + lm = kids (i); endif endif endfor + + linestyle = get (h, "linestyle"); + marker = get (h, "marker"); + displayname = get (h, "displayname"); + + if ((isempty (displayname) + || (strcmp (marker, "none") && strcmp (linestyle, "none"))) + && (! isempty (lm) || isempty (ll))) + ## An element was removed from the legend. Need to recall the + ## legend function to recreate a new legend + [hplots, text_strings] = getlegenddata (hlegend); + for i = 1 : numel (hplots) + if (hplots (i) == h) + hplots(i) = []; + text_strings(i) = []; + break; + endif + endfor + legend (hplots, text_strings); + elseif ((!isempty (displayname) + && (! strcmp (marker, "none") || ! strcmp (linestyle, "none"))) + && isempty (lm) && isempty (ll)) + ## An element was added to the legend. Need to recall the + ## legend function to recreate a new legend + [hplots, text_strings] = getlegenddata (hlegend); + hplots = [hplots, h]; + text_strings = {text_strings{:}, displayname}; + legend (hplots, text_strings); + else + if (! isempty (ll)) + ypos1 = get (ll,"ydata"); + xpos1 = get (ll,"xdata"); + ypos2 = ypos1(1); + xpos2 = sum(xpos1) / 2; + delete (ll); + if (! isempty (lm)) + delete (lm); + endif + else + ypos2 = get (lm,"ydata"); + xpos2 = get (lm,"xdata"); + ypos1 = [ypos2, ypos2]; + xpos1 = xpos2 + [-0.5, 0.5] * linelength; + delete (lm); + endif + if (! strcmp (linestyle, "none")) + line ("xdata", xpos1, "ydata", ypos1, "color", get (h, "color"), + "linestyle", get (h, "linestyle"), "marker", "none", + "userdata", h, "parent", hlegend); + endif + if (! strcmp (marker, "none")) + line ("xdata", xpos2, "ydata", ypos2, "color", get (h, "color"), + "marker", marker, "markeredgecolor", get (h, "markeredgecolor"), + "markerfacecolor", get (h, "markerfacecolor"), + "markersize", get (h, "markersize"), "linestyle", "none", + "userdata", h, "parent", hlegend); + endif + endif +endfunction + +function [hplots, text_strings] = getlegenddata (hlegend) + hplots = []; + text_strings = {}; + ca = getfield (get (hlegend, "userdata"), "handle"); + kids = []; + for i = 1 : numel (ca) + kids = [kids; get(ca (i), "children")]; + endfor + k = numel (kids); + while (k > 0) + typ = get (kids(k), "type"); + while (k > 0 + && ! (strcmp (typ, "line") || strcmp (typ, "surface") + || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) + typ = get (kids(--k), "type"); + endwhile + if (k > 0) + if (strcmp (get (kids(k), "type"), "hggroup")) + hgkids = get (kids(k), "children"); + for j = 1 : length (hgkids) + hgobj = get (hgkids (j)); + if (isfield (hgobj, "displayname") + && ! isempty (hgobj.displayname)) + hplots = [hplots, hgkids(j)]; + text_strings = {text_strings{:}, hbobj.displayname}; + break; + endif + endfor + else + if (! isempty (get (kids (k), "displayname"))) + hplots = [hplots, kids(k)]; + text_strings = {text_strings{:}, get(kids (k), "displayname")}; + endif + endif + if (--k == 0) + break; + endif + endif + endwhile endfunction %!demo