# HG changeset patch # User David Bateman # Date 1284841841 -7200 # Node ID e81914f3921f6d8fe503be48f4f66120b59d1d14 # Parent 9e1270a84a101e93bf4da5bbafec91793a1dbffa Update legend code to support fltk (fixes #29348 and partially fixes #30461) diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,16 @@ +2010-09-18 David Bateman + + * plot/__go_draw_axes__.m: Modify legend code to use data from legend + axes. + * plot/__go_draw_figure__.m: Draw draw figure axes, but pass their + data to the axis they are associated with. + * plot/__get_plt_axes_arg__.m: Ignores axes tagged with "legend". + * plot/legend.m: Rewrite to use line and text primitives in a seperate + axis. + * plot/plot3.m: Support old legend format (eg "-;title'") with new + legend code. + * plot/private/__plt__.m: Ditto. + 2010-09-16 Ben Abbott * plot/__go_draw_axes__.m: Ensure text objects have units of "data". diff --git a/scripts/plot/__go_draw_axes__.m b/scripts/plot/__go_draw_axes__.m --- a/scripts/plot/__go_draw_axes__.m +++ b/scripts/plot/__go_draw_axes__.m @@ -23,7 +23,7 @@ ## Author: jwe -function __go_draw_axes__ (h, plot_stream, enhanced, mono, bg_is_set) +function __go_draw_axes__ (h, plot_stream, enhanced, mono, bg_is_set, hlegend) if (nargin >= 4 && nargin <= 6) @@ -31,6 +31,11 @@ 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 @@ -486,11 +491,10 @@ parametric(data_idx) = true; have_cdata(data_idx) = false; have_3d_patch(data_idx) = false; - - if (isempty (obj.keylabel)) + if (isempty (obj.displayname)) titlespec{data_idx} = "title \"\""; else - tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "keylabel")); + tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "displayname")); titlespec{data_idx} = cstrcat ("title \"", tmp, "\""); endif usingclause{data_idx} = sprintf ("record=%d", numel (obj.xdata)); @@ -606,10 +610,10 @@ have_3d_patch(data_idx) = false; endif - if (i > 1 || isempty (obj.keylabel)) + if (i > 1 || isempty (obj.displayname)) titlespec{local_idx} = "title \"\""; else - tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "keylabel")); + tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "displayname")); titlespec{local_idx} = cstrcat ("title \"", tmp, "\""); endif if (isfield (obj, "facecolor")) @@ -1028,10 +1032,11 @@ style = do_linestyle_command (obj, obj.edgecolor, data_idx, mono, plot_stream); - if (isempty (obj.keylabel)) + + if (isempty (obj.displayname)) titlespec{data_idx} = "title \"\""; else - tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "keylabel")); + tmp = undo_string_escapes (__maybe_munge_text__ (enhanced, obj, "displayname")); titlespec{data_idx} = cstrcat ("title \"", tmp, "\""); endif withclause{data_idx} = sprintf ("with pm3d linestyle %d", @@ -1351,7 +1356,7 @@ else if (nd == 3) fputs (plot_stream, "set border 895;\n"); - else + elseif (! isempty (axis_obj.ytick)) if (strcmpi (axis_obj.yaxislocation, "right")) fprintf (plot_stream, "unset ytics; set y2tics %s nomirror\n", axis_obj.tickdir); @@ -1386,19 +1391,30 @@ fprintf (plot_stream, "set border lw %f;\n", axis_obj.linewidth); endif - if (strcmpi (axis_obj.key, "on")) - if (strcmpi (axis_obj.keybox, "on")) + if (! isempty (hlgnd) + && any (strcmpi (get (get (hlegend, "children"), "visible"), "on"))) + hlgnd.box + hlgnd.orientation + hlgnd.textposition + hlgnd.location + + if (strcmpi (hlgnd.box, "on")) box = "box"; else box = "nobox"; endif - if (strcmpi (axis_obj.keyreverse, "on")) + if (strcmpi (hlgnd.orientation, "vertical")) + horzvert = "vertical"; + else + horzvert = "horizontal"; + endif + if (strcmpi (hlgnd.textposition, "right")) reverse = "reverse"; else reverse = "noreverse"; endif inout = "inside"; - keypos = axis_obj.keypos; + keypos = hlgnd.location; if (ischar (keypos)) keypos = lower (keypos); keyout = findstr (keypos, "outside"); @@ -1408,17 +1424,6 @@ endif endif switch (keypos) - case -1 - pos = "right top"; - inout = "outside"; - case 1 - pos = "right top"; - case 2 - pos = "left top"; - case 3 - pos = "left bottom"; - case {4, 0} - pos = "right bottom"; case "north" pos = "center top"; case "south" @@ -1444,16 +1449,15 @@ pos = ""; endswitch if (__gnuplot_has_feature__ ("key_has_font_properties")) - fontspec = create_fontspec (axis_obj.fontname, axis_obj.fontsize, gnuplot_term); + fontspec = create_fontspec (hlgnd.fontname, hlgnd.fontsize, gnuplot_term); else fontspec = ""; endif - fprintf (plot_stream, "set key %s %s %s %s %s;\n", inout, pos, box, - reverse, fontspec); + fprintf (plot_stream, "set key %s %s;\nset key %s %s %s %s;\n", + inout, pos, box, reverse, horzvert, fontspec); else fputs (plot_stream, "unset key;\n"); endif - fputs (plot_stream, "set style data lines;\n"); if (! use_gnuplot_for_images) diff --git a/scripts/plot/__go_draw_figure__.m b/scripts/plot/__go_draw_figure__.m --- a/scripts/plot/__go_draw_figure__.m +++ b/scripts/plot/__go_draw_figure__.m @@ -48,7 +48,12 @@ type = get (kids(i), "type"); switch (type) case "axes" - ## Rely upon listener to convert axes position to "normalized" units. + if (strcmpi (get (kids (i), "tag"), "legend")) + continue; + endif + + ## 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 @@ -63,9 +68,26 @@ if (bg_is_set) fprintf (plot_stream, "set border linecolor rgb \"#%02x%02x%02x\"\n", 255 * (1 - bg)); endif - ## Return axes "units" and "position" back to their original values. - __go_draw_axes__ (kids(i), plot_stream, enhanced, mono, bg_is_set); + ## 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 + 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; diff --git a/scripts/plot/__plt_get_axis_arg__.m b/scripts/plot/__plt_get_axis_arg__.m --- a/scripts/plot/__plt_get_axis_arg__.m +++ b/scripts/plot/__plt_get_axis_arg__.m @@ -40,7 +40,8 @@ && varargin{1}(1) != 0 && ! isfigure (varargin{1}(1))) tmp = varargin{1}; obj = get (tmp); - if (strcmp (obj.type, "axes") || strcmp (obj.type, "hggroup")) + if ((strcmp (obj.type, "axes") && ! strcmp (obj.tag, "legend")) + || strcmp (obj.type, "hggroup")) h = ancestor (tmp, "axes"); varargin(1) = []; if (isempty (varargin)) diff --git a/scripts/plot/legend.m b/scripts/plot/legend.m --- a/scripts/plot/legend.m +++ b/scripts/plot/legend.m @@ -1,5 +1,4 @@ -## Copyright (C) 2001, 2006, 2007, 2008, 2009 Laurent Mazet -## Copyright (C) 2006 John W. Eaton +## Copyright (C) 2010 David Bateman ## ## This file is part of Octave. ## @@ -22,6 +21,7 @@ ## @deftypefnx {Function File} {} legend (@var{matstr}) ## @deftypefnx {Function File} {} legend (@var{cell}) ## @deftypefnx {Function File} {} legend (@dots{}, "location", @var{pos}) +## @deftypefnx {Function File} {} legend (@dots{}, "orientation", @var{orient}) ## @deftypefnx {Function File} {} legend (@var{hax}, @dots{}) ## @deftypefnx {Function File} {} legend (@var{hobjs}, @dots{}) ## @deftypefnx {Function File} {} legend (@var{hax}, @var{hobjs}, @dots{}) @@ -70,6 +70,10 @@ ## can be appended to any location string ## @end multitable ## +## The optional parameter @var{orient} determines if the key elements +## are placed vertically or horizontally. The allowed values are "vertical" +## or "horizontal" with the default being "vertical". +## ## The following customizations are available using @var{option}: ## ## @table @asis @@ -94,25 +98,44 @@ ## @end table ## @end deftypefn -function legend (varargin) +function [hlegend2, hobjects2, hplot2, text_strings2] = legend (varargin) - [ca, varargin, nargin] = __plt_get_axis_arg__ ("legend", varargin{:}); - nargs = nargin; + if (! ishandle (varargin {1}) || (strcmp (get (varargin {1}, "type"), "axes") + && !strcmp (get (varargin {1}, "tag"), "legend"))) + [ca, varargin, nargs] = __plt_get_axis_arg__ ("legend", varargin{:}); + fig = get (ca, "parent"); + else + fig = get (0, "currentfigure"); + ca = get (fig, "currentaxes"); + endif if (all (ishandle (varargin{1}))) kids = flipud (varargin{1}(:)); varargin(1) = []; nargs = numel (varargin); else - kids = get (ca, "children"); + kids = ca; + kids (strcmp (get (ca, "tag"), "legend")) = []; + if (isscalar (kids)) + kids = get(kids, "children")(:); + else + kids = [get(kids, "children"){:}](:); + endif endif nkids = numel (kids); + orientation = "default"; + position = "default"; + show = "create"; + textpos = "default"; + box = "default"; + if (nargs > 0) pos = varargin{nargs}; if (isnumeric (pos) && isscalar (pos) && round (pos) == pos) if (pos >= -1 && pos <= 4) - set (ca, "keypos", pos); + position = {"northeastoutside", "best", "northeast", + "northwest", "southwest", "southeast"} (pos + 2); nargs--; else error ("legend: invalid position specified"); @@ -120,17 +143,59 @@ endif endif - if (nargs > 1) + while (nargs > 1) pos = varargin{nargs-1}; str = varargin{nargs}; if (strcmpi (pos, "location") && ischar (str)) - set (ca, "keypos", str); + position = lower (str); + nargs -= 2; + elseif (strcmpi (pos, "orientation") && ischar (str)) + orientation = lower (str); nargs -= 2; + else + break; endif + endwhile + + ## Validate the orientation + switch (orientation) + case {"vertical", "horizontal","default"} + otherwise + error ("legend: unrecognized legend orientation"); + endswitch + + ## Validate the position type is valid + outside = false; + inout = findstr (position, "outside"); + if (! isempty (inout)) + outside = true; + position = position(1:inout-1); + else + outside = false; endif - k = 1; - turn_on_legend = false; + switch (position) + case {"north", "south", "east", "west", "northeast", "northwest", ... + "southeast", "southwest", "default"} + case "best" + warning ("legend: 'Best' not yet implemented for location specifier\n"); + position = "northeast"; + otherwise + error ("legend: unrecognized legend position"); + endswitch + + hlegend = []; + fkids = get (fig, "children"); + for i = 1 : numel(fkids) + if (ishandle (fkids (i)) && strcmp (get (fkids (i), "type"), "axes") + && (strcmp (get (fkids (i), "tag"), "legend"))) + udata = get (fkids (i), "userdata"); + if (! isempty (intersect (udata.handle, ca))) + hlegend = fkids (i); + break; + endif + endif + endfor if (nargs == 1) arg = varargin{1}; @@ -139,30 +204,29 @@ str = tolower (deblank (arg)); switch (str) case {"off", "hide"} - set (ca, "key", "off"); + show = "off"; nargs--; case "show" - set (ca, "key", "on"); + show = "on"; nargs--; case "toggle" - val = get (ca, "key"); - if (strcmpi (val, "on")) - set (ca, "key", "off"); + if (isempty (hlegend) || strcmp (get (hlegend, "visible"), "off")) + show = "on"; else - set (ca, "key", "on"); + show = "off"; endif nargs--; case "boxon" - set (ca, "key", "on", "keybox", "on"); + box = "on"; nargs--; case "boxoff" - set (ca, "keybox", "off"); + box = "off"; nargs--; case "left" - set (ca, "keyreverse", "off") + textpos = "left"; nargs--; case "right" - set (ca, "keyreverse", "on") + textpos = "right"; nargs--; otherwise endswitch @@ -178,62 +242,572 @@ endif endif - if (nargs > 0) - have_data = false; - for k = 1:nkids - typ = get (kids(k), "type"); - if (strcmp (typ, "line") || strcmp (typ, "surface") - || strcmp (typ, "patch") || strcmp (typ, "hggroup")) - have_data = true; - break; + if (strcmp (show, "off")) + if (! isempty (hlegend)) + set (get (hlegend, "children"), "visible", "off"); + hlegend = []; + endif + hobjects = []; + hplots = []; + text_strings = {}; + elseif (strcmp (show, "on")) + if (! isempty (hlegend)) + set (get (hlegend, "children"), "visible", "on"); + else + hobjects = []; + hplots = []; + text_strings = {}; + endif + elseif (strcmp (box, "on")) + if (! isempty (hlegend)) + set (hlegend, "visible", "on", "box", "on"); + endif + elseif (strcmp (box, "off")) + if (! isempty (hlegend)) + set (hlegend, "box", "off", "visible", "off"); + endif + else + hobjects = []; + hplots = []; + text_strings = {}; + + if (nargs > 0) + have_data = false; + for k = 1:nkids + typ = get (kids(k), "type"); + if (strcmp (typ, "line") || strcmp (typ, "surface") + || strcmp (typ, "patch") || strcmp (typ, "hggroup")) + have_data = true; + break; + endif + endfor + + if (! have_data) + warning ("legend: plot data is empty; setting key labels has no effect"); + endif + endif + + if (strcmp (textpos, "default")) + warned = false; + k = nkids; + for i = 1 : nargs + arg = varargin{i}; + if (ischar (arg)) + 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")) + set (hgkids(j), "displayname", arg); + hplots = [hplots, hgkids(j)]; + text_strings = {text_strings{:}, arg}; + break; + endif + endfor + else + set (kids(k), "displayname", arg); + hplots = [hplots, kids(k)]; + text_strings = {text_strings{:}, arg}; + endif + + if (--k == 0) + break; + endif + elseif (! warned) + warned = true; + warning ("legend: ignoring extra labels"); + endif + else + error ("legend: expecting argument to be a character string"); + endif + endfor + else + k = nkids; + 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 + endif + + if (isempty (hplots)) + if (! isempty (hlegend)) + fkids = get (fig, "children"); + delete (fkids (fkids == hlegend)); + hlegend = []; + hobjects = []; + hplots = []; + text_strings = {}; + endif + else + ## Delete the old legend if it exists + if (! isempty (hlegend)) + if (strcmp (textpos, "default")) + textpos = get (hlegend, "textposition"); + endif + if (strcmp (position, "default")) + position = get (hlegend, "location"); + inout = findstr (position, "outside"); + if (! isempty (inout)) + outside = true; + position = position(1:inout-1); + else + outside = false; + endif + endif + if (strcmp (orientation, "default")) + orientation = get (hlegend, "orientation"); + endif + box = get (hlegend, "box"); + fkids = get (fig, "children"); + delete (fkids (fkids == hlegend)); + else + if (strcmp (textpos, "default")) + textpos = "left"; + endif + if (strcmp (position, "default")) + position = "northeast"; + endif + if (strcmp (orientation, "default")) + orientation = "vertical"; + endif + box = "off"; endif - endfor - if (! have_data) - warning ("legend: plot data is empty; setting key labels has no effect"); + + ## Force the figure to be drawn here, so that the figure position + ## is updated correctly before reading it + drawnow (); + + ## Get axis size and fontsize in points. + ## Rely on listener to handle coversion. + units = get (ca(1), "units"); + fontunits = get (ca(1), "fontunits"); + unwind_protect + set (ca(1), "units", "points"); + set (ca(1), "fontunits", "points"); + ca_pos = get (ca(1), "position"); + ca_outpos = get (ca(1), "outerposition"); + ca_fontsize = get (ca(1), "fontsize"); + unwind_protect_cleanup + set (ca(1), "units", units); + set (ca(1), "fontunits", fontunits); + end_unwind_protect + + ## Padding between legend entries horizontally and vertically + xpad = 2; + ypad = 2; + + ## Length of line segments in the legend in points + linelength = 15; + + ## Create the axis first + ## 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"); + + ## Add text label to the axis first, checking their extents + nentries = numel (hplots); + texthandle = []; + maxwidth = 0; + maxheight = 0; + for k = 1 : nentries + if (strcmp (textpos, "right")) + texthandle = [texthandle, text(0, 0, text_strings {k}, + "horizontalalignment", "left")]; + else + texthandle = [texthandle, text(0, 0, text_strings {k}, + "horizontalalignment", "right")]; + endif + units = get (texthandle (end), "units"); + unwind_protect + set (texthandle (end), "units", "points"); + extents = get (texthandle (end), "extent"); + maxwidth = max (maxwidth, extents (3)); + maxheight = max (maxheight, extents (4)); + unwind_protect_cleanup + set (texthandle (end), "units", units); + end_unwind_protect + endfor + + num1 = nentries; + if (strcmp (orientation, "vertical")) + height = nentries * (ypad + maxheight); + if (outside) + if (height > ca_pos (4)) + ## Avoid shrinking the height of the axis to zero if outside + num1 = ca_pos(4) / (maxheight + ypad) / 2; + endif + else + if (height > 0.9 * ca_pos (4)) + num1 = 0.9 * ca_pos(4) / (maxheight + ypad); + endif + endif + else + width = nentries * (ypad + maxwidth); + if (outside) + if (width > ca_pos (3)) + ## Avoid shrinking the width of the axis to zero if outside + num1 = ca_pos(3) / (maxwidth + ypad) / 2; + endif + else + if (width > 0.9 * ca_pos (3)) + num1 = 0.9 * ca_pos(3) / (maxwidth + ypad); + endif + endif + endif + num2 = ceil (nentries / num1); + + xstep = 3 * xpad + (maxwidth + linelength); + if (strcmp (textpos, "right")) + xoffset = xpad; + txoffset = 2 * xpad + linelength; + else + xoffset = 2 * xpad + maxwidth; + txoffset = xpad + maxwidth; + endif + ystep = (ypad + maxheight); + yoffset = ystep / 2; + + ## Place the legend in the desired position + if (strcmp (orientation, "vertical")) + lpos = [0, 0, num2 * xstep, num1 * ystep]; + else + lpos = [0, 0, num1 * xstep, num2 * ystep]; + endif + switch(position) + case "north" + if (outside) + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ... + ca_outpos(2) + ca_outpos(4) - lpos(4), lpos(3), lpos(4)]; + + new_pos = [ca_pos(1), ca_pos(2), ca_pos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2), ca_outpos(3), ... + ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ... + ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)]; + endif + case "south" + if (outside) + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ca_outpos(2), ... + lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2) + lpos(4), ca_pos(3), ... + ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2) + lpos(4), ... + ca_outpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ... + ca_pos(2) + ypad, lpos(3), lpos(4)]; + endif + case "east" + if (outside) + lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ... + 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_outpos = [ca_outpos(1), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4)]; + else + lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ... + ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)]; + endif + case "west" + if (outside) + lpos = [ca_outpos(1), ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, ... + lpos(3), lpos(4)]; + new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ... + ca_pos(3) - lpos(3), ca_pos(4)]; + new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4)]; + else + lpos = [ca_pos(1) + ypad, ... + ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)]; + endif + case "northeast" + if (outside) + lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ... + ca_outpos(2) + ca_outpos(4) - lpos(4), lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ... + ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ... + ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)]; + endif + case "northwest" + if (outside) + lpos = [ca_outpos(1), ca_outpos(2) + ca_outpos(4) - lpos(4), ... + lpos(3), lpos(4)]; + new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ... + ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ypad, ... + ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)]; + endif + case "southeast" + if (outside) + lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ca_outpos(2), + lpos(3), lpos(4)]; + new_pos = [ca_pos(1), ca_pos(2) + lpos(4), ... + ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1), ca_outpos(2) + lpos(4), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ... + ca_pos(2) + ypad, lpos(3), lpos(4)]; + endif + case "southwest" + if (outside) + lpos = [ca_outpos(1), ca_outpos(2), 0, lpos(3), lpos(4)]; + new_pos = [ca_pos(1) +lpos(3), ca_pos(2) + lpos(4), ... + ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)]; + new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2) + lpos(4), ... + ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)]; + else + lpos = [ca_pos(1) + ypad, ca_pos(2) + ypad, lpos(3), lpos(4)]; + endif + endswitch + + units = get (hlegend, "units"); + unwind_protect + set (hlegend, "units", "points"); + set (hlegend, "position", lpos, "outerposition", lpos); + unwind_protect_cleanup + set (hlegend, "units", units); + end_unwind_protect + + ## Now write the line segments and place the text objects correctly + xk = 0; + yk = 0; + for k = 1 : numel (hplots) + hobjects = [hobjects, texthandle (k)]; + color = get (hplots (k), "color"); + style = get (hplots (k), "linestyle"); + 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); + 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, + "markeredgecolor", get (hplots (k), "markeredgecolor"), + "markerfacecolor", get (hplots (k), "markerfacecolor"), + "markersize", get (hplots (k), "markersize")); + hobjects = [hobjects, l1]; + endif + set (texthandle (k), "position", [(txoffset + xk * xstep) / lpos(3), ... + (lpos(4) - yoffset - yk * ystep) / lpos(4)]); + + if (strcmp (orientation, "vertical")) + yk++; + if (yk > num1) + yk = 0; + xk++; + endif + else + xk++; + if (xk > num1) + xk = 0; + yk++; + endif + endif + endfor + + ## 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}); + + ## Resize the axis the legend is attached to if the + ## legend is "outside" the plot and create listener to + ## resize axis to original size if the legend is deleted, + ## hidden or shown + if (outside) + for i = 1 : numel (ca) + units = get (ca(i), "units"); + unwind_protect + set (ca(i), "units", "points"); + set (ca (i), "position", new_pos, "outerposition", new_outpos); + unwind_protect_cleanup + set (ca(i), "units", units); + end_unwind_protect + endfor + + set (hlegend, "deletefcn", {@deletelegend2, ca, ... + ca_pos, ca_outpos, t1}); + addlistener (hlegend, "visible", {@hideshowlegend, ca, ... + ca_pos, new_pos, ... + ca_outpos, new_outpos}); + else + set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1}); + 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 (outside) + set (hlegend, "location", strcat (position, "outside"), + "orientation", orientation, "textposition", textpos); + else + 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); + unwind_protect_cleanup + set (fig, "currentaxes", curaxes); + end_unwind_protect endif endif - warned = false; - k = nkids; - for i = 1:nargs - arg = varargin{i}; - if (ischar (arg)) - typ = get (kids(k), "type"); - while (k > 1 - && ! (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, "keylabel")) - set (hgkids(j), "keylabel", arg); - break; - endif - endfor + if (nargout > 0) + hlegend2 = hlegend2; + hobjects2 = hobjects; + hplot2 = hplots; + text_strings2 = text_strings; + endif + +endfunction + +function updatelegendtext (h, d) + kids = get (h, "children"); + k = numel (kids); + in = get (h, "interpreter"); + tc = get (h, "textcolor"); + while (k > 0) + typ = get (kids(k), "type"); + while (k > 0 && ! strcmp (typ, "text")) + typ = get (kids(--k), "type"); + endwhile + if (k > 0) + set (kids (k), "interpreter", in, "color", tc); + if (--k == 0) + break; + endif + endif + endwhile +endfunction + +function hideshowlegend (h, d, ca, pos1, pos2, outpos1, outpos2) + isvisible = strcmp (get (h, "visible"), "off"); + if (! isvisible) + kids = get (h, "children"); + for i = 1 : numel (kids) + if (! strcmp (get (kids(i), "visible"), "off")) + isvisible = true; + break; + endif + endfor + endif + + for i = 1 : numel (ca) + if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ca(i), "beingdeleted"), "off")) + units = get (ca(i), "units"); + unwind_protect + set (ca(i), "units", "points"); + if (isvisible) + set (ca(i), "position", pos2, "outerposition", outpos2); else - set (kids(k), "keylabel", arg); - endif - turn_on_legend = true; - if (--k == 0) - break; + set (ca(i), "position", pos1, "outerposition", outpos1); endif - elseif (! warned) - warned = true; - warning ("legend: ignoring extra labels"); - endif - else - error ("legend: expecting argument to be a character string"); + unwind_protect_cleanup + set (ca(i), "units", units); + end_unwind_protect endif endfor +endfunction - if (turn_on_legend) - set (ca, "key", "on"); +function deletelegend1 (h, d, ca) + if (ishandle (ca) && strcmp (get (ca, "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ca, "beingdeleted"), "off")) + delete (ca); endif +endfunction +function deletelegend2 (h, d, ca, pos, outpos, t1) + for i = 1 : numel (ca) + if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ca(i), "beingdeleted"), "off")) + if (!isempty (pos) && !isempty(outpos)) + units = get (ca(i), "units"); + unwind_protect + set (ca(i), "units", "points"); + set (ca(i), "position", pos, "outerposition", outpos, "deletefcn", ""); + unwind_protect_cleanup + set (ca(i), "units", units); + end_unwind_protect + endif + if (i == 1) + set (t1, "deletefcn", ""); + delete (t1); + endif + endif + endfor endfunction %!demo diff --git a/scripts/plot/plot3.m b/scripts/plot/plot3.m --- a/scripts/plot/plot3.m +++ b/scripts/plot/plot3.m @@ -95,7 +95,8 @@ property_set = 0; fmt_set = 0; properties = {}; - + tlgnd = {}; + hlgnd = []; idx = 0; ## Gather arguments, decode format, and plot lines. @@ -171,11 +172,6 @@ error ("plot3: x, y, and z must have the same shape"); endif - key = options.key; - if (! isempty (key)) - set (gca (), "key", "on"); - endif - for i = 1 : columns (x) linestyle = options.linestyle; marker = options.marker; @@ -183,13 +179,18 @@ [linestyle, marker] = __next_line_style__ (); endif color = options.color; - if (isempty (options.color)) + if (isempty (color)) color = __next_line_color__ (); endif - tmp(++idx) = line (x(:, i), y(:, i), z(:, i), "keylabel", key, + tmp(++idx) = line (x(:, i), y(:, i), z(:, i), "color", color, "linestyle", linestyle, "marker", marker, properties{:}); + key = options.key; + if (! isempty (key)) + hlgnd = [hlgnd, tmp(idx)]; + tlgnd = {tlgnd{:}, key}; + endif endfor x_set = 0; @@ -224,11 +225,6 @@ endif options = __default_plot_options__ (); - key = options.key; - if (! isempty (key)) - set (gca (), "key", "on"); - endif - for i = 1 : columns (x) linestyle = options.linestyle; marker = options.marker; @@ -240,9 +236,14 @@ color = __next_line_color__ (); endif - tmp(++idx) = line (x(:, i), y(:, i), z(:, i), "keylabel", key, + tmp(++idx) = line (x(:, i), y(:, i), z(:, i), "color", color, "linestyle", linestyle, "marker", marker, properties{:}); + key = options.key; + if (! isempty (key)) + hlgnd = [hlgnd, tmp(idx)]; + tlgnd = {tlgnd{:}, key}; + endif endfor x = new; @@ -296,10 +297,6 @@ endif options = __default_plot_options__ (); - key = options.key; - if (! isempty (key)) - set (gca (), "key", "on"); - endif for i = 1 : columns (x) linestyle = options.linestyle; @@ -312,12 +309,21 @@ color = __next_line_color__ (); endif - tmp(++idx) = line (x(:, i), y(:, i), z(:, i), "keylabel", key, + tmp(++idx) = line (x(:, i), y(:, i), z(:, i), "color", color, "linestyle", linestyle, "marker", marker, properties{:}); + key = options.key; + if (! isempty (key)) + hlgnd = [hlgnd, tmp(idx)]; + tlgnd = {tlgnd{:}, key}; + endif endfor endif + if (!isempty (hlgnd)) + legend (gca(), hlgnd, tlgnd); + endif + set (gca (), "view", [-37.5, 30]); if (nargout > 0 && idx > 0) diff --git a/scripts/plot/private/__plt__.m b/scripts/plot/private/__plt__.m --- a/scripts/plot/private/__plt__.m +++ b/scripts/plot/private/__plt__.m @@ -37,6 +37,9 @@ property_set = false; properties = {}; + hlgnd = []; + tlgnd = {}; + ## Gather arguments, decode format, gather plot strings, and plot lines. retval = []; @@ -77,10 +80,12 @@ endif if (y_set) tmp = __plt2__ (h, x, y, options, properties); + [hlgnd, tlgnd] = __plt_key__ (tmp, options); properties = {}; retval = [retval; tmp]; else tmp = __plt1__ (h, x, options, properties); + [hlgnd, tlgnd] = __plt_key__ (tmp, options); properties = {}; retval = [retval; tmp]; endif @@ -93,6 +98,7 @@ if (y_set) options = __pltopt__ (caller, {""}); tmp = __plt2__ (h, x, y, options, properties); + [hlgnd, tlgnd] = __plt_key__ (tmp, options); retval = [retval; tmp]; x = next_arg; y_set = false; @@ -108,12 +114,32 @@ endwhile + if (!isempty (hlgnd)) + legend (gca(), hlgnd, tlgnd); + endif else error ("__plt__: invalid number of arguments"); endif endfunction - + +function [hlgnd, tlgnd] = __plt_key__ (h, options) + hlgnd = []; + tlgnd = {}; + n = numel (h); + if (numel (options) == 1) + options = repmat (options(:), n, 1); + endif + + for i = 1 : n + key = options.key; + if (! isempty (key)) + hlgnd = [h(i), tmp(idx)]; + tlgnd = {tlgnd{:}, key}; + endif + endfor +endfunction + function retval = __plt1__ (h, x1, options, properties) if (nargin < 2 || nargin > 4) @@ -238,10 +264,6 @@ endif retval = zeros (x_nc, 1); for i = 1:x_nc - tkey = options(i).key; - if (! isempty (tkey)) - set (h, "key", "on"); - endif linestyle = options(i).linestyle; marker = options(i).marker; if (isempty (marker) && isempty (linestyle)) @@ -252,7 +274,7 @@ color = __next_line_color__ (); endif - retval(i) = line (x(:,i), y(:,i), "keylabel", tkey, "color", color, + retval(i) = line (x(:,i), y(:,i), "color", color, "linestyle", linestyle, "marker", marker, properties{:}); endfor @@ -306,10 +328,6 @@ endif retval = zeros (x_nc, 1); for i = 1:x_nc - tkey = options(i).key; - if (! isempty (tkey)) - set (h, "key", "on"); - endif linestyle = options(i).linestyle; marker = options(i).marker; if (isempty (marker) && isempty (linestyle)) @@ -320,7 +338,7 @@ color = __next_line_color__ (); endif - retval(i) = line (x(:,i), y, "keylabel", tkey, "color", color, + retval(i) = line (x(:,i), y, "color", color, "linestyle", linestyle, "marker", marker, properties{:}); endfor @@ -352,10 +370,6 @@ [y_nr, y_nc] = size (y); if (x_nr == 1 && x_nr == y_nr && x_nc == 1 && x_nc == y_nc) - key = options.key; - if (! isempty (key)) - set (h, "key", "on"); - endif linestyle = options.linestyle; marker = options.marker; if (isempty (marker) && isempty (linestyle)) @@ -366,7 +380,7 @@ color = __next_line_color__ (); endif - retval = line (x, y, "keylabel", key, "color", color, + retval = line (x, y, "color", color, "linestyle", linestyle, "marker", marker, properties{:}); else @@ -396,10 +410,6 @@ endif retval = zeros (len, 1); for i = 1:len - tkey = options(i).key; - if (! isempty (tkey)) - set (h, "key", "on"); - endif linestyle = options(i).linestyle; marker = options(i).marker; if (isempty (marker) && isempty (linestyle)) @@ -410,7 +420,7 @@ color = __next_line_color__ (); endif - retval(i) = line (x, y(i), "keylabel", tkey, "color", color, + retval(i) = line (x, y(i), "color", color, "linestyle", linestyle, "marker", marker, properties{:}); endfor @@ -461,10 +471,6 @@ endif retval = zeros (y_nc, 1); for i = 1:y_nc - tkey = options(i).key; - if (! isempty (tkey)) - set (h, "key", "on"); - endif linestyle = options(i).linestyle; marker = options(i).marker; if (isempty (marker) && isempty (linestyle)) @@ -475,7 +481,7 @@ color = __next_line_color__ (); endif - retval(i) = line (x, y(:,i), "keylabel", tkey, "color", color, + retval(i) = line (x, y(:,i), "color", color, "linestyle", linestyle, "marker", marker, properties{:}); endfor @@ -506,10 +512,6 @@ endif retval = zeros (len, 1); for i = 1:len - tkey = options(i).key; - if (! isempty (tkey)) - set (h, "key", "on"); - endif linestyle = options(i).linestyle; marker = options(i).marker; if (isempty (marker) && isempty (linestyle)) @@ -520,7 +522,7 @@ color = __next_line_color__ (); endif - retval(i) = line (x(i), y, "keylabel", tkey, "color", color, + retval(i) = line (x(i), y, "color", color, "linestyle", linestyle, "marker", marker, properties{:}); endfor @@ -566,10 +568,6 @@ endif if (x_nr == y_nr) - key = options.key; - if (! isempty (key)) - set (h, "key", "on"); - endif linestyle = options.linestyle; marker = options.marker; if (isempty (marker) && isempty (linestyle)) @@ -580,7 +578,7 @@ color = __next_line_color__ (); endif - retval = line (x, y, "keylabel", key, "color", color, + retval = line (x, y, "color", color, "linestyle", linestyle, "marker", marker, properties{:}); else diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2010-09-18 David Bateman + + * graphics.h.in: Remove properties for dead legend code. + 2010-09-18 Ben Abbott * graphics.cc: Replace pagetype property value custom with . diff --git a/src/graphics.cc b/src/graphics.cc --- a/src/graphics.cc +++ b/src/graphics.cc @@ -3316,10 +3316,6 @@ const std::string& mode) { box = "on"; - key = "off"; - keybox = "off"; - keyreverse = "off"; - keypos = 1.0; colororder = default_colororder (); dataaspectratio = Matrix (1, 3, 1.0); dataaspectratiomode = "auto"; diff --git a/src/graphics.h.in b/src/graphics.h.in --- a/src/graphics.h.in +++ b/src/graphics.h.in @@ -2950,10 +2950,6 @@ BEGIN_PROPERTIES (axes) array_property position u , default_axes_position () bool_property box , "on" - bool_property key , "off" - bool_property keybox , "off" - bool_property keyreverse , "off" - any_property keypos , 1 array_property colororder , default_colororder () array_property dataaspectratio m , Matrix (1, 3, 1.0) radio_property dataaspectratiomode , "{auto}|manual" @@ -3254,7 +3250,7 @@ // See the genprops.awk script for an explanation of the // properties declarations. - // properties which are not in matlab: keylabel, interpreter + // properties which are not in matlab: interpreter BEGIN_PROPERTIES (line) row_vector_property xdata u , default_data () @@ -3270,7 +3266,6 @@ color_property markeredgecolor , "{auto}|none" color_property markerfacecolor , "auto|{none}" double_property markersize , 6 - string_property keylabel , "" radio_property interpreter , "{tex}|none|latex" string_property displayname , "" radio_property erasemode , "{normal}|none|xor|background" @@ -3582,7 +3577,6 @@ color_property markeredgecolor , "{auto}|none|flat" color_property markerfacecolor , "auto|{none}|flat" double_property markersize , 6 - string_property keylabel , "" radio_property interpreter , "{tex}|none|latex" radio_property alphadatamapping l , "none|{scaled}|direct" // hidden properties for limit computation @@ -3688,7 +3682,6 @@ color_property markeredgecolor , "{auto}|none" color_property markerfacecolor , "auto|{none}" double_property markersize , 6 - string_property keylabel , "" radio_property interpreter , "{tex}|none|latex" array_property alphadata u , Matrix () radio_property alphadatamapping l , "none|direct|{scaled}"