changeset 16801:286904321282

Use unmodified axes "position" and "outerposition" properties for legend(). legend.m: Preserve parent axes' initial "positon" and "outerposition" values. Clear figure before each demo. Add demo. (Bug # 36408).
author Ben Abbott <bpabbott@mac.com>
date Sat, 22 Jun 2013 11:18:56 +0800
parents d749c9b588e5
children 56102c33122d
files scripts/plot/legend.m
diffstat 1 files changed, 145 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/plot/legend.m
+++ b/scripts/plot/legend.m
@@ -259,7 +259,7 @@
         str = tolower (strtrim (arg));
         switch (str)
           case "off"
-            delete (hlegend);
+            delete (hlegend)
             return;
           case "hide"
             show = "off";
@@ -420,8 +420,8 @@
     if (have_labels || ! have_dname)
       k = nkids;
       if (! have_labels)
-        varargin = arrayfun (@(x) sprintf ("data%d", x), [1:nkids]',
-          "uniformoutput", false);
+        varargin = arrayfun (@(x) sprintf ("data%d", x), [1:nkids]', 
+                             "uniformoutput", false);
         have_labels = true;
         nargs = nkids;
       endif
@@ -511,7 +511,7 @@
     if (isempty (hplots))
       if (! isempty (hlegend))
         fkids = get (fig, "children");
-        delete (fkids(fkids == hlegend));
+        delete_legend (fkids(fkids == hlegend));
         hlegend = [];
         hobjects = [];
         hplots  = [];
@@ -557,8 +557,16 @@
       unwind_protect
         set (ca(1), "units", "points");
         set (ca(1), "fontunits", "points");
-        ca_pos = get (ca(1), "position");
-        ca_outpos = get (ca(1), "outerposition");
+        if (isempty (hlegend) || ! isprop (hlegend, "unmodified_axes_position"))
+          unmodified_axes_position = get (ca(1), "position");
+          unmodified_axes_outerposition = get (ca(1), "outerposition");
+        else
+          unmodified_axes_position = get (hlegend, "unmodified_axes_position");
+          unmodified_axes_outerposition = get (hlegend, ...
+            "unmodified_axes_outerposition");
+        endif
+        ca_pos = unmodified_axes_position;
+        ca_outpos = unmodified_axes_outerposition;
         ca_fontsize = get (ca(1), "fontsize");
       unwind_protect_cleanup
         set (ca(1), "units", units);
@@ -569,7 +577,6 @@
       xpad = 2;
       ypad = 2;
 
-      ## Length of line segments in the legend in points
       linelength = 15;
 
       ## Create the axis first
@@ -663,12 +670,35 @@
         ystep = (ypad + maxheight);
         yoffset = ystep / 2;
 
-        ## Place the legend in the desired position
+        ## Place the legend in the desired location
         if (strcmp (orientation, "vertical"))
           lpos = [0, 0, num2 * xstep, num1 * ystep];
         else
           lpos = [0, 0, num1 * xstep, num2 * ystep];
         endif
+
+        if (strcmp (get (fig, "__graphics_toolkit__"), "gnuplot"))
+          ## Gnuplot places the key (legend) at edge of the figure window.
+          ## OpenGL places the legend box at edge of the unmodified axes
+          ## position.
+          if (isempty (strfind (location, "east")))
+            extra_offset = unmodified_axes_outerposition(1) ...
+                         + unmodified_axes_outerposition(3) ...
+                         - unmodified_axes_position(1) ...
+                         - unmodified_axes_position(3);
+          else
+            extra_offset = unmodified_axes_position(1) ...
+                         - unmodified_axes_outerposition(1);
+          endif
+          ## FIXME - the "fontsize" is added to match the behavior of OpenGL.
+          ## This implies that a change in fontsize should trigger a listener
+          ## to update the legend.  The "2" was determined using a long legend
+          ## key in the absence of any subplots.
+          extra_offset = extra_offset - 2 * fontsize;
+        else
+          extra_offset = 0;
+        endif
+
         switch (location)
           case "north"
             if (outside)
@@ -696,6 +726,7 @@
               lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - ypad, ...
                       ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
               new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ca_pos(4)];
+              new_pos(3) = new_pos(3) + extra_offset;
             else
               lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
                       ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
@@ -707,6 +738,8 @@
                       lpos(3), lpos(4)];
               new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ...
                          ca_pos(3) - lpos(3), ca_pos(4)];
+              new_pos(1) = new_pos(1) - extra_offset;
+              new_pos(3) = new_pos(3) + extra_offset;
             else
               lpos = [ca_pos(1) +  ypad, ...
                       ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
@@ -716,6 +749,7 @@
               lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - ypad, ...
                       ca_pos(2) + ca_pos(4) - lpos(4), lpos(3), lpos(4)];
               new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ca_pos(4)];
