changeset 8101:86955a1559c5

improve speed of cell2mat * * * trivial fix for previous cell2mat change
author David Bateman <dbateman@free.fr>
date Thu, 11 Sep 2008 16:57:12 -0400
parents da2fbd22d672
children c066714ee5d5
files scripts/ChangeLog scripts/general/cell2mat.m scripts/image/__img__.m scripts/plot/__go_draw_axes__.m scripts/plot/__go_draw_figure__.m scripts/plot/colorbar.m scripts/plot/legend.m scripts/plot/newplot.m scripts/plot/pareto.m scripts/plot/plotyy.m scripts/plot/subplot.m src/ChangeLog src/graphics.cc src/graphics.h.in
diffstat 14 files changed, 567 insertions(+), 232 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/ChangeLog	Thu Sep 11 16:57:12 2008 -0400
@@ -1,3 +1,29 @@
+2008-09-11  David Bateman  <dbateman@free.fr>
+
+	* 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-09-09  David Bateman  <dbateman@free.fr>
+
+	* general/cell2mat.m: Improve the speed..
+	
 2008-09-09  John W. Eaton  <jwe@octave.org>
 
 	* time/datestr.m: Convert format and use strftime to do most of
--- a/scripts/general/cell2mat.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/general/cell2mat.m	Thu Sep 11 16:57:12 2008 -0400
@@ -48,20 +48,46 @@
     else
       error ("cell2mat: all elements of cell array must be numeric, logical or char");
     endif
+  elseif (ndims (c) == 2)
+    nr = rows (c);
+    c1 = cell (nr, 1);
+    for i = 1 : nr
+      c1{i} = [c{i : nr : end}];
+    endfor
+    ## This is faster than "c = cat(1, c{:})"
+    m = [cellfun(@(x) x.', c1, "UniformOutput", false){:}].';
   else
-    ## n dimensions case
-    for k = ndims (c):-1:2,
+   nd = ndims (c);
+   for k = nd : -1 : 2
       sz = size (c);
+      if (k > ndims (c) || sz(end) == 1)
+	continue;
+      endif
       sz(end) = 1;
       c1 = cell (sz);
-      for i = 1:(prod (sz))
-        c1{i} = cat (k, c{i:(prod (sz)):end});
-      endfor
+      sz = prod (sz);
+      if (k == 2)
+        for i = 1 : sz
+	  c1{i} = [c{i : sz : end}];
+        endfor
+      else
+        ## This is faster than
+        ##   for i = 1:sz, c1{i} = cat (k, c{i:(prod (sz)):end}); endfor
+	idx = [1, k, (3 : (k - 1)), 2, ((k + 1): nd)];
+        c = cellfun(@(x) permute (x, idx), c, "UniformOutput", false);
+        for i = 1: sz
+	  c1{i} = ipermute ([c{i : sz : end}], idx);
+        endfor
+      endif
       c = c1;
     endfor
-    m = cat (1, c1{:});
+    if (numel (c) > 1)
+      idx = [2, 1, 3 : nd];
+      m = ipermute([cellfun(@(x) permute (x, idx), c, "UniformOutput", false){:}], idx);
+    else
+      m = c{1};
+    endif
   endif
-
 endfunction
 
 ## Tests
--- a/scripts/image/__img__.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/image/__img__.m	Thu Sep 11 16:57:12 2008 -0400
@@ -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");
--- a/scripts/plot/__go_draw_axes__.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/__go_draw_axes__.m	Thu Sep 11 16:57:12 2008 -0400
@@ -31,27 +31,17 @@
     persistent have_newer_gnuplot ...
       = compare_versions (__gnuplot_version__ (), "4.0", ">");
 
-    ## 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));
@@ -358,12 +348,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);
@@ -1027,6 +1021,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
@@ -1035,8 +1031,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;
@@ -1046,8 +1041,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))
@@ -1209,16 +1203,8 @@
 	fputs (plot_stream, ");\n");
       endif
     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)
