changeset 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 836427db633b
children 91c606a68693
files scripts/ChangeLog scripts/plot/__go_draw_axes__.m scripts/plot/__go_draw_figure__.m scripts/plot/gnuplot_drawnow.m scripts/plot/legend.m scripts/plot/plotyy.m scripts/plot/private/__contour__.m
diffstat 7 files changed, 358 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/ChangeLog	Sun Nov 07 22:35:40 2010 +0100
@@ -1,3 +1,18 @@
+2010-11-07  David Bateman  <dbateman@free.fr>
+
+	* plot/__go_draw_axes__.m: Pass the legend axes as a structure.
+	Test whether the legend axis has any children before using it.
+	* plot/__go_draw_figure.m: Setup a fake axis to handle multi-parent
+	legend axes and delete this fake axiss when we're done with it.
+	* plot/gnuplot_drawnow.m: Don't cound legend axes when decidong if
+	multiplot should be used or not.
+	* plot/legend.m: Handle correctly plotyy as a multi-parented axis.
+	Reuse existing legend axis if possible. Setup listeners to propagate
+	changes in the lines to the legend. Setup listeners that handle the
+	properties that need to legend to be recreated.
+	* plot/plotyy.m: Cross-references the axes of the plotyy in the userdata
+	of the axes.
+
 2010-11-07  Konstantinos Poulios  <logari81@googlemail.com>
 
 	* plot/colorbar.m: Make colorbar function aware of dataaspect settings.
--- a/scripts/plot/__go_draw_axes__.m	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/plot/__go_draw_axes__.m	Sun Nov 07 22:35:40 2010 +0100
@@ -23,7 +23,7 @@
 
 ## Author: jwe
 
-function __go_draw_axes__ (h, plot_stream, enhanced, mono, bg_is_set, hlegend)
+function __go_draw_axes__ (h, plot_stream, enhanced, mono, bg_is_set, hlgnd)
 
   if (nargin >= 4 && nargin <= 6)
 
@@ -31,11 +31,6 @@
     unwind_protect
       set (0, "showhiddenhandles", "on");
       axis_obj = __get__ (h);
-      if (isempty (hlegend))
-        hlgnd = [];
-      else
-        hlgnd = __get__ (hlegend);
-      endif
     unwind_protect_cleanup
       set (0, "showhiddenhandles", showhiddenhandles);
     end_unwind_protect
@@ -1391,8 +1386,8 @@
       fprintf (plot_stream, "set border lw %f;\n", axis_obj.linewidth);
     endif
 
-    if (! isempty (hlgnd) 
-        && any (strcmpi (get (get (hlegend, "children"), "visible"), "on")))
+    if (! isempty (hlgnd) && ! isempty (hlgnd.children)
+        && any (strcmpi (get (hlgnd.children, "visible"), "on")))
       if (strcmpi (hlgnd.box, "on"))
         box = "box";
       else
--- a/scripts/plot/__go_draw_figure__.m	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/plot/__go_draw_figure__.m	Sun Nov 07 22:35:40 2010 +0100
@@ -44,57 +44,139 @@
         else
           bg_is_set = false;
         endif
+
         for i = nkids:-1:1
           type = get (kids(i), "type");
           switch (type)
             case "axes"
               if (strcmpi (get (kids (i), "tag"), "legend"))
-                continue;
-              endif
+                ## 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 = getfield (get (kids(i), "userdata"), "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
+                  continue;
+                else
+                  ca = lh(1);
+                  ## Rely upon listener to convert axes position 
+                  ## to "normalized" units.
+                  legend_axes_units = get (kids(i), "units");
+                  legend_axes_position = get (kids(i), "position");
+                  legend_axes_outerposition = get (kids(i), "outerposition");
+                  legend_axes_box = get (kids(i), "box");
+                  legend_axes_ylim = get (kids(i), "ylim");
+                  orig_axes_units = get (ca, "units");
+                  hlgnd = get (kids(i));
+
+                  unwind_protect
+                    set (ca, "units", "normalized");
+                    set (kids(i), "units", "normalized", "box", "off", 
+                         "ylim", [-2, -1], "position", get (ca(1), "position"),
+                         "outerposition", get (ca(1), "outerposition"));
 
