changeset 7222:dd8b3bbeeaf9

[project @ 2007-11-30 06:23:25 by jwe]
author jwe
date Fri, 30 Nov 2007 06:23:26 +0000
parents 2636c0846924
children 868101dc4404
files scripts/ChangeLog scripts/plot/__go_draw_axes__.m src/ChangeLog src/graphics.cc src/graphics.h.in
diffstat 5 files changed, 509 insertions(+), 237 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Thu Nov 29 23:27:32 2007 +0000
+++ b/scripts/ChangeLog	Fri Nov 30 06:23:26 2007 +0000
@@ -1,3 +1,8 @@
+2007-11-30  John W. Eaton  <jwe@octave.org>
+
+	* plot/__go_draw_axes__.m: Don't compute data or axis limits.
+	(get_data_limits, get_axis_limits): Delete.
+
 2007-11-29  David Bateman  <dbateman@free.fr>
 
 	* plot/pareto.m: New file.
--- a/scripts/plot/__go_draw_axes__.m	Thu Nov 29 23:27:32 2007 +0000
+++ b/scripts/plot/__go_draw_axes__.m	Fri Nov 30 06:23:26 2007 +0000
@@ -247,29 +247,13 @@
     is_image_data = [];
     hidden_removal = NaN;
 
-    xminp = yminp = zminp = cminp = Inf;
-    xmax = ymax = zmax = cmax = -Inf;
-    xmin = ymin = zmin = cmin = Inf;
+    xlim = axis_obj.xlim
+    ylim = axis_obj.ylim
+    zlim = axis_obj.zlim
+    clim = axis_obj.clim
 
-    ## This has to be done here as some of the code below depends on the
-    ## final clim.
-    if (cautoscale)
-      for i = 1:length (kids)
-	obj = get (kids(i));
-	if (isfield (obj, "cdata"))
-	  cdat = obj.cdata(:);
-	  [cmin, cmax, cminp] = get_data_limits (cmin, cmax, cminp, cdat);
-	endif
-      endfor
-      if (cmin == cmax)
-	cmax = cmin + 1;
-      endif      
-      clim = [cmin, cmax];
-    else
-      clim = axis_obj.clim;
-      if (clim(1) == clim(2))
-	clim = [clim(1), clim(1) + 1];
-      endif
+    if (! cautoscale && clim(1) == clim(2))
+      clim(2)++;
     endif
 
     [view_cmd, view_fcn, view_zoom] = image_viewer ();
@@ -318,22 +302,6 @@
 	    x_origin = min (img_xdata);
 	    y_origin = min (img_ydata);
 
-	    if (nd == 2)
-	      if (xautoscale)
-		xmin = min (xmin, min (img_xdata) - dx/2);
-		xmax = max (xmax, max (img_xdata) + dx/2);
-		xminp = min (xminp, min (img_xdata((img_xdata - dx/2)>0)) - dx/2);
-	      endif
-	      if (yautoscale)
-		ymin = min (ymin, min (img_ydata) - dy/2);
-		ymax = max (ymax, max (img_ydata) + dy/2);
-		yminp = min (yminp, min (img_ydata((img_ydata - dy/2)>0)) - dy/2);
-	      endif
-	    else
-	      ## Can have images in 3D, but the image routines don't seem
-	      ## to have a means of arbitrary projection.
-	    endif
-
 	    if (ndims (img_data) == 3)
 	      data{data_idx} = permute (img_data, [3, 1, 2])(:);
 	      format = "1:2:3";
@@ -385,15 +353,6 @@
 	    ydat = obj.ydata(:);
 	    zdat = obj.zdata(:);
 
-	    if (xautoscale)
-	      [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xdat);
-	    endif
-	    if (yautoscale)
-	      [ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ydat);
-	    endif
-	    if (zautoscale)
-	      [zmin, zmax, zminp] = get_data_limits (zmin, zmax, zminp, zdat);
-	    endif
 	    data{data_idx} = [xdat, ydat, zdat]';
 	    usingclause{data_idx} = "using ($1):($2):($3)";
 	    fputs (plot_stream, "set parametric;\n");
