# HG changeset patch # User John W. Eaton # Date 1223651273 14400 # Node ID f6ca8ff518181e2aa4db7762911a219bcd22e348 # Parent 60b4c75287a13ed3a16e414c466802c2549ba93c [mq]: graphics-backend diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,25 @@ +2008-10-10 David Bateman + + * image/__img__.m: Manually set the limits of th eimage + * plot/__go_draw_axes__.m: Base window position in the axis + position property and not the outerposition property. Remove + colorbar code based on the gnuplot colorbox. Allow images to be a + vector to support image based colorbars. Also check labelmode for + manual tics. + * plot/__go_draw_figure__.m: Remove gnuplot colorbox based + colorbar code. + * plot/colorbar.m: Rewrite to use an image and callbacks to link + it to the principal axis. + * plot/legend.m: Support an axis handle as the first + argument. Support hggroups. + * plot/pareto.m: Don't support an axis handle as the first + argument as the plotyy command in fact needs two axis handles. + * plot/plotyy.m: Rewrite to use listeners and callbacks to + synchronize the two axes. + * plot/subplot.m: Also skip axes that are tagged as being a + colorbar. Don't break in search of overlapping axes to delete. Set + both the position and the outerposition. + 2008-10-09 Ben Abbott * plot/__axis_label__.m: Inherit font properties from axes. diff --git a/scripts/image/__img__.m b/scripts/image/__img__.m --- a/scripts/image/__img__.m +++ b/scripts/image/__img__.m @@ -65,7 +65,8 @@ endif endif - set (ca, "view", [0, 90]); + set (ca, "view", [0, 90], "xlimmode", "manual", "ylimmode", "manual", + "xlim", xlim, "ylim", ylim); if (strcmp (get (ca, "nextplot"), "replace")) set (ca, "ydir", "reverse"); 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 @@ -28,27 +28,17 @@ parent_figure_obj = get (axis_obj.parent); - ## Set axis properties here? - pos = [0, 0, 1, 1]; - if (strcmpi (axis_obj.activepositionproperty, "outerposition")) - ymirror = true; - if (! isempty (axis_obj.outerposition)) - pos = axis_obj.outerposition; - endif - else + pos = axis_obj.position; + fprintf (plot_stream, "set tmargin 0;\n"); + fprintf (plot_stream, "set bmargin 0;\n"); + fprintf (plot_stream, "set lmargin 0;\n"); + fprintf (plot_stream, "set rmargin 0;\n"); + + ## Set to false for plotyy axes. + if (strcmp (axis_obj.tag, "plotyy")) ymirror = false; - if (! isempty (axis_obj.position)) - pos = axis_obj.position; - fprintf (plot_stream, "set tmargin 0;\n"); - fprintf (plot_stream, "set bmargin 0;\n"); - fprintf (plot_stream, "set lmargin 0;\n"); - fprintf (plot_stream, "set rmargin 0;\n"); - endif - endif - - if (! strcmpi (get (h, "__colorbar__"), "none")) - [pos, cbox_orient, cbox_size, cbox_origin, cbox_mirror] = ... - gnuplot_position_colorbox (pos, get (h, "__colorbar__"), axis_obj); + else + ymirror = true; endif fprintf (plot_stream, "set origin %.15g, %.15g;\n", pos(1), pos(2)); @@ -342,12 +332,16 @@ if (x_dim > 1) dx = abs (img_xdata(2)-img_xdata(1))/(x_dim-1); else - dx = 1; + x_dim = 2; + img_data = [img_data, img_data]; + dx = abs (img_xdata(2)-img_xdata(1)); endif if (y_dim > 1) dy = abs (img_ydata(2)-img_ydata(1))/(y_dim-1); else - dy = 1; + y_dim = 2; + img_data = [img_data; img_data]; + dy = abs (img_ydata(2)-img_ydata(1)); endif x_origin = min (img_xdata); y_origin = min (img_ydata); @@ -962,6 +956,8 @@ have_data = (! (isempty (data) || all (cellfun (@isempty, data)))); + ## Note we don't use the [xy]2range of gnuplot as we don't use the + ## dual axis plotting features of gnuplot if (isempty (xlim)) return; endif @@ -970,8 +966,7 @@ else xdir = "noreverse"; endif - fprintf (plot_stream, "set %srange [%.15e:%.15e] %s;\n", - xaxisloc, xlim, xdir); + fprintf (plot_stream, "set xrange [%.15e:%.15e] %s;\n", xlim, xdir); if (isempty (ylim)) return; @@ -981,8 +976,7 @@ else ydir = "noreverse"; endif - fprintf (plot_stream, "set %srange [%.15e:%.15e] %s;\n", - yaxisloc, ylim, ydir); + fprintf (plot_stream, "set yrange [%.15e:%.15e] %s;\n", ylim, ydir); if (nd == 3) if (isempty (zlim)) @@ -1126,16 +1120,8 @@ fwrite (plot_stream, [1:cmap_sz; cmap.'], "float32"); fwrite (plot_stream, "\n"); endif - - if (strcmpi (get (h, "__colorbar__"), "none")) - fputs (plot_stream, "unset colorbox;\n"); - else - ## FIXME If cbox_mirror is true we want to invert the tic labels - ## but gnuplot doesn't allow that - fputs (plot_stream, - sprintf ("set colorbox %s user origin %f,%f size %f,%f;\n", - cbox_orient, cbox_origin, cbox_size)); - endif + + fputs (plot_stream, "unset colorbox;\n"); if (have_data) if (nd == 2) @@ -1491,8 +1477,8 @@ else fprintf (plot_stream, "set format %s \"%%g\";\n", ax); if (mirror) - fprintf (plot_stream, "set %stics %s %s %s;\n", ax, axispos, tickdir, - colorspec); + fprintf (plot_stream, "set %stics %s %s mirror %s;\n", ax, + axispos, tickdir, colorspec); else fprintf (plot_stream, "set %stics %s %s nomirror %s;\n", ax, tickdir, axispos, colorspec); @@ -1871,105 +1857,6 @@ sym.int = '{/Symbol \362}'; endfunction -function [pos, orient, sz, origin, mirr] = gnuplot_position_colorbox (pos, cbox, obj) - ## This is an emprically derived function that attempts to find a good - ## size for the colorbox even for subplots and strange aspect ratios. - - if (strncmp (cbox, "north", 5) || strncmp (cbox, "south", 5)) - scl = pos([2,4]); - else - scl = pos([1,3]); - endif - - if (length(cbox) > 7 && strncmp (cbox(end-6:end), "outside", 7)) - scl(2) -= 0.2 * scl(2); - if (strncmp (cbox, "west", 4) || strncmp (cbox, "south", 5)) - scl(1) += 0.2 * scl(2); - endif - endif - - if (strcmpi (obj.dataaspectratiomode, "manual")) - sz = min(pos(3:4))([1,1]); - r = obj.dataaspectratio; - if (pos(3) > pos(4)) - switch (cbox) - case {"north", "northoutside"} - off = 4 / 3 * [(pos(3) - pos(4)) ./ (r(2)/r(1)), pos(4) / pos(3) / 2]; - sz = 2 * sz / 3; - case {"south", "southoutside"} - off = 4 / 3 * [(pos(3) - pos(4)) ./ (r(2)/r(1)), 0]; - sz = 2 * sz / 3; - otherwise - off = [(pos(3) - pos(4)) ./ (r(2)/r(1)), 0]; - endswitch - else - switch (cbox) - case {"north", "northoutside"} - off = 1.5 * [0, (pos(4) - pos(3)) ./ (r(1) / r(2))]; - case {"south", "southoutside"} - off = 0.5 * [0, (pos(4) - pos(3)) ./ (r(1) / r(2))]; - otherwise - off = [0, (pos(4) - pos(3)) ./ (r(1) / r(2))]; - endswitch - endif - off = off / 2; - else - sz = pos(3:4); - off = 0; - endif - switch (cbox) - case "northoutside" - sz = sz - 0.08; - origin = [0.05, 0.06] + [0.00, 0.88] .* sz + pos(1:2) + off; - mirr = true; - orient = "horizontal"; - case "north" - sz = sz - 0.16; - origin = [0.09, 0.09] + [0.00, 0.94] .* sz + pos(1:2) + off; - mirr = false; - orient = "horizontal"; - case "southoutside" - sz = sz - 0.08; - origin = [0.05, 0.06] + [0.00, 0.00] .* sz + pos(1:2) + off; - mirr = false; - orient = "horizontal"; - case "south" - sz = sz - 0.16; - origin = [0.08, 0.09] + [0.03, 0.05] .* sz + pos(1:2) + off; - mirr = true; - orient = "horizontal"; - case "eastoutside" - sz = sz - 0.08; - origin = [0.00, 0.06] + [0.94, 0.00] .* sz + pos(1:2) + off; - mirr = false; - orient = "vertical"; - case "east" - sz = sz - 0.16; - origin = [0.09, 0.10] + [0.91, 0.01] .* sz + pos(1:2) + off; - mirr = true; - orient = "vertical"; - case "westoutside" - sz = sz - 0.08; - origin = [0.00, 0.06] + [0.06, 0.00] .* sz + pos(1:2) + off; - mirr = true; - orient = "vertical"; - case "west" - sz = sz - 0.16; - origin = [0.06, 0.09] + [0.04, 0.03] .* sz + pos(1:2) + off; - mirr = false; - orient = "vertical"; - endswitch - - if (strncmp (cbox, "north", 5) || strncmp (cbox, "south", 5)) - sz = sz .* [1, 0.07]; - pos([2,4]) = scl; - else - sz = sz .* [0.07, 1]; - pos([1,3]) = scl; - endif - -endfunction - function retval = __do_enhanced_option__ (enhanced, obj) retval = ""; if (enhanced) 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 @@ -37,10 +37,6 @@ switch (obj.type) case "axes" axes_count++; - ## Force multiplot with a colorbar to ensure colorbar on the page - if (!strcmpi (obj.__colorbar__, "none")) - axes_count++; - endif endswitch endfor diff --git a/scripts/plot/colorbar.m b/scripts/plot/colorbar.m --- a/scripts/plot/colorbar.m +++ b/scripts/plot/colorbar.m @@ -1,4 +1,4 @@ -## Copyright (C) 2007 David Bateman +## Copyright (C) 2008 David Bateman ## ## This file is part of Octave. ## @@ -49,48 +49,304 @@ ## PKG_ADD: mark_as_command colorbar -function colorbar (varargin) - - if (nargin > 0 && strcmpi (varargin{1}, "peer")) - if (nargin > 1) - ax = varargin{2}; - if (!isscalar (ax) || ! ishandle (ax) - || strcmp (get (ax, "type"), "axes")) - error ("colorbar: expecting an axes handle following 'peer'"); - endif - else - error ("colorbar: misisng axes handle after 'peer'"); - endif - else - ax = gca (); - endif +function h = colorbar (varargin) + ax = []; + loc = "eastoutside"; + args = {}; + deleting = false; + + i = 1; + while (i <= nargin) + arg = varargin {i++}; - pos = "eastoutside"; - for i = 1 : length (varargin) - arg = varargin{i}; - if (length(arg) < 1) - pos = "eastoutside"; - elseif (ischar (arg)) - if (strcmpi (arg, "off") || strcmpi (arg, "none")) - pos = "none"; + if (ischar(arg)) + if (strcmpi (arg, "peer")) + if (i > nargin) + error ("colorbar: missing axes handle after 'peer'"); + else + ax = vargin{i++} + if (!isscalar (ax) || ! ishandle (ax) + || strcmp (get (ax, "type"), "axes")) + error ("colorbar: expecting an axes handle following 'peer'"); + endif + endif elseif (strcmpi (arg, "north") || strcmpi (arg, "south") || strcmpi (arg, "east") || strcmpi (arg, "west") || strcmpi (arg, "northoutside") || strcmpi (arg, "southoutside") || strcmpi (arg, "eastoutside") || strcmpi (arg, "westoutside")) - pos = arg; + loc = arg; + elseif (strcmpi (arg, "off") || strcmpi (arg, "none")) + deleting = true; else - error ("colorbar: unrecognized position argument"); + args{end+1} = arg; + endif + else + args{end+1} = arg; + endif + endwhile + + if (isempty (ax)) + ax = gca (); + endif + obj = get (ax); + + if (deleting) + objs = findobj (get (ax, "parent"), "type", "axes"); + for i = 1 : length (objs) + if (strcmp (get (objs(i), "tag"), "colorbar") && + get (objs(i), "axes") == ax) + delete (objs(i)); + endif + endfor + else + position = obj.position; + clen = rows (get (get (ax, "parent"), "colormap")); + cext = get (ax, "clim"); + cdiff = (cext(2) - cext(1)) / clen / 2; + cmin = cext(1) + cdiff; + cmax = cext(2) - cdiff; + + orig_pos = obj.position; + orig_opos = obj.outerposition; + [pos, cpos, vertical, mirror, aspect] = ... + __position_colorbox__ (loc, obj, ancestor (ax, "figure")); + set (ax, "activepositionproperty", "position", "position", pos); + + cax = __go_axes__ (get (ax, "parent"), "tag", "colorbar", + "handlevisibility", "off", + "activepositionproperty", "position", + "position", cpos); + addproperty ("location", cax, "radio", + "eastoutside|east|westoutside|west|northoutside|north|southoutside|south", + loc); + addproperty ("axes", cax, "handle", ax); + + if (vertical) + hi = image (cax, [0,1], [cmin, cmax], [1 : clen]'); + if (mirror) + set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", + "ylim", cext, "ylimmode", "manual", + "yaxislocation", "right", args{:}); + else + set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", + "ylim", cext, "ylimmode", "manual", + "yaxislocation", "left", args{:}); endif else - error ("colorbar: expecting string arguments"); + hi = image (cax, [cmin, cmax], [0,1], [1 : clen]); + if (mirror) + set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", + "xlim", cext, "xlimmode", "manual", + "xaxislocation", "top", args{:}); + else + set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", + "xlim", cext, "xlimmode", "manual", + "xaxislocation", "bottom", args{:}); + endif + endif + + if (! isnan (aspect)) + set (cax, "dataaspectratio", aspect); + endif + + ctext = text (0, 0, "", "tag", "colorbar","visible", "off", + "handlevisibility", "off", "xliminclude", "off", + "yliminclude", "off", "zliminclude", "off", + "deletefcn", {@deletecolorbar, cax, orig_pos, orig_opos}); + + set (cax, "deletefcn", {@resetaxis, orig_pos, orig_opos}); + + addlistener (ax, "clim", {@update_colorbar_clim, hi, vertical}) + addlistener (ax, "dataaspectratio", {@update_colorbar_axis, cax}) + addlistener (ax, "position", {@update_colorbar_axis, cax}) + + endif + + if (nargout > 0) + h = cax; + endif +endfunction + +function deletecolorbar (h, d, hc, pos, opos) + ## Don't delete the colorbar and reset the axis size if the + ## parent figure is being deleted. + if (ishandle (hc) && strcmp (get (hc, "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off"))) + if (strcmp (get (hc, "beingdeleted"), "off")) + delete (hc); + endif + if (!isempty (ancestor (h, "axes")) && + strcmp (get (ancestor (h, "axes"), "beingdeleted"), "off")) + set (ancestor (h, "axes"), "position", pos, "outerposition", opos); + endif + endif +endfunction + +function resetaxis (h, d, pos, opos) + if (ishandle (h) && strcmp (get (h, "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + ishandle (get (h, "axes"))) + #set (get (h, "axes"), "position", pos, "outerposition", opos); + endif +endfunction + +function update_colorbar_clim (h, d, hi, vert) + if (ishandle (h) && strcmp (get (h, "type"), "image") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off"))) + clen = rows (get (get (h, "parent"), "colormap")); + cext = get (h, "clim"); + cdiff = (cext(2) - cext(1)) / clen / 2; + cmin = cext(1) + cdiff; + cmax = cext(2) - cdiff; + + if (vert) + set (hi, "ydata", [cmin, cmax]); + set (get (hi, "parent"), "ylim", cext); + else + set (hi, "xdata", [cmin, cmax]); + set (get (hi, "parent"), "xlim", cext); + endif + endif +endfunction + +function update_colorbar_axis (h, d, cax) + if (ishandle (cax) && strcmp (get (cax, "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off"))) + loc = get (cax, "location"); + obj = get (h); + [pos, cpos, vertical, mirror, aspect] = ... + __position_colorbox__ (loc, obj, ancestor (h, "figure")); + + if (vertical) + if (mirror) + set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", + "yaxislocation", "right", "position", cpos); + else + set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", + "yaxislocation", "left", "position", cpos); + endif + else + if (mirror) + set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", + "xaxislocation", "top", "position", cpos); + else + set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", + "xaxislocation", "bottom", "position", cpos); + endif + endif + + if (! isnan (aspect)) + aspect + set (cax, "dataaspectratio", aspect); endif - endfor + endif +endfunction + +function [pos, cpos, vertical, mirr, aspect] = __position_colorbox__ (cbox, obj, cf) + + pos = obj.position; + sz = pos(3:4); + + off = 0; + if (strcmpi (obj.dataaspectratiomode, "manual")) + r = obj.dataaspectratio; + if (pos(3) > pos(4)) + switch (cbox) + case {"east", "eastoutside", "west", "westoutside"} + off = [(pos(3) - pos(4)) ./ (r(2) / r(1)), 0]; + endswitch + else + switch (cbox) + case {"north", "northoutside", "south", "southoutside"} + off = [0, (pos(4) - pos(3)) ./ (r(1) / r(2))]; + ## This shouldn't be here except that gnuplot doesn't have a + ## square window and so a square aspect ratio is not square. + ## The corrections are empirical. + if (strcmp (get (cf, "__backend__"), "gnuplot")) + if (length (cbox) > 7 && strcmp (cbox(end-6:end),"outside")) + off = off / 2; + else + off = off / 1.7; + endif + endif + endswitch + endif + off = off / 2; + endif - set (ax, "__colorbar__", pos); + switch (cbox) + case "northoutside" + origin = pos(1:2) + [0., 0.9] .* sz + [1, -1] .* off; + sz = sz .* [1.0, 0.06]; + pos(4) = 0.8 * pos(4); + mirr = true; + vertical = false; + case "north" + origin = pos(1:2) + [0.05, 0.9] .* sz + [1, -1] .* off; + sz = sz .* [1.0, 0.06] * 0.9; + mirr = false; + vertical = false; + case "southoutside" + origin = pos(1:2) + off; + sz = sz .* [1.0, 0.06]; + pos(2) = pos(2) + pos(4) * 0.2; + pos(4) = 0.8 * pos(4); + mirr = false; + vertical = false; + case "south" + origin = pos(1:2) + [0.05, 0.05] .* sz + off; + sz = sz .* [1.0, 0.06] * 0.9; + mirr = true; + vertical = false; + case "eastoutside" + origin = pos(1:2) + [0.9, 0] .* sz + [-1, 1] .* off; + sz = sz .* [0.06, 1.0]; + pos(3) = 0.8 * pos(3); + mirr = true; + vertical = true; + case "east" + origin = pos(1:2) + [0.9, 0.05] .* sz + [-1, 1] .* off; + sz = sz .* [0.06, 1.0] * 0.9; + mirr = false; + vertical = true; + case "westoutside" + origin = pos(1:2) + off; + sz = sz .* [0.06, 1.0]; + pos(1) = pos(1) + pos(3) * 0.2; + pos(3) = 0.8 * pos(3); + mirr = false; + vertical = true; + case "west" + origin = pos(1:2) + [0.05, 0.05] .* sz + off; + sz = sz .* [0.06, 1.0] .* 0.9; + mirr = true; + vertical = true; + endswitch + + cpos = [origin, sz]; + + if (strcmpi (obj.dataaspectratiomode, "manual")) + r = obj.dataaspectratio; + + if (pos(3) > pos(4)) + if (vertical) + aspect = [1, 0.21, 1]; + else + aspect = [0.21, 1, 1]; + endif + else + if (vertical) + aspect = [1, 0.21, 1]; + else + aspect = [0.21, 1, 1]; + endif + endif + else + aspect = NaN; + endif endfunction - %!demo %! hold off; %! close all; diff --git a/scripts/plot/legend.m b/scripts/plot/legend.m --- a/scripts/plot/legend.m +++ b/scripts/plot/legend.m @@ -80,10 +80,9 @@ function legend (varargin) + [ca, varargin, nargin] = __plt_get_axis_arg__ ("legend", varargin{:}); nargs = nargin; - ca = gca (); - if (nargs > 0) pos = varargin{nargs}; if (isnumeric (pos) && isscalar (pos) && round (pos) == pos) @@ -132,12 +131,25 @@ case "boxoff" set (ca, "keybox", "off"); otherwise - while (k <= nkids && ! strcmp (get (kids(k), "type"), "line")) + typ = get (kids (k), "type"); + while (k <= nkids && ! strcmp (typ, "line") && + ! strcmp (typ, "hggroup")) k++; endwhile if (k <= nkids) turn_on_legend = true; - set (kids(k), "keylabel", arg); + if (strcmp (typ, "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 + else + set (kids(k), "keylabel", arg); + endif else warning ("legend: ignoring extra labels"); endif @@ -160,7 +172,8 @@ for i = 1:nkids if (strcmp (get (kids(k), "type"), "line") || strcmp (get (kids(k), "type"), "surface") - || strcmp (get (kids(k), "type"), "patch")) + || strcmp (get (kids(k), "type"), "patch") + || strcmp (get (kids(k), "type"), "hggroup")) have_data = true; break; endif @@ -177,11 +190,23 @@ while (k <= nkids && ! (strcmp (get (kids(k), "type"), "line") || strcmp (get (kids(k), "type"), "surface") - || strcmp (get (kids(k), "type"), "patch"))) + || strcmp (get (kids(k), "type"), "patch") + || strcmp (get (kids(k), "type"), "hggroup"))) k++; endwhile if (k <= nkids) - set (kids(k), "keylabel", arg); + 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 + else + set (kids(k), "keylabel", arg); + endif turn_on_legend = true; k++; elseif (! warned) @@ -189,6 +214,9 @@ warning ("legend: ignoring extra labels"); endif else + arg + get(kids(k),"type") + k error ("legend: expecting argument to be a character string"); endif endfor diff --git a/scripts/plot/newplot.m b/scripts/plot/newplot.m --- a/scripts/plot/newplot.m +++ b/scripts/plot/newplot.m @@ -49,8 +49,13 @@ otherwise error ("newplot: unrecognized nextplot property for current axes"); endswitch + + yt = get (ca, "ylabel"); + if (! strcmp (get (yt, "type"), "text")) + disp("BAD!!!!!"); + get(yt) + endif else print_usage (); endif - endfunction diff --git a/scripts/plot/pareto.m b/scripts/plot/pareto.m --- a/scripts/plot/pareto.m +++ b/scripts/plot/pareto.m @@ -55,8 +55,6 @@ function h = pareto (varargin) - [ax, varargin, nargin] = __plt_get_axis_arg__ ("pareto", varargin{:}); - if (nargin != 1 && nargin != 2) print_usage (); endif @@ -84,7 +82,7 @@ cdf95 = cdf - 0.95; idx95 = find(sign(cdf95(1:end-1)) != sign(cdf95(2:end)))(1); - [ax, hbar, hline] = plotyy (ax, 1 : idx95, x (1 : idx95), + [ax, hbar, hline] = plotyy (1 : idx95, x (1 : idx95), 1 : length(cdf), 100 .* cdf, @bar, @plot); diff --git a/scripts/plot/plotyy.m b/scripts/plot/plotyy.m --- a/scripts/plot/plotyy.m +++ b/scripts/plot/plotyy.m @@ -77,10 +77,14 @@ ax(2) = axes (); else ax = get (f, "children"); - for i = 3 : length (ax) - delete (ax (i)); - endfor - ax = ax(1:2); + if (length (ax) > 2) + for i = 3 : length (ax) + delete (ax (i)); + endfor + ax = ax(1:2); + elseif (length (ax) == 1) + ax(2) = axes (); + endif endif if (nargin < 2) varargin = {}; @@ -125,8 +129,6 @@ h1 = feval (fun1, x1, y1); set (ax(1), "ycolor", getcolor (h1(1))); - set (ax(1), "position", [0.11 0.13 0.78 0.73]); - set (ax(1), "activepositionproperty", "position"); set (ax(1), "xlim", xlim); cf = gcf (); @@ -141,9 +143,68 @@ set (ax(2), "yaxislocation", "right"); set (ax(2), "ycolor", getcolor (h2(1))); set (ax(2), "position", get (ax(1), "position")); - set (ax(2), "activepositionproperty", "position"); set (ax(2), "xlim", xlim); set (ax(2), "color", "none"); + + ## Add invisible text objects that when destroyed, + ## also remove the other axis + t1 = text (0, 0, "", "parent", ax(1), "tag", "plotyy", + "handlevisibility", "off", "visible", "off", + "xliminclude", "off", "yliminclude", "off"); + t2 = text (0, 0, "", "parent", ax(2), "tag", "plotyy", + "handlevisibility", "off", "visible", "off", + "xliminclude", "off", "yliminclude", "off"); + + set (t1, "deletefcn", {@deleteplotyy, ax(2), t2}); + set (t2, "deletefcn", {@deleteplotyy, ax(1), t1}); + + addlistener (ax(1), "position", {@update_position, ax(2)}); + addlistener (ax(2), "position", {@update_position, ax(1)}); + addlistener (ax(1), "view", {@update_position, ax(2)}); + addlistener (ax(2), "view", {@update_position, ax(1)}); + + ## Tag the plotyy axes, so we can use that information + ## not to mirror the y axis tick marks + set (ax, "tag", "plotyy") + +endfunction + +%!demo +%! x = 0:0.1:2*pi; +%! y1 = sin (x); +%! y2 = exp (x - 1); +%! ax = plotyy (x, y1, x - 1, y2, @plot, @semilogy); +%! xlabel ("X"); +%! ylabel (ax(1), "Axis 1"); +%! ylabel (ax(2), "Axis 2"); + +function deleteplotyy (h, d, ax2, t2) + if (ishandle (ax2) && strcmp (get (ax2, "type"), "axes") && + (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) && + strcmp (get (ax2, "beingdeleted"), "off")) + set (t2, "deletefcn", []); + delete (ax2); + endif +endfunction + +function update_position (h, d, ax2) + persistent recursion = false; + + ## Don't allow recursion + if (! recursion) + unwind_protect + recursion = true; + position = get (h, "position"); + view = get (h, "view"); + oldposition = get (ax2, "position"); + oldview = get (ax2, "view"); + if (! (isequal (position, oldposition) && isequal (view, oldview))) + set (ax2, "position", position, "view", view); + endif + unwind_protect_cleanup + recursion = false; + end_unwind_protect + endif endfunction function color = getcolor (ax) @@ -159,11 +220,3 @@ endif endfunction -%!demo -%! x = 0:0.1:2*pi; -%! y1 = sin (x); -%! y2 = exp (x - 1); -%! ax = plotyy (x, y1, x - 1, y2, @plot, @semilogy); -%! xlabel ("X"); -%! ylabel (ax(1), "Axis 1"); -%! ylabel (ax(2), "Axis 2"); diff --git a/scripts/plot/subplot.m b/scripts/plot/subplot.m --- a/scripts/plot/subplot.m +++ b/scripts/plot/subplot.m @@ -126,8 +126,9 @@ continue; endif if (strcmp (get (child, "type"), "axes")) - ## Skip legend objects. - if (strcmp (get (child, "tag"), "legend")) + ## Skip legend and colorbar objects. + if (strcmp (get (child, "tag"), "legend") || + strcmp (get (child, "tag"), "colorbar")) continue; endif objpos = get (child, "outerposition"); @@ -136,7 +137,6 @@ ## existing axes object, use the existing axes. found = true; tmp = child; - break; else ## If the new axes overlap an old axes object, delete the old ## axes. @@ -154,7 +154,9 @@ if (found) set (cf, "currentaxes", tmp); else - tmp = axes ("outerposition", pos); + border = [0.130, 0.110, 0.225, 0.185] .* [xsize, ysize, xsize, ysize]; + pos2 = [pos(1:2) + border(1:2), pos(3:4) - border(1:2) - border(3:4)]; + tmp = axes ("outerposition", pos, "position", pos2); endif if (nargout > 0) diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,37 @@ +2008-10-10 John W. Eaton + + * graphics.cc (gh_manager::do_free): Set the beingdeleted + property, then delete the children, then execute the deletefcn. + (axes::properties::set_defaults, axes::properties::remove_child, + axes::properites::delete_children): Call delete_text_child to + manage the title, xlabel, ylabel, and zlabel properties. + (axes::properties::get_title, axes::properties::get_xlabel, + axes::properties::get_ylabel, axes::properties::get_zlabel): Delete. + + * graphics.h.in (axes::properites::title, + axes::properites::xlabel, axes::properites::ylabel, + axes::properites::zlabel): No longer mutable. Don't generate + factory default values or custom get functions for these + properties. + + * graphics.cc (axes::properties::delete_text_child): New function. + * graphics.h.in: Provide decl. + + * graphics.h.in (graphics_object::type): New function. + +2008-10-10 David Bateman + + * graphics.h.in (radio_property axes::properties::__colorbar__): + Delete. + * graphics.cc (void axes::properties::sync_positions (void)): + Disable code synchronizing outerposiiton and position. + (void axes::properties::set_defaults (base_graphics_object&, + const std::string&): Remove __colorbar__. + (F__go_delete__): Don't delete if already being deleting to avoid + recursion in callback functions. + (F__go_axes_init__): Flag error if handle is deleted during + initialization due. + 2008-10-07 David Bateman * graphics.cc (F__go_delete__): Allow arrays of graphic handles. diff --git a/src/graphics.cc b/src/graphics.cc --- a/src/graphics.cc +++ b/src/graphics.cc @@ -1291,19 +1291,25 @@ if (p != handle_map.end ()) { - // FIXME: should we explicitely free all children first? - // => call delete_children () ? - - p->second.get_properties ().set_beingdeleted (true); - p->second.get_properties ().execute_deletefcn (); + base_properties& bp = p->second.get_properties (); + + bp.set_beingdeleted (true); + + bp.delete_children (); + + octave_value val = bp.get_deletefcn (); + + bp.execute_deletefcn (); // notify backend graphics_backend backend = p->second.get_backend (); if (backend) backend.object_destroyed (p->second); - // note - this will be valid only for first explicitly deleted object. - // All his children will have unknown backend then. - + + // Note: this will be valid only for first explicitly + // deleted object. All its children will then have an + // unknown backend. + handle_map.erase (p); if (h.value () < 0) @@ -1737,8 +1743,15 @@ { octave_idx_type n = children.numel (); + // A callback function might have already deleted the child, + // so check before deleting for (octave_idx_type i = 0; i < n; i++) - gh_manager::free (children(i)); + { + graphics_object go = gh_manager::get_object (children(i)); + + if (go.valid_object ()) + gh_manager::free (children(i)); + } } graphics_backend @@ -2104,8 +2117,12 @@ void axes::properties::sync_positions (void) { +#if 0 // FIXME -- this should take font metrics into consideration, - // for now we'll just make it position 90% of outerposition + // and also the fact that the colorbox leaves the outerposition + // alone but alters the position. For now just don't adjust the + // positions relative to each other. + if (activepositionproperty.is ("outerposition")) { Matrix outpos = outerposition.get ().matrix_value (); @@ -2126,6 +2143,7 @@ pos(3) *= 1.1; outerposition = pos; } +#endif update_transform (); } @@ -2182,7 +2200,8 @@ axes::properties::set_defaults (base_graphics_object& obj, const std::string& mode) { - title = graphics_handle (); + delete_text_child (title); + box = "on"; key = "off"; keybox = "off"; @@ -2206,9 +2225,11 @@ ylimmode = "auto"; zlimmode = "auto"; climmode = "auto"; - xlabel = graphics_handle (); - ylabel = graphics_handle (); - zlabel = graphics_handle (); + + delete_text_child (xlabel); + delete_text_child (ylabel); + delete_text_child (zlabel); + xgrid = "off"; ygrid = "off"; zgrid = "off"; @@ -2289,7 +2310,6 @@ } activepositionproperty = "outerposition"; - __colorbar__ = "none"; delete_children (); @@ -2300,53 +2320,34 @@ override_defaults (obj); } -graphics_handle -axes::properties::get_title (void) const -{ - if (! title.handle_value ().ok ()) - title = gh_manager::make_graphics_handle ("text", __myhandle__); - - return title.handle_value (); -} - -graphics_handle -axes::properties::get_xlabel (void) const +void +axes::properties::delete_text_child (handle_property& hp) { - if (! xlabel.handle_value ().ok ()) - xlabel = gh_manager::make_graphics_handle ("text", __myhandle__); - - return xlabel.handle_value (); -} - -graphics_handle -axes::properties::get_ylabel (void) const -{ - if (! ylabel.handle_value ().ok ()) - ylabel = gh_manager::make_graphics_handle ("text", __myhandle__); - - return ylabel.handle_value (); -} - -graphics_handle -axes::properties::get_zlabel (void) const -{ - if (! zlabel.handle_value ().ok ()) - zlabel = gh_manager::make_graphics_handle ("text", __myhandle__); - - return zlabel.handle_value (); + graphics_handle h = hp.handle_value (); + + if (h.ok ()) + { + graphics_object go = gh_manager::get_object (h); + + if (go.valid_object ()) + gh_manager::free (h); + } + + if (! is_beingdeleted ()) + hp = gh_manager::make_graphics_handle ("text", __myhandle__); } void axes::properties::remove_child (const graphics_handle& h) { if (title.handle_value ().ok () && h == title.handle_value ()) - title = gh_manager::make_graphics_handle ("text", __myhandle__); + delete_text_child (title); else if (xlabel.handle_value ().ok () && h == xlabel.handle_value ()) - xlabel = gh_manager::make_graphics_handle ("text", __myhandle__); + delete_text_child (xlabel); else if (ylabel.handle_value ().ok () && h == ylabel.handle_value ()) - ylabel = gh_manager::make_graphics_handle ("text", __myhandle__); + delete_text_child (ylabel); else if (zlabel.handle_value ().ok () && h == zlabel.handle_value ()) - zlabel = gh_manager::make_graphics_handle ("text", __myhandle__); + delete_text_child (zlabel); else base_properties::remove_child (h); } @@ -2356,10 +2357,11 @@ { base_properties::delete_children (); - gh_manager::free (title.handle_value ()); - gh_manager::free (xlabel.handle_value ()); - gh_manager::free (ylabel.handle_value ()); - gh_manager::free (zlabel.handle_value ()); + delete_text_child (title); + + delete_text_child (xlabel); + delete_text_child (ylabel); + delete_text_child (zlabel); } inline Matrix @@ -4431,20 +4433,28 @@ { graphics_object obj = gh_manager::get_object (h); - graphics_handle parent_h = obj.get_parent (); - - graphics_object parent_obj = - gh_manager::get_object (parent_h); - - // NOTE: free the handle before removing it from its parent's - // children, such that the object's state is correct - // when the deletefcn callback is executed - - gh_manager::free (h); - - parent_obj.remove_child (h); - - Vdrawnow_requested = true; + // Don't do recursive deleting, due to callbacks + if (! obj.get_properties ().is_beingdeleted ()) + { + graphics_handle parent_h = obj.get_parent (); + + graphics_object parent_obj = + gh_manager::get_object (parent_h); + + // NOTE: free the handle before removing it from its + // parent's children, such that the object's + // state is correct when the deletefcn callback + // is executed + + gh_manager::free (h); + + // A callback function might have already deleted + // the parent + if (parent_obj.valid_object ()) + parent_obj.remove_child (h); + + Vdrawnow_requested = true; + } } else { @@ -4500,6 +4510,10 @@ graphics_object obj = gh_manager::get_object (h); obj.set_defaults (mode); + + h = gh_manager::lookup (val); + if (! h.ok ()) + error ("__go_axes_init__: axis deleted during initialization (= %g)", val); } else error ("__go_axes_init__: invalid graphics object (= %g)", val); diff --git a/src/graphics.h.in b/src/graphics.h.in --- a/src/graphics.h.in +++ b/src/graphics.h.in @@ -2030,6 +2030,8 @@ bool valid_object (void) const { return rep->valid_object (); } + std::string type (void) const { return rep->type (); } + operator bool (void) const { return rep->valid_object (); } // FIXME -- these functions should be generated automatically by the @@ -2530,12 +2532,14 @@ Matrix x_zlim; std::list zoom_stack; + void delete_text_child (handle_property& h); + // See the genprops.awk script for an explanation of the // properties declarations. BEGIN_PROPERTIES(axes) array_property position u , default_axes_position () - mutable handle_property title GSO , graphics_handle () + handle_property title SOf , gh_manager::make_graphics_handle ("text", __myhandle__) bool_property box , "on" bool_property key , "off" bool_property keybox , "off" @@ -2554,9 +2558,9 @@ radio_property zlimmode al , "{auto}|manual" radio_property climmode al , "{auto}|manual" radio_property alimmode , "{auto}|manual" - mutable handle_property xlabel GSO , graphics_handle () - mutable handle_property ylabel GSO , graphics_handle () - mutable handle_property zlabel GSO , graphics_handle () + handle_property xlabel SOf , gh_manager::make_graphics_handle ("text", __myhandle__) + handle_property ylabel SOf , gh_manager::make_graphics_handle ("text", __myhandle__) + handle_property zlabel SOf , gh_manager::make_graphics_handle ("text", __myhandle__) bool_property xgrid , "off" bool_property ygrid , "off" bool_property zgrid , "off" @@ -2595,7 +2599,6 @@ radio_property nextplot , "add|replace_children|{replace}" array_property outerposition u , default_axes_outerposition () radio_property activepositionproperty , "{outerposition}|position" - radio_property __colorbar__ h , "{none}|north|south|east|west|northoutside|southoutside|eastoutside|westoutside" color_property ambientlightcolor , color_values (1, 1, 1) array_property cameraposition m , Matrix (1, 3, 0.0) array_property cameratarget m , Matrix (1, 3, 0.0)