-              ## Rely upon listener to convert axes position 
-              ## to "normalized" units.
-              orig_axes_units = get (kids(i), "units");
-              orig_axes_position = get (kids(i), "position");
-              unwind_protect
-                set (kids(i), "units", "normalized");
-                fg = get (kids(i), "color");
-                if (isnumeric (fg) && strcmp (get (kids(i), "visible"), "on"))
-                  fprintf (plot_stream, "set obj 2 rectangle from graph 0,0 to graph 1,1 behind fc rgb \"#%02x%02x%02x\"\n", 255 * fg);
-                  fg_is_set = true;
-                else
-                  fg_is_set = false;
-                endif
-                if (bg_is_set)
-                  fprintf (plot_stream, "set border linecolor rgb \"#%02x%02x%02x\"\n", 255 * (1 - bg));
+                    ## Create a new set of lines with the appropriate 
+                    ## displaynames, etc
+                    toberm = [];
+                    hobj = get (kids(i), "children");
+                    for j = numel (hobj) : -1 : 1
+                      if (! strcmp (get (hobj(j), "type"), "text"))
+                        continue;
+                      endif
+                      displayname = get (hobj(j), "string");
+                      ll = [];
+                      lm = [];
+                      for k = numel (hobj) : -1 : 1
+                        if (! strcmp (get (hobj(k), "type"), "line"))
+                          continue;
+                        endif
+                        if (get (hobj(j), "userdata") 
+                            != get (hobj(k), "userdata"))
+                          continue;
+                        endif
+                        if (! strcmp (get (hobj(k), "linestyle"), "none"))
+                          ll = hobj(k);
+                        endif
+                        if (! strcmp (get (hobj(k), "marker"), "none"))
+                          lm = hobj(k);
+                        endif
+                      endfor
+
+                      if (! isempty (ll))
+                        if (!isempty (lm))
+                          toberm = [toberm, line("xdata",[0,0],"ydata",[0,0], "color", get(lm,"color"), "linestyle", get(ll,"linestyle"), "marker", get(lm,"marker"), "markeredgecolor", get(lm,"markeredgecolor"), "markerfacecolor", get(lm,"markerfacecolor"), "markersize", get (lm, "markersize"), "displayname", displayname, "parent", kids(i))];
+                        else
+                          toberm = [toberm, line("xdata",[0,0],"ydata",[0,0], "color", get(ll,"color"), "linestyle", get(ll,"linestyle"), "marker", "none", "displayname", displayname, "parent", kids(i))];
+                        endif
+                      elseif (! isempty (lm))
+                        toberm = [toberm, line("xdata",[0,0],"ydata",[0,0], "color", get(lm,"color"), "linestyle", "none", "marker", get(lm,"marker"), "markeredgecolor", get(lm,"markeredgecolor"), "markerfacecolor", get(lm,"markerfacecolor"), "markersize", get (lm, "markersize"), "displayname", displayname, "parent", kids(i))];
+                      endif
+                    endfor
+                    if (bg_is_set)
+                      fprintf (plot_stream, "set border linecolor rgb \"#%02x%02x%02x\"\n", 255 * (1 - bg));
+                    endif
+                    __go_draw_axes__ (kids(i), plot_stream, enhanced, mono,
+                                      bg_is_set, hlgnd);
+                  unwind_protect_cleanup
+                    ## Return axes "units" and "position" back to
+                    ## their original values.
+                    set (ca, "units", orig_axes_units);
+                    set (kids(i), "units", legend_axes_units, 
+                         "box", legend_axes_box, 
+                         "ylim", legend_axes_ylim, 
+                         "position", legend_axes_position,
+                         "outerposition", legend_axes_outerposition);
+                    delete (toberm);
+                    bg_is_set = false;
+                  end_unwind_protect
                 endif
-                ## Find if this axes has an associated legend axes and pass it
-                ## to __go_draw_axes__
-                hlegend = [];
-                fkids = get (h, "children");
-                for j = 1 : numel(fkids)
-                  if (ishandle (fkids (j)) 
-                      && strcmp (get (fkids (j), "type"), "axes") 
-                      && (strcmp (get (fkids (j), "tag"), "legend")))
-                    udata = get (fkids (j), "userdata");
-                    if (! isempty (intersect (udata.handle, kids (i))))
-                      hlegend = fkids (j);
-                      break;
-                    endif
+              else
+                ## Rely upon listener to convert axes position 
+                ## to "normalized" units.
+                orig_axes_units = get (kids(i), "units");
+                orig_axes_position = get (kids(i), "position");
+                unwind_protect
+                  set (kids(i), "units", "normalized");
+                  fg = get (kids(i), "color");
+                  if (isnumeric (fg) && strcmp (get (kids(i), "visible"), "on"))
+                    fprintf (plot_stream, "set obj 2 rectangle from graph 0,0 to graph 1,1 behind fc rgb \"#%02x%02x%02x\"\n", 255 * fg);
+                    fg_is_set = true;
+                  else
+                    fg_is_set = false;
+                  endif
+                  if (bg_is_set)
+                    fprintf (plot_stream, "set border linecolor rgb \"#%02x%02x%02x\"\n", 255 * (1 - bg));
                   endif