@@ -449,49 +408,19 @@
 		else
 		  xhi = xdat+xudat;
 		endif
-		if (xautoscale)
-		  tx = [xdat; xlo; xhi];
-		  [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, tx);
-		endif
 		data{data_idx} = [xdat, ydat, xlo, xhi, ylo, yhi]';
 		usingclause{data_idx} = "using ($1):($2):($3):($4):($5):($6)";
 		withclause{data_idx} = "with xyerrorbars";
 	      else
-		if (xautoscale)
-		  [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xdat);
-		endif
 		data{data_idx} = [xdat, ydat, ylo, yhi]';
 		usingclause{data_idx} = "using ($1):($2):($3):($4)";
 		withclause{data_idx} = "with yerrorbars";
 	      endif
 	    elseif (xerr)
-	      if (isempty (xldat))
-		xlo = xdat;
-	      else
-		xlo = xdat-xldat;
-	      endif
-	      if (isempty (xudat))
-		xhi = xdat;
-	      else
-		xhi = xdat+xudat;
-	      endif
-	      if (xautoscale)
-		tx = [xdat; xlo; xhi];
-		[xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, tx);
-	      endif
-	      if (yautoscale)
-		[ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ydat);
-	      endif
 	      data{data_idx} = [xdat, ydat, xlo, xhi]';
 	      usingclause{data_idx} = "using ($1):($2):($3):($4)";
 	      withclause{data_idx} = "with xerrorbars";
 	    else
-	      if (xautoscale)
-		[xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xdat);
-	      endif
-	      if (yautoscale)
-		[ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ydat);
-	      endif
 	      data{data_idx} = [xdat, ydat]';
 	      usingclause{data_idx} = sprintf ("using ($1):($2) axes %s%s",
 					      xaxisloc_using, yaxisloc_using);
@@ -525,18 +454,6 @@
 	     zcol = [];
 	   endif
 
-	   if (xautoscale)
-             [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xcol);
-	   endif
-	   if (yautoscale)
-	     [ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ycol);
-	   endif
-	   if (! isempty (obj.zdata) && ! strncmp(obj.edgecolor, "none", 4))
-	     if (zautoscale)
-	       [zmin, zmax, zminp] = get_data_limits (zmin, zmax, zminp, zcol);
-	     endif
-	   endif
-
 	   if (! isnan (xcol) && ! isnan (ycol))
 	     ## Is the patch closed or not
 	     if (strncmp (obj.facecolor, "none", 4)) 
@@ -871,19 +788,6 @@
 	    zdat = obj.zdata;
 	    cdat = obj.cdata;
 
-	    if (xautoscale)
-	      tx = xdat(:);
-	      [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, tx);
-	    endif
-	    if (yautoscale)
-	      ty = ydat(:);
-	      [ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ty);
-	    endif
-	    if (zautoscale)
-	      tz = zdat(:);
-	      [zmin, zmax, zminp] = get_data_limits (zmin, zmax, zminp, tz);
-	    endif
-
   	    err = false;
             if (! size_equal(zdat, cdat))
               err = true;
@@ -1053,14 +957,8 @@
 
     have_data = (! (isempty (data) || any (cellfun (@isempty, data))));
 
-    if (xautoscale && have_data)
-      xlim = get_axis_limits (xmin, xmax, xminp, xlogscale);
-      if (isempty (xlim))
-	return;
-      endif
-      set (h, "xlim", xlim, "xlimmode", "auto");
-    else
-      xlim = axis_obj.xlim;
+    if (isempty (xlim))
+      return;
     endif
     if (strcmpi (axis_obj.xdir, "reverse"))
       xdir = "reverse";
@@ -1070,14 +968,8 @@
     fprintf (plot_stream, "set %srange [%.15e:%.15e] %s;\n",
 	     xaxisloc, xlim, xdir);
 