+              new_pos(3) = new_pos(3) + extra_offset;
             else
               lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
                       ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
@@ -726,6 +760,8 @@
                       lpos(3), lpos(4)];
               new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ...
                          ca_pos(3) - lpos(3), ca_pos(4)];
+              new_pos(1) = new_pos(1) - extra_offset;
+              new_pos(3) = new_pos(3) + extra_offset;
             else
               lpos = [ca_pos(1) + ypad, ...
                       ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
@@ -736,6 +772,7 @@
                       ca_pos(2), lpos(3), lpos(4)];
               new_pos = [ca_pos(1), ca_pos(2), ...
                          ca_pos(3) - lpos(3), ca_pos(4)];
+              new_pos(3) = new_pos(3) + extra_offset;
             else
               lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
                       ca_pos(2) + ypad, lpos(3), lpos(4)];
@@ -745,6 +782,8 @@
               lpos = [ca_outpos(1) + ypad, ca_pos(2), lpos(3), lpos(4)];
               new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ...
                          ca_pos(3) - lpos(3), ca_pos(4)];
+              new_pos(1) = new_pos(1) - extra_offset;
+              new_pos(3) = new_pos(3) + extra_offset;
             else
               lpos = [ca_pos(1) + ypad, ca_pos(2) + ypad, lpos(3), lpos(4)];
             endif
@@ -827,10 +866,29 @@
 
         ## Add an invisible text object to original axis
         ## that when it is destroyed will remove the legend
-        t1 = text (0, 0, "", "parent", ca(1), "tag", "legend",
-                   "handlevisibility", "off", "visible", "off",
-                   "xliminclude", "off", "yliminclude", "off");
-        set (t1, "deletefcn", {@deletelegend1, hlegend});
+        props = {"parent", ca(1), "tag", "legend", ...
+                 "handlevisibility", "off", "visible", "off", ...
+                 "xliminclude", "off", "yliminclude", "off"};
+        t1 = findall (ca(1), props{:}, "type", "text");
+        if (isempty (t1))
+          ht = findall (ca(1), "type", "text", props{3:end});
+          if (! isempty (ht))
+            set (ht, "deletefcn", "")
+            delete (ht);
+          endif
+          t1 = text (0, 0, "", props{:});
+          set (t1, "deletefcn", {@deletelegend1, hlegend});
+        endif
+        if (isprop (hlegend, "unmodified_axes_position"))
+          set (hlegend, "unmodified_axes_position", unmodified_axes_position)
+          set (hlegend, "unmodified_axes_outerposition", 
+               unmodified_axes_outerposition)
+        else
+          addproperty ("unmodified_axes_position", hlegend,
+                       "data", unmodified_axes_position);
+          addproperty ("unmodified_axes_outerposition", hlegend,
+                       "data", unmodified_axes_outerposition);
+        endif
 
         ## Resize the axis that the legend is attached to if the
         ## legend is "outside" the plot and create a listener to
@@ -848,9 +906,10 @@
           endfor
 
           set (hlegend, "deletefcn", {@deletelegend2, ca, ...
-                                      ca_pos, ca_outpos, t1, hplots});
+                                      unmodified_axes_position, ...
+                                      unmodified_axes_outerposition, t1, hplots});
           addlistener (hlegend, "visible", {@hideshowlegend, ca, ...
-                                            ca_pos, new_pos});
+                                            unmodified_axes_position, new_pos});
         else
           set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1, hplots});
         endif
@@ -858,7 +917,12 @@
         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");
+          locations = {"north", "south", "east", "west", "{northeast}", ...
+            "southeast", "northwest", "southwest", "northoutside", ...
+            "southoutside", "eastoutside", "westoutside", ...
+            "northeastoutside", "southeastoutside", "northwestoutside", ...
+            "southwestoutside"};
+          addproperty ("location", hlegend, "radio", strjoin (locations, "|"));
           addproperty ("orientation", hlegend, "radio",
                        "{vertical}|horizontal");
           addproperty ("string", hlegend, "any", text_strings);
@@ -906,6 +970,19 @@
     unwind_protect
       hax = getfield (get (h, "userdata"), "handle");
       [hplots, text_strings] = __getlegenddata__ (h);
+      position = get (h, "unmodified_axes_position");
+      outerposition = get (h, "unmodified_axes_outerposition");
+      units = get (hax, "units");
+      set (hax, "units", "points")
+      switch get (hax, "activepositionproperty")
+      case "position"
+        set (hax, "outerposition", outerposition)
+        set (hax, "position", position)
+      case "outerposition"
+        set (hax, "position", position)
+        set (hax, "outerposition", outerposition)
+      endswitch
+      set (hax, "units", units)
       h = legend (hax, hplots, get (h, "string"));
     unwind_protect_cleanup
       recursive = false;
@@ -1070,20 +1147,26 @@
 endfunction
 
 %!demo