@@ -1549,7 +1535,7 @@
 function do_tics_1 (ticmode, tics, labelmode, labels, color, ax,
 		    plot_stream, mirror, mono, axispos, tickdir)
   colorspec = get_text_colorspec (color, mono);
-  if (strcmpi (ticmode, "manual"))
+  if (strcmpi (ticmode, "manual") || strcmpi (labelmode, "manual"))
     if (isempty (tics))
       fprintf (plot_stream, "unset %stics;\n", ax);
     elseif (strcmpi (labelmode, "manual") && ! isempty (labels))
@@ -1562,7 +1548,8 @@
 	nlabels = numel (labels);
 	fprintf (plot_stream, "set format %s \"%%s\";\n", ax);
 	if (mirror)
-	  fprintf (plot_stream, "set %stics %s %s (", ax, tickdir, axispos);
+	  fprintf (plot_stream, "set %stics %s %s mirror (", ax, 
+		   tickdir, axispos);
 	else
 	  fprintf (plot_stream, "set %stics %s %s nomirror (", ax,
 		   tickdir, axispos);
@@ -1584,7 +1571,8 @@
     else
       fprintf (plot_stream, "set format %s \"%%g\";\n", ax);
       if (mirror)
-	fprintf (plot_stream, "set %stics %s %s (", ax, tickdir, axispos );
+	fprintf (plot_stream, "set %stics %s %s mirror (", ax, 
+		 tickdir, axispos );
       else
 	fprintf (plot_stream, "set %stics %s %s nomirror (", ax, tickdir,
 		 axispos);
@@ -1595,8 +1583,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);
@@ -1987,105 +1975,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)
--- a/scripts/plot/__go_draw_figure__.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/__go_draw_figure__.m	Thu Sep 11 16:57:12 2008 -0400
@@ -37,10 +37,6 @@
 	  switch (obj.type)
 	    case "axes"
 	      axes_count++;
-	      ## Force multiplot with a colorbar to ensure colorbar on the page
-	      if (!strcmp (obj.__colorbar__, "none"))
-		axes_count++;
-	      endif
 	  endswitch
 	endfor
 
--- a/scripts/plot/colorbar.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/colorbar.m	Thu Sep 11 16:57:12 2008 -0400
@@ -1,4 +1,4 @@
-## Copyright (C) 2007 David Bateman
+## Copyright (C) 2008 David Bateman
 ##
 ## This file is part of Octave.
 ##
@@ -47,51 +47,304 @@
 ## @end deftypefn
 
 
-## PKG_ADD: mark_as_command colorbar
+function h = colorbar (varargin)
+  ax = [];
+  loc = "eastoutside";
+  args = {};
+  deleting = false;
+
+  i = 1;
+  while (i <= nargin)
+    arg = varargin {i++};
 
-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'");
+    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"))
+	loc = arg;
+      elseif (strcmpi (arg, "off") || strcmpi (arg, "none"))
+	deleting = true;
+      else
+	args{end+1} = arg;
       endif
     else
-      error ("colorbar: misisng axes handle after 'peer'");
+      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
-    ax = gca ();
+    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
+      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
 
-  pos = "eastoutside";
-  for i = 1 : length (varargin)
-    arg = varargin{i};
-    if (length(arg) < 1)
-      pos = "eastoutside";
-    elseif (ischar (arg))
-      arg = tolower (arg);
-      if (strcmp (arg, "off") || strcmp (arg, "none"))
-	pos = "none";
-      elseif (strcmp (arg, "north") || strcmp (arg, "south")
-	      || strcmp (arg, "east") || strcmp (arg, "west")
-	      || strcmp (arg, "northoutside") || strcmp (arg, "southoutside")
-	      || strcmp (arg, "eastoutside") || strcmp (arg, "westoutside"))
-	pos = arg;
+  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
-	error ("colorbar: unrecognized position argument");
+	set (cax, "xtick", [], "xdir", "normal", "ydir", "normal",
+	     "yaxislocation", "left", "position", cpos);
       endif
     else