-    if (yautoscale && have_data)
-      ylim = get_axis_limits (ymin, ymax, yminp, ylogscale);
-      if (isempty (ylim))
-	return;
-      endif
-      set (h, "ylim", ylim, "ylimmode", "auto");
-    else
-      ylim = axis_obj.ylim;
+    if (isempty (ylim))
+      return;
     endif
     if (strcmpi (axis_obj.ydir, "reverse"))
       ydir = "reverse";
@@ -1088,14 +980,8 @@
 	     yaxisloc, ylim, ydir);
 
     if (nd == 3)
-      if (zautoscale && have_data)
-	zlim = get_axis_limits (zmin, zmax, zminp, zlogscale);
-	if (isempty (zlim))
-	  return;
-	endif
-	set (h, "zlim", zlim, "zlimmode", "auto");
-      else
-	zlim = axis_obj.zlim;
+      if (isempty (zlim))
+	return;
       endif
       if (strcmpi (axis_obj.zdir, "reverse"))
 	zdir = "reverse";
@@ -1105,9 +991,6 @@
       fprintf (plot_stream, "set zrange [%.15e:%.15e] %s;\n", zlim, zdir);
     endif
 
-    if (cautoscale && have_data)
-      set (h, "clim", clim, "climmode", "auto");
-    endif
     if (! any (isinf (clim)))
       fprintf (plot_stream, "set cbrange [%g:%g];\n", clim);
     endif
@@ -1276,62 +1159,6 @@
 
 endfunction
 
-function [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xdat)
-  if (! isempty (xdat))
-    xdat = xdat(! isinf (xdat));
-    xmin = min (xmin, min (xdat));
-    xmax = max (xmax, max (xdat));
-    tmp = min (xdat(xdat > 0));
-    if (! isempty (tmp))
-      xminp = min (xminp, tmp);
-    endif
-  endif
-endfunction
-
-## Attempt to make "nice" limits from the actual max and min of the
-## data.  For log plots, we will also use the smallest strictly positive
-## value.
-
-function lim = get_axis_limits (min_val, max_val, min_pos, logscale)
-
-  if (! (isinf (min_val) || isinf (max_val)))
-    if (logscale)
-      if (isinf (min_pos))
-	lim = [];
-	warning ("axis: logscale with no positive values to plot");
-	return;
-      endif
-      if (min_val <= 0)
-	warning ("axis: omitting nonpositive data in log plot");
-	min_val = min_pos;
-      endif
-      ## FIXME -- maybe this test should also be relative?
-      if (abs (min_val - max_val) < sqrt (eps))
-	min_val *= 0.9;
-	max_val *= 1.1;
-      endif
-      min_val = 10 ^ floor (log10 (min_val));
-      max_val = 10 ^ ceil (log10 (max_val));
-    else
-      if (min_val == 0 && max_val == 0)
-	min_val = -1;
-	max_val = 1;
-      ## FIXME -- maybe this test should also be relative?
-      elseif (abs (min_val - max_val) < sqrt (eps))
-	min_val -= 0.1 * abs (min_val);
-	max_val += 0.1 * abs (max_val);
-      endif
-      ## FIXME -- to do a better job, we should consider the tic spacing.
-      scale = 10 ^ floor (log10 (max_val - min_val) - 1);
-      min_val = scale * floor (min_val / scale);
-      max_val = scale * ceil (max_val / scale);
-    endif
-  endif
-
-  lim = [min_val, max_val];
-
-endfunction
-
 function [style, typ, with] = do_linestyle_command (obj, idx, plot_stream)
 
   persistent have_newer_gnuplot ...