+%! clf ()
 %! plot (rand (2));
 %! title ('legend called with cellstr and string inputs for labels');
 %! h = legend ({'foo'}, 'bar');
+%! legend location northeastoutside
 %! set (h, 'fontsize', 20)
 
 %!demo
+%! clf ()
 %! plot (rand (3));
 %! title ('legend() without inputs creates default labels');
-%! legend ();
+%! h = legend ();
 
 %!demo
 %! clf;
 %! x = 0:1;
 %! plot (x,x,';I am Blue;', x,2*x, x,3*x,';I am Red;');
+%! legend location northeastoutside
+%! # Placing legend inside should return axes to original size
+%! legend location northeast
 %! title ('Blue and Red keys, with Green missing');
 
 %!demo
@@ -1091,6 +1174,8 @@
 %! plot (1:10, 1:10, 1:10, fliplr (1:10));
 %! title ('incline is blue and decline is green');
 %! legend ({'I am blue', 'I am green'}, 'location', 'east');
+%! legend hide
+%! legend show
 
 %!demo
 %! clf;
@@ -1098,6 +1183,7 @@
 %! title ('Legend with keys in horizontal orientation');
 %! legend ({'I am blue', 'I am green'}, 'location', 'east', 'orientation', 'horizontal');
 %! legend boxoff;
+%! legend boxon
 
 %!demo
 %! clf;
@@ -1116,7 +1202,8 @@
 %!demo
 %! clf;
 %! plot (1:10, 1:10, 1:10, fliplr (1:10));
-%! title ('Using properties to have legend text shown to the right of key');
+%! title ({'Use properties to place legend text to the right of key', ...
+%!         'Legend text color is magenta'});
 %! h = legend ({'I am blue', 'I am green'}, 'location', 'east');
 %! legend ('left');
 %! set (h, 'textposition', 'right');
@@ -1133,7 +1220,8 @@
 %! clf;
 %! x = 0:1;
 %! plot (x,x,';I am Blue;', x,2*x,';I am Green;', x,3*x,';I am Red;');
-%! title ('labels embedded in call to plot');
+%! title ({'Labels are embedded in call to plot', ...
+%!         'Legend is hidden and then shown'});
 %! legend boxon
 %! legend hide
 %! legend show
@@ -1144,7 +1232,7 @@
 %! plot (x, x, ';\alpha;',  ...
 %!       x, 2*x, ';\beta=2\alpha;',  ...
 %!       x, 3*x, ';\gamma=3\alpha;');
-%! title ('labels with interpreted Greek text');
+%! title ('Labels with interpreted Greek text');
 
 %!demo
 %! clf;
@@ -1275,6 +1363,7 @@
 %! legend ('Hello', 'World', 'interpreter', 'foobar');
 
 %!demo
+%! clf;
 %! x = 0:10;
 %! y1 = rand (size (x));
 %! y2 = rand (size (x));
@@ -1283,6 +1372,7 @@
 %! legend ([h1, h2], {'Blue', 'Green'}, 'location', 'south');
 
 %!demo
+%! clf;
 %! x = 0:10;
 %! y1 = rand (size (x));
 %! y2 = rand (size (x));
@@ -1291,6 +1381,7 @@
 %! legend ({'Blue', 'Green'}, 'location', 'south');
 
 %!demo
+%! clf;
 %! x = 0:10;
 %! y1 = rand (size (x));
 %! y2 = rand (size (x));
@@ -1298,3 +1389,38 @@
 %! title ('plotyy legend test #3: Blue and Green labels');
 %! legend ('Blue', 'Green', 'location', 'south');
 
+%!demo % bug 36408
+%! clf;
+%! option = "right";
+%! subplot (3,1,1)
+%! plot (rand (1,4));
+%! title ("Subplots should adjust to the legend placed outside")
+%! legend ({"1"}, "location", "northeastoutside")
+%! legend (option)
+%! subplot (3,1,2)
+%! plot (rand (1,4));
+%! legend ({"1234567890"}, "location", "eastoutside")
+%! legend (option)
+%! subplot (3,1,3)
+%! plot (rand (1,4));
+%! legend ({"12345678901234567890"}, "location", "southeastoutside")
+%! legend (option)
+
+%!demo % bug 36408
+%! clf;
+%! option = "right";
+%! subplot (3,1,1)
+%! plot (rand (1,4));
+%! title ("Subplots should adjust to the legend placed outside")
+%! legend ({"1"}, "location", "northwestoutside")
+%! legend (option)
+%! subplot (3,1,2)
+%! plot (rand (1,4));
+%! legend ({"1234567890"}, "location", "westoutside")
+%! legend (option)
+%! subplot (3,1,3)
+%! plot (rand (1,4));
+%! legend ({"12345678901234567890"}, "location", "southwestoutside")
+%! legend (option)
+
+