-      error ("colorbar: expecting string arguments");
+      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
+  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
-  endfor
+    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;
--- a/scripts/plot/legend.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/legend.m	Thu Sep 11 16:57:12 2008 -0400
@@ -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
--- a/scripts/plot/newplot.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/newplot.m	Thu Sep 11 16:57:12 2008 -0400
@@ -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
--- a/scripts/plot/pareto.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/pareto.m	Thu Sep 11 16:57:12 2008 -0400
@@ -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);
 
--- a/scripts/plot/plotyy.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/plotyy.m	Thu Sep 11 16:57:12 2008 -0400
@@ -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");
--- a/scripts/plot/subplot.m	Thu Sep 11 15:53:37 2008 -0400
+++ b/scripts/plot/subplot.m	Thu Sep 11 16:57:12 2008 -0400
@@ -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)
--- a/src/ChangeLog	Thu Sep 11 15:53:37 2008 -0400
+++ b/src/ChangeLog	Thu Sep 11 16:57:12 2008 -0400
@@ -3,6 +3,19 @@
 	* octave.cc (octave_main): Make all command-line arguments
 	available to startup scripts and PKG_ADD files.
 
+2008-09-10  David Bateman  <dbateman@free.fr>
+
+	* 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-09-09  David Bateman  <dbateman@free.fr>
 
 	* DLD-FUNCTIONS/regexp.cc (octregexp_list): Distinguish between
--- a/src/graphics.cc	Thu Sep 11 15:53:37 2008 -0400
+++ b/src/graphics.cc	Thu Sep 11 16:57:12 2008 -0400
@@ -1301,8 +1301,9 @@
 	      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);
 
@@ -1713,8 +1714,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
@@ -2080,8 +2088,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 ();
@@ -2102,6 +2114,7 @@
       pos(3) *= 1.1;
       outerposition = pos;
     }
+#endif
 
   update_transform ();
 }
@@ -2158,7 +2171,14 @@
 axes::properties::set_defaults (base_graphics_object& obj,
 				const std::string& mode)
 {
+  gh_manager::free (title.handle_value ());
   title = graphics_handle ();
+
+  if (! title.handle_value ().ok ()) 
+    std::cerr << "set_defaults not ok\n";
+  else
+    std::cerr << "set_defaults ok " << title.handle_value().value () << "\n";
+
   box = "on";
   key = "off";
   keybox = "off";
@@ -2182,9 +2202,14 @@
   ylimmode = "auto";
   zlimmode = "auto";
   climmode = "auto";
+
+  gh_manager::free (xlabel.handle_value ());
+  gh_manager::free (ylabel.handle_value ());
+  gh_manager::free (zlabel.handle_value ());
   xlabel = graphics_handle ();
   ylabel = graphics_handle ();
   zlabel = graphics_handle ();
+
   xgrid = "off";
   ygrid = "off";
   zgrid = "off";
@@ -2265,7 +2290,6 @@
     }
 
   activepositionproperty = "outerposition";
-  __colorbar__  = "none";
 
   delete_children ();
 
@@ -2279,8 +2303,19 @@
 graphics_handle
 axes::properties::get_title (void) const
 {
+  if (! title.handle_value ().ok ()) 
+    std::cerr << "get_title not ok\n";
+  else
+    std::cerr << "get_title ok " << title.handle_value().value () << "\n";
+
+    
   if (! title.handle_value ().ok ())
     title = gh_manager::make_graphics_handle ("text", __myhandle__);
+  
+  if (! title.handle_value ().ok ()) 
+    std::cerr << "get_title 2 not ok\n";
+  else
+    std::cerr << "get_title 2 ok " << title.handle_value().value () << "\n";
 
   return title.handle_value ();
 }
@@ -4405,19 +4440,26 @@
 	    {
 	      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
 	    error ("delete: invalid graphics object (= %g)", val);
@@ -4468,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);
--- a/src/graphics.h.in	Thu Sep 11 15:53:37 2008 -0400
+++ b/src/graphics.h.in	Thu Sep 11 16:57:12 2008 -0400
@@ -2595,7 +2595,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)