--- a/src/ChangeLog	Thu Nov 29 23:27:32 2007 +0000
+++ b/src/ChangeLog	Fri Nov 30 06:23:26 2007 +0000
@@ -1,3 +1,36 @@
+2007-11-30  John W. Eaton  <jwe@octave.org>
+
+	* graphics.cc (updating_axis_limits): New static variable.
+	(check_limit_val, check_limit_vals, get_axis_limits): New functions.
+	(axes::update_axis_limits): Make it work.
+	* graphics.h.in (base_properties::get_children): New function.
+	(base_properties::get_xdata, base_properties::get_ydata,
+	base_properties::get_zdata, base_properties::get_ldata,
+	base_properties::get_udata, base_properties::get_xldata,
+	base_properties::get_xudata, base_properties::get_cdata,
+	base_properties::get_properties (void) const):
+	New virtual functions.
+	(graphics_object::get_xdata, graphics_object::get_ydata,
+	graphics_object::get_zdata, graphics_object::get_ldata,
+	graphics_object::get_udata, graphics_object::get_xldata,
+	graphics_object::get_xudata, graphics_object::get_cdata,
+	graphics_object::get_properties (void) const,
+	root_figure::get_properties (void) const,
+	figure::get_properties (void) const,
+	axes::get_properties (void) const,
+	line::get_properties (void) const,
+	text::get_properties (void) const,
+	image::get_properties (void) const,
+	patch::get_properties (void) const,
+	surface::get_properties (void) const)): New functions.
+	(radio_property::radio_property (const radio_values&)):
+	Provide	default value for argument. 
+	(radio_property::radio_property (const radio_values&, const
+	std::string&)): Delete.
+	(axes::xlimmode, axes::ylimmode, axes::zlimmode, axes::climmode,
+	axes::xscale, axes::yscale, axes::zscale): Declare as
+	radio_property instead of octave_value values.  Adjust all uses.
+
 2007-11-29  John W. Eaton  <jwe@octave.org>
 
 	* pr-output.cc (octave_print_internal_template (std::ostream&,
--- a/src/graphics.cc	Thu Nov 29 23:27:32 2007 +0000
+++ b/src/graphics.cc	Fri Nov 30 06:23:26 2007 +0000
@@ -25,6 +25,7 @@
 #endif
 
 #include <cctype>
+#include <cfloat>
 
 #include <algorithm>
 #include <list>
@@ -40,6 +41,7 @@
 #include "oct-map.h"
 #include "ov-fcn-handle.h"
 #include "parse.h"
+#include "unwind-prot.h"
 
 static void
 gripe_set_invalid (const std::string& pname)
@@ -1087,10 +1089,10 @@
     ylim (),
     zlim (),
     clim (),
-    xlimmode ("auto"),
-    ylimmode ("auto"),
-    zlimmode ("auto"),
-    climmode ("auto"),
+    xlimmode (radio_values ("{auto}|manual")),
+    ylimmode (radio_values ("{auto}|manual")),
+    zlimmode (radio_values ("{auto}|manual")),
+    climmode (radio_values ("{auto}|manual")),
     xlabel (octave_NaN),
     ylabel (octave_NaN),
     zlabel (octave_NaN),
@@ -1115,9 +1117,9 @@
     xcolor (),
     ycolor (),
     zcolor (),
-    xscale ("linear"),
-    yscale ("linear"),
-    zscale ("linear"),
+    xscale (radio_values ("{linear}|log")),
+    yscale (radio_values ("{linear}|log")),
+    zscale (radio_values ("{linear}|log")),
     xdir ("normal"),
     ydir ("normal"),
     zdir ("normal"),
@@ -1370,10 +1372,10 @@
   cl(1) = 1;
   clim = cl;
   
-  xlimmode = "auto";
-  ylimmode = "auto";
-  zlimmode = "auto";
-  climmode = "auto";
+  xlimmode = radio_property (radio_values ("{auto}|manual"));
+  ylimmode = radio_property (radio_values ("{auto}|manual"));
+  zlimmode = radio_property (radio_values ("{auto}|manual"));
+  climmode = radio_property (radio_values ("{auto}|manual"));
   xlabel = octave_NaN;
   ylabel = octave_NaN;
   zlabel = octave_NaN;
@@ -1398,9 +1400,9 @@
   xcolor = color_property ("black");
   ycolor = color_property ("black");
   zcolor = color_property ("black");
-  xscale = "linear";
-  yscale = "linear";
-  zscale = "linear";
+  xscale = radio_property (radio_values ("{linear}|log"));
+  yscale = radio_property (radio_values ("{linear}|log"));
+  zscale = radio_property (radio_values ("{linear}|log"));
   xdir = "normal";
   ydir = "normal";
   zdir = "normal";
@@ -1720,10 +1722,10 @@
   
   m["clim"] = cl;
 
-  m["xlimmode"] = "auto";
-  m["ylimmode"] = "auto";
-  m["zlimmode"] = "auto";
-  m["climmode"] = "auto";
+  m["xlimmode"] = radio_property (radio_values ("{auto}|manual"));
+  m["ylimmode"] = radio_property (radio_values ("{auto}|manual"));
+  m["zlimmode"] = radio_property (radio_values ("{auto}|manual"));
+  m["climmode"] = radio_property (radio_values ("{auto}|manual"));
   m["xlabel"] = octave_NaN;
   m["ylabel"] = octave_NaN;
   m["zlabel"] = octave_NaN;
@@ -1748,9 +1750,9 @@
   m["xcolor"] = color_property ("black");
   m["ycolor"] = color_property ("black");
   m["zcolor"] = color_property ("black");
-  m["xscale"] = "linear";
-  m["yscale"] = "linear";
-  m["zscale"] = "linear";
+  m["xscale"] = radio_property (radio_values ("{linear}|log"));
+  m["yscale"] = radio_property (radio_values ("{linear}|log"));
+  m["zscale"] = radio_property (radio_values ("{linear}|log"));
   m["xdir"] = "normal";
   m["ydir"] = "normal";
   m["zdir"] = "normal";
@@ -1791,9 +1793,281 @@
   return retval;
 }
 
+static void
+check_limit_val (double& min_val, double& max_val, double& min_pos, double val)
+{
+  if (! (xisinf (val) || xisnan (val)))
+    {
+      if (val < min_val)
+	min_val = val;
+
+      if (val > max_val)
+	max_val = val;
+
+      if (val > 0 && val < min_pos)
+	min_pos = val;
+    }
+}
+
+static void
+check_limit_vals (double& min_val, double& max_val, double& min_pos,
+		  const data_property& data)
+{
+  check_limit_val (min_val, max_val, min_pos, data.min_val ());
+  check_limit_val (max_val, max_val, min_pos, data.max_val ());
+  check_limit_val (min_pos, max_val, min_pos, data.min_pos ());
+}
+
+// Attempt to make "nice" limits from the actual max and min of the
+// data.  For log plots, we will also use the smallest strictly positive
+// value.
+
+static Matrix
+get_axis_limits (double xmin, double xmax, double min_pos, bool logscale)
+{
+  Matrix retval;
+
+  double min_val = xmin;
+  double max_val = xmax;
+
+  if (! (xisinf (min_val) || xisinf (max_val)))
+    {
+      if (logscale)
+	{
+	  if (xisinf (min_pos))
+	    {
+	      // warning ("axis: logscale with no positive values to plot");
+	      return retval;
+	    }
+
+	  if (min_val <= 0)
+	    {
+	      warning ("axis: omitting nonpositive data in log plot");
+	      min_val = min_pos;
+	    }
+	  // FIXME -- maybe this test should also be relative?
+	  if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
+	    {
+	      min_val *= 0.9;
+	      max_val *= 1.1;
+	    }
+	  min_val = pow (10, floor (log10 (min_val)));
+	  max_val = pow (10, ceil (log10 (max_val)));
+	}
+      else
+	{
+	  if (min_val == 0 && max_val == 0)
+	    {
+	      min_val = -1;
+	      max_val = 1;
+	    }
+	  // FIXME -- maybe this test should also be relative?
+	  else if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
+	    {
+	      min_val -= 0.1 * std::abs (min_val);
+	      max_val += 0.1 * std::abs (max_val);
+	    }
+	  // FIXME -- to do a better job, we should consider the tic spacing.
+	  double scale = pow (10, floor (log10 (max_val - min_val) - 1));
+	  min_val = scale * floor (min_val / scale);
+	  max_val = scale * ceil (max_val / scale);
+	}
+    }
+
+  retval.resize (1, 2);
+
+  retval(0) = min_val;
+  retval(1) = max_val;
+
+  return retval;
+}
+
+static bool updating_axis_limits = false;
+
 void
-axes::update_axis_limits (const std::string& /* axis_type */)
+axes::update_axis_limits (const std::string& axis_type)
 {
+  if (updating_axis_limits)
+    return;
+
+  Matrix kids = xproperties.get_children ();
+
+  octave_idx_type n = kids.numel ();
+
+  double min_val = octave_Inf;
+  double max_val = -octave_Inf;
+  double min_pos = octave_Inf;
+
+  radio_property tmp;
+
+  char update_type = 0;
+
+  Matrix limits;
+
+  if (axis_type == "xdata" || axis_type == "xscale"
+      || axis_type == "xldata" || axis_type == "xudata"
+      || axis_type == "xlimmode")
+    {
+      tmp = xproperties.get_xlimmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	  for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("line") || obj.isa ("image")
+		  || obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property xdata = obj.get_xdata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, xdata);
+
+		  if (obj.isa ("line"))
+		    {
+		      data_property xldata = obj.get_xldata ();
+		      data_property xudata = obj.get_xudata ();
+
+		      check_limit_vals (min_val, max_val, min_pos, xldata);
+		      check_limit_vals (min_val, max_val, min_pos, xudata);
+		    }
+		}
+	    }
+
+	  tmp = xproperties.get_xscale ();
+
+	  limits = get_axis_limits (min_val, max_val, min_pos,
+				    tmp.current_value () == "log");
+
+	  update_type = 'x';
+	}
+    }
+  else if (axis_type == "ydata" || axis_type == "yscale"
+	   || axis_type == "ldata" || axis_type == "udata"
+	   || axis_type == "ylimmode")
+    {
+      tmp = xproperties.get_ylimmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	    for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("line") || obj.isa ("image")
+		|| obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property ydata = obj.get_ydata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, ydata);
+
+		  if (obj.isa ("line"))
+		    {
+		      data_property ldata = obj.get_ldata ();
+		      data_property udata = obj.get_udata ();
+
+		      check_limit_vals (min_val, max_val, min_pos, ldata);
+		      check_limit_vals (min_val, max_val, min_pos, udata);
+		    }
+		}
+	    }
+
+	  tmp = xproperties.get_yscale ();
+
+	  limits = get_axis_limits (min_val, max_val, min_pos,
+				    tmp.current_value () == "log");
+
+	  update_type = 'y';
+	}
+    }
+  else if (axis_type == "zdata" || axis_type == "zscale"
+	   || axis_type == "zlimmode")
+    {
+      tmp = xproperties.get_zlimmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	  for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("line") || obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property zdata = obj.get_zdata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, zdata);
+		}
+	    }
+
+	  tmp = xproperties.get_zscale ();
+
+	  limits = get_axis_limits (min_val, max_val, min_pos,
+				    tmp.current_value () == "log");
+
+	  update_type = 'z';
+	}
+    }
+  else if (axis_type == "cdata" || axis_type == "climmode")
+    {
+      tmp = xproperties.get_climmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	  for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("image") || obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property cdata = obj.get_cdata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, cdata);
+		}
+	    }
+
+	  if (min_val == max_val)
+	    max_val = min_val + 1;
+
+	  limits.resize (1, 2);
+
+	  limits(0) = min_val;
+	  limits(1) = max_val;
+
+	  update_type = 'c';
+	}
+
+    }
+
+  unwind_protect_bool (updating_axis_limits);
+  updating_axis_limits = true;
+
+  switch (update_type)
+    {
+    case 'x':
+      xproperties.set_xlim (limits);
+      xproperties.set_xlimmode ("auto");
+      break;
+
+    case 'y':
+      xproperties.set_ylim (limits);
+      xproperties.set_ylimmode ("auto");
+      break;
+
+    case 'z':
+      xproperties.set_zlim (limits);
+      xproperties.set_zlimmode ("auto");
+      break;
+
+    case 'c':
+      xproperties.set_clim (limits);
+      xproperties.set_climmode ("auto");
+      break;
+
+    default:
+      break;
+    }
+
+  unwind_protect::run ();
 }
 
 std::string axes::properties::go_name ("axes");