-                endfor
-                __go_draw_axes__ (kids(i), plot_stream, enhanced, mono,
-                                  bg_is_set, hlegend);
-              unwind_protect_cleanup
-                ## Return axes "units" and "position" back to
-                ## their original values.
-                set (kids(i), "units", orig_axes_units);
-                set (kids(i), "position", orig_axes_position);
-                bg_is_set = false;
-                if (fg_is_set)
-                  fputs (plot_stream, "unset obj 2\n");
-                endif
-              end_unwind_protect
+                  ## Find if this axes has an associated legend axes and pass it
+                  ## to __go_draw_axes__
+                  hlegend = [];
+                  fkids = get (h, "children");
+                  for j = 1 : numel(fkids)
+                    if (ishandle (fkids (j)) 
+                        && strcmp (get (fkids (j), "type"), "axes") 
+                        && (strcmp (get (fkids (j), "tag"), "legend")))
+                      udata = get (fkids (j), "userdata");
+                      if (isscalar(udata.handle) 
+                          && ! isempty (intersect (udata.handle, kids (i))))
+                        hlegend = get (fkids (j));
+                        break;
+                      endif
+                    endif
+                  endfor
+                  __go_draw_axes__ (kids(i), plot_stream, enhanced, mono,
+                                    bg_is_set, hlegend);
+                unwind_protect_cleanup
+                  ## Return axes "units" and "position" back to
+                  ## their original values.
+                  set (kids(i), "units", orig_axes_units);
+                  set (kids(i), "position", orig_axes_position);
+                  bg_is_set = false;
+                  if (fg_is_set)
+                    fputs (plot_stream, "unset obj 2\n");
+                  endif
+                end_unwind_protect
+              endif
             case "uimenu"
               ## ignore uimenu objects
             otherwise
--- a/scripts/plot/gnuplot_drawnow.m	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/plot/gnuplot_drawnow.m	Sun Nov 07 22:35:40 2010 +0100
@@ -302,7 +302,8 @@
     fputs (plot_stream, "unset multiplot;\n");
     flickering_terms = {"x11", "windows", "wxt", "dumb"};
     if (! any (strcmp (term, flickering_terms))
-        || numel (findall (h, "type", "axes")) > 1
+        || (numel (findall (h, "type", "axes")) -
+            sum (strcmp (get (findall (h, "type", "axes"), "tag"), "legend"))) > 1
         || numel (findall (h, "type", "image")) > 0)
       fprintf (plot_stream, "%s\n", term_str);
       if (nargin == 5)
--- a/scripts/plot/legend.m	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/plot/legend.m	Sun Nov 07 22:35:40 2010 +0100
@@ -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
--- a/scripts/plot/plotyy.m	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/plot/plotyy.m	Sun Nov 07 22:35:40 2010 +0100
@@ -194,6 +194,10 @@
   ## not to mirror the y axis tick marks
   set (ax, "tag", "plotyy")
 
+  ## Cross-reference one axis to the other in the userdata
+  set (ax(1), "userdata", ax(2));
+  set (ax(2), "userdata", ax(1));
+
   ## Store the axes handles for the sister axes.
   try 
     addproperty ("__plotyy_axes__", ax(1), "data", ax);
--- a/scripts/plot/private/__contour__.m	Sun Nov 07 11:51:36 2010 +0100
+++ b/scripts/plot/private/__contour__.m	Sun Nov 07 22:35:40 2010 +0100
@@ -520,9 +520,9 @@
                       get (h, "labelspacing"), []);
       endswitch
     endif
+
+    recursive = false;
   endif
-
-  recursive = false;
 endfunction
 
 function lvl_eps = get_lvl_eps (lev)