--- a/src/graphics.h.in	Thu Nov 29 23:27:32 2007 +0000
+++ b/src/graphics.h.in	Fri Nov 30 06:23:26 2007 +0000
@@ -130,12 +130,9 @@
 class radio_property
 {
 public:
-  radio_property (const radio_values& v)
+  radio_property (const radio_values& v = radio_values ())
     : vals (v), current_val (v.default_value ()) { }
 
-  radio_property (const radio_values& v, const std::string& initial_value)
-    : vals (v), current_val (initial_value) { }
-
   radio_property (const radio_property& a)
     : vals (a.vals), current_val (a.current_val) { }
 
@@ -412,15 +409,13 @@
 {
 public:
   data_property (const Matrix& m = Matrix ())
-    : data (m), min_val (octave_Inf), max_val (-octave_Inf),
-      min_pos (octave_Inf)
+    : data (m), xmin (octave_Inf), xmax (-octave_Inf), xminp (octave_Inf)
   {
     get_data_limits ();
   }
 
   data_property (const octave_value& val)
-    : data (), min_val (octave_Inf), max_val (-octave_Inf),
-      min_pos (octave_Inf)
+    : data (), xmin (octave_Inf), xmax (-octave_Inf), xminp (octave_Inf)
   {
     data = val.matrix_value ();
 
@@ -432,9 +427,9 @@
     if (&a != this)
       {
 	data = a.data;
-	min_val = a.min_val;
-	max_val = a.max_val;
-	min_pos = a.min_pos;
+	xmin = a.xmin;
+	xmax = a.xmax;
+	xminp = a.xminp;
       }
 
     return *this;
@@ -442,11 +437,15 @@
 
   operator octave_value (void) const { return data; }
 
+  double min_val (void) const { return xmin; }
+  double max_val (void) const { return xmax; }
+  double min_pos (void) const { return xminp; }
+
 private:
   Matrix data;
-  double min_val;
-  double max_val;
-  double min_pos;
+  double xmin;
+  double xmax;
+  double xminp;
 
   void get_data_limits (void)
   {
@@ -462,14 +461,14 @@
 
 	    if (! (xisinf (val) || xisnan (val)))
 	      {
-		if (val < min_val)
-		  min_val = val;
-
-		if (val > max_val)
-		  max_val = val;
-
-		if (val > 0 && val < min_pos)
-		  min_pos = val;
+		if (val < xmin)
+		  xmin = val;
+
+		if (val > xmax)
+		  xmax = val;
+
+		if (val > 0 && val < xminp)
+		  xminp = val;
 	      }
 	  }
       }
@@ -673,6 +672,60 @@
 
   virtual void delete_children (void);
 
+  Matrix get_children (void) const { return children; }
+
+  // FIXME -- these functions should be generated automatically by the
+  // genprops.awk script.
+  //
+  // EMIT_BASE_PROPERTIES_GET_FUNCTIONS
+  virtual data_property get_xdata (void) const
+  {
+    error ("get: invalid property \"xdata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_ydata (void) const
+  {
+    error ("get: invalid property \"ydata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_zdata (void) const
+  {
+    error ("get: invalid property \"zdata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_ldata (void) const
+  {
+    error ("get: invalid property \"ldata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_udata (void) const
+  {
+    error ("get: invalid property \"udata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_xldata (void) const
+  {
+    error ("get: invalid property \"xldata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_xudata (void) const
+  {
+    error ("get: invalid property \"xudata\"");
+    return data_property ();
+  }
+
+  virtual data_property get_cdata (void) const
+  {
+    error ("get: invalid property \"cdata\"");
+    return data_property ();
+  }
+
 protected:
   std::string tag;
   std::string type;
@@ -779,7 +832,14 @@
     return properties;
   }
 
-  virtual void update_axis_limits (const std::string& axis_type)
+  virtual const base_properties& get_properties (void) const
+  {
+    static base_properties properties;
+    error ("base_graphics_object::get_properties: invalid graphics object");
+    return properties;
+  }
+
+  virtual void update_axis_limits (const std::string&)
   {
     error ("base_graphics_object::update_axis_limits: invalid graphics object");
   }
@@ -891,6 +951,11 @@
 
   base_properties& get_properties (void) { return rep->get_properties (); }
 
+  const base_properties& get_properties (void) const
+  {
+    return rep->get_properties ();
+  }
+
   void update_axis_limits (const std::string& axis_type)
   {
     rep->update_axis_limits (axis_type);
@@ -900,6 +965,58 @@
 
   operator bool (void) const { return rep->valid_object (); }
 
+  // FIXME -- these functions should be generated automatically by the
+  // genprops.awk script.
+  //
+  // EMIT_GRAPHICS_OBJECT_GET_FUNCTIONS
+  data_property get_xdata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_xdata ();
+  }
+
+  data_property get_ydata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_ydata ();
+  }
+
+  data_property get_zdata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_zdata ();
+  }
+
+  data_property get_ldata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_ldata ();
+  }
+
+  data_property get_udata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_udata ();
+  }
+
+  data_property get_xldata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_xldata ();
+  }
+
+  data_property get_xudata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_xudata ();
+  }
+
+  data_property get_cdata (void) const
+  {
+    const base_properties& props = get_properties ();
+    return props.get_cdata ();
+  }
+
 private:
   base_graphics_object *rep;
 };
@@ -1037,6 +1154,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const
   {
     gripe_not_implemented ("root_figure::defaults");
@@ -1177,6 +1296,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("figure::defaults"); }
 
   bool valid_object (void) const { return true; }
@@ -1230,10 +1351,10 @@
       octave_value ylim m
       octave_value zlim m
       octave_value clim m
-      octave_value xlimmode
-      octave_value ylimmode
-      octave_value zlimmode
-      octave_value climmode
+      radio_property xlimmode al
+      radio_property ylimmode al
+      radio_property zlimmode al
+      radio_property climmode al
       mutable graphics_handle xlabel GSO
       mutable graphics_handle ylabel GSO
       mutable graphics_handle zlabel GSO
@@ -1258,9 +1379,9 @@
       color_property xcolor
       color_property ycolor
       color_property zcolor
-      octave_value xscale l
-      octave_value yscale l
-      octave_value zscale l
+      radio_property xscale al
+      radio_property yscale al
+      radio_property zscale al
       octave_value xdir
       octave_value ydir
       octave_value zdir
@@ -1362,6 +1483,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("axes::defaults"); }
 
   void update_axis_limits (const std::string& axis_type);
@@ -1472,6 +1595,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("line::defaults"); }
 
   bool valid_object (void) const { return true; }
@@ -1572,6 +1697,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("text::defaults"); }
 
   bool valid_object (void) const { return true; }
@@ -1664,6 +1791,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("image::defaults"); }
 
   bool valid_object (void) const { return true; }
@@ -1770,6 +1899,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("patch::defaults"); }
 
   bool valid_object (void) const { return true; }
@@ -1874,6 +2005,8 @@
 
   base_properties& get_properties (void) { return xproperties; }
 
+  const base_properties& get_properties (void) const { return xproperties; }
+
   void defaults (void) const { gripe_not_implemented ("surface::defaults"); }
 
   bool valid_object (void) const { return true; }