changeset 8052:961d4c52ffae

Convert stem and stem3 to use stem series objects * * * Use property inheritance and don't call drawnow in __stem__
author David Bateman <dbateman@free.fr>
date Mon, 25 Aug 2008 15:45:24 -0400
parents 36a485f7f335
children 89a512e8ec43
files scripts/ChangeLog scripts/plot/__go_draw_axes__.m scripts/plot/__stem__.m scripts/plot/stem.m scripts/plot/stem3.m src/ChangeLog src/graphics.cc src/graphics.h.in
diffstat 8 files changed, 343 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Fri Aug 22 16:29:17 2008 -0400
+++ b/scripts/ChangeLog	Mon Aug 25 15:45:24 2008 -0400
@@ -1,3 +1,12 @@
+2008-08-25  David Bateman  <dbateman@free.fr>
+
+	* plot/__go_draw_axes__.m: Respect the "visible" property of object and
+	don't draw them if the object is not visible.
+
+	* plot/__stem__.m: Convert to use stem series object.
+	* plot/stem.m, plot/stem3.m: Update documentation to correpsond to
+	the stem series usage.
+
 2008-08-22  John W. Eaton  <jwe@octave.org>
 
 	* statistics/distributions/chi2rnd.m: Fix missing semicolon.
@@ -23,6 +32,11 @@
 	* pkg/pkg.m (configure_make): Pass handle to is_architecture_dependent
 	directly.
 
+2008-08-25  David Bateman  <dbateman@free.fr>
+
+	* plot/__stem__.m: Use property inheritance and don't explicitly
+	call drawnow.
+
 2008-08-20  David Bateman  <dbateman@free.fr>
 
 	* plot/__go_draw_axes__.m: Don't set pm3d implicit if the plot
--- a/scripts/plot/__go_draw_axes__.m	Fri Aug 22 16:29:17 2008 -0400
+++ b/scripts/plot/__go_draw_axes__.m	Mon Aug 25 15:45:24 2008 -0400
@@ -331,6 +331,10 @@
       obj = get (kids(1));
       kids = kids(2:end);
 
+      if (strcmp (obj.visible, "off"))
+	continue;
+      endif
+
       switch (obj.type)
 	case "image"
 	  img_data = obj.cdata;
--- a/scripts/plot/__stem__.m	Fri Aug 22 16:29:17 2008 -0400
+++ b/scripts/plot/__stem__.m	Mon Aug 25 15:45:24 2008 -0400
@@ -31,54 +31,119 @@
 
   [ax, varargin, nargin] = __plt_get_axis_arg__ (caller, varargin{:});
 
-  [x, y, z, dofill, lc, ls, mc, ms] = check_stem_arg (have_z, varargin{:});
-
-  if (dofill)
-    fc = mc;
-  else
-    fc = "none";
-  endif
-
-  newplot ();
-  nx = numel (x);
-  xt = x(:)';
-  xt = [xt; xt; NaN(1, nx)](:);
-  if (have_z)
-    yt = y(:)';
-    yt = [yt; yt; NaN(1, nx)](:);
-    zt = z(:)';
-    zt = [zeros(1, nx); zt; NaN(1, nx)](:);
-  else
-    yt = y(:)';
-    yt = [zeros(1, nx); yt; NaN(1, nx)](:);
-  endif
+  [x, y, z, dofill, llc, ls, mmc, ms] = check_stem_arg (have_z, varargin{:});
 
   oldax = gca ();
   unwind_protect
     axes (ax);
+    hold_state = get (ax, "nextplot");
+    newplot ();
+    h = [];
 
-    if (have_z)
-      h_stems = plot3 (xt, yt, zt, "color", lc, "linestyle", ls,
-		      x, y, z, "color", mc, "marker", ms, "linestyle", "",
-		      "markerfacecolor", fc);
+    nx = rows (x);
+    for i = 1: columns (x)
+      if (have_z)
+	xt = x(:)';
+	xt = [xt; xt; NaN(1, nx)](:);
+	yt = y(:)';
+	yt = [yt; yt; NaN(1, nx)](:);
+	zt = z(:)';
+	zt = [zeros(1, nx); zt; NaN(1, nx)](:);
+      else
+	xt = x(:, i)';
+	xt = [xt; xt; NaN(1, nx)](:);
+	yt = y(:, i)';
+	yt = [zeros(1, nx); yt; NaN(1, nx)](:);
+      endif
+
+      hg  = hggroup ();
+      h = [h; hg];
+      if (i == 1)
+	set (ax, "nextplot", "add");
+      endif
+
+      if (isempty (llc))
+	lc = __next_line_color__ ();
+      else
+	lc = llc;
+      endif
+
+      if (isempty (mmc))
+	mc = lc;
+      else
+	mc = mmc;
+      endif
+
+      if (dofill)
+	fc = mc;
+      else
+	fc = "none";
+      endif
+
+      if (have_z)
+	h_stems = plot3 (xt, yt, zt, "color", lc, "linestyle", ls, 
+			 "parent", hg, x, y, z, "color", mc,
+			 "marker",  ms, "linestyle", "none",
+			 "markerfacecolor", fc, "parent", hg);
 
-      h_baseline = [];
-    else
-      h_stems = plot (xt, yt, "color", lc, "linestyle", ls,
-		      x, y, "color", mc, "marker", ms, "linestyle", "",
-		      "markerfacecolor", fc);
+	h_baseline = [];
+      else
+	h_stems = plot (xt, yt, "color", lc, "linestyle", ls,
+			"parent", hg, x(:,i), y(:, i), "color", mc, "marker",
+			ms, "linestyle", "none", "markerfacecolor",
+			fc, "parent", hg); 
+
+	if (i == 1)
+	  x_axis_range = get (ax, "xlim");
+	  h_baseline = line (x_axis_range, [0, 0], "color", [0, 0, 0]);
+	  set (h_baseline, "handlevisibility", "off");
+	  addlistener (ax, "xlim", @update_xlim);
+	  addlistener (h_baseline, "ydata", @update_baseline);
+	  addlistener (h_baseline, "visible", @update_baseline);
+	endif
+      endif
+
+      ## Setup the hggroup and listeners
+      addproperty ("showbaseline", hg, "radio", "{on}|off");
+      addproperty ("basevalue", hg, "data", 0);
+      addproperty ("baseline", hg, "data", h_baseline);
+
+      if (!have_z)
+	addlistener (hg, "showbaseline", @show_baseline);
+	addlistener (hg, "basevalue", @move_baseline); 
+      endif
 
-      ## Must draw the plot first to get proper x limits.
-      drawnow();
-      x_axis_range = get (gca, "xlim");
-      h_baseline = line (x_axis_range, [0, 0], "color", [0, 0, 0]);
-    endif
+      addproperty ("color", hg, "linecolor", lc);
+      addproperty ("linewidth", hg, "linelinewidth", 0.5);
+      addproperty ("linestyle", hg, "linelinestyle", ls);
+      addproperty ("marker", hg, "linemarker", ms);
+      addproperty ("markerfacecolor", hg, "linemarkerfacecolor", fc);
+      addproperty ("markersize", hg, "linemarkersize", 6);
+
+      addlistener (hg, "color", @update_props);
+      addlistener (hg, "linewidth", @update_props); 
+      addlistener (hg, "linestyle", @update_props); 
+      addlistener (hg, "marker", @update_props); 
+      addlistener (hg, "markerfacecolor", @update_props); 
+      addlistener (hg, "markersize", @update_props);
+
+      addproperty ("xdata", hg, "data", x(:, i));
+      addproperty ("ydata", hg, "data", y(:, i));
+      if (have_z)
+	addproperty ("zdata", hg, "data", z(:, i));
+      else
+	addproperty ("zdata", hg, "data", []);
+      endif
+
+      addlistener (hg, "xdata", @update_data);
+      addlistener (hg, "ydata", @update_data);
+      addlistener (hg, "zdata", @update_data);
+    endfor
+
   unwind_protect_cleanup
+    set (ax, "nextplot", hold_state);
     axes (oldax);
   end_unwind_protect
-
-  h = [h_stems; h_baseline];
-
 endfunction
 
 function [x, y, z, dofill, lc, ls, mc, ms] = check_stem_arg (have_z, varargin)
@@ -115,11 +180,11 @@
   elseif (nargin == 3)
     ## several possibilities
     ## 1. the real y data
-    ## 2. 'fill'
+    ## 2. 'filled'
     ## 3. line spec
     if (ischar (varargin{2}))
       ## only 2. or 3. possible
-      if (strcmp ("fill", varargin{2}))
+      if (strcmpi ("fill", varargin{2}) || strcmpi ("filled", varargin{2}))
 	dofill = 1;
       else
 	## parse the linespec
@@ -154,12 +219,12 @@
   elseif (nargin == 4)
     ## again several possibilities
     ## arg2 1. real y
-    ## arg2 2. 'fill' or linespec
+    ## arg2 2. 'filled' or linespec
     ## arg3 1. real z
-    ## arg3 2. 'fill' or linespec
+    ## arg3 2. 'filled' or linespec
     if (ischar (varargin{2}))
       ## only arg2 2. / arg3 1. & arg3 3. are possible
-      if (strcmp ("fill", varargin{2}))
+      if (strcmpi ("fill", varargin{2}) || strcmpi ("filled", varargin{2}))
 	dofill = 1;
 	fill_2 = 1; # be sure, no second "fill" is in the arguments
       else
@@ -200,14 +265,16 @@
     endif # if ischar(varargin{2})
     if (! have_z)
       ## varargin{3} must be char
-      ## check for "fill"
-      if (strcmp ("fill", varargin{3}) && fill_2)
+      ## check for "fill
+      if ((strcmpi ("fill", varargin{3}) || strcmpi ("filled", varargin{3}))
+	  && fill_2)
 	error ("stem: duplicate fill argument");
       elseif (strcmp("fill", varargin{3}) && linespec_2)
 	## must be "fill"
 	dofill = 1;
 	fill_2 = 1;
-      elseif (strcmp ("fill", varargin{3}) && ! linespec_2)
+      elseif ((strcmpi ("fill", varargin{3}) || strcmpi ("filled", varargin{3}))
+	  && !linespec_2)
 	## must be "fill"
 	dofill = 1;
 	fill_2 = 1;
@@ -234,7 +301,7 @@
     endif
 
     if (! have_z)
-      if (strcmp ("fill", varargin{3}))
+      if (strcmpi ("fill", varargin{3}) || strcmpi ("filled", varargin{3}))
 	dofill = 1;
 	fill_2 = 1; # be sure, no second "fill" is in the arguments
       else
@@ -245,13 +312,16 @@
     endif
 
     ## check for "fill" ..
-    if (strcmp ("fill", varargin{4}) && fill_2)
+    if ((strcmpi ("fill", varargin{4}) || strcmpi ("filled", varargin{4}))
+	&& fill_2)
       error ("%s: duplicate fill argument", caller);
-    elseif (strcmp ("fill", varargin{4}) && linespec_2)
+    elseif ((strcmpi ("fill", varargin{4}) || strcmpi ("filled", varargin{4}))
+	&& linespec_2)
       ## must be "fill"
       dofill = 1;
       fill_2 = 1;
-    elseif (! strcmp ("fill", varargin{4}) && ! linespec_2)
+    elseif (!strcmpi ("fill", varargin{4}) && !strcmpi ("filled", varargin{4})
+	&& !linespec_2)
       ## must be linespec
       [lc, ls, mc, ms] = stem_line_spec (caller, varargin{4});
       linespec_2 = 1;
@@ -264,7 +334,7 @@
       error ("stem3: X, Y and Z must be matrices");
     endif
 
-    if (strcmp ("fill", varargin{4}))
+    if (strcmpi ("fill", varargin{4}) || strcmpi ("filled", varargin{4}))
       dofill = 1;
       fill_2 = 1; # be sure, no second "fill" is in the arguments
     else
@@ -274,13 +344,16 @@
     endif
 
     ## check for "fill" ..
-    if (strcmp ("fill", varargin{5}) && fill_2)
+    if ((strcmpi ("fill", varargin{5}) || strcmpi ("filled", varargin{5}))
+	&& fill_2)
       error ("stem3: duplicate fill argument");
-    elseif (strcmp ("fill", varargin{5}) && linespec_2)
+    elseif ((strcmpi ("fill", varargin{5}) || strcmpi ("filled", varargin{5}))
+	&& linespec_2)
       ## must be "fill"
       dofill = 1;
       fill_2 = 1;
-    elseif (! strcmp ("fill", varargin{5}) && ! linespec_2)
+    elseif (!strcmpi ("fill", varargin{5}) && !strcmpi ("filled", varargin{5})
+	&& !linespec_2)
       ## must be linespec
       [lc, ls, mc, ms] = stem_line_spec (caller, varargin{5});
       linespec_2 = 1;
@@ -289,6 +362,36 @@
     error ("%s: incorrect number of arguments", caller);
   endif
 
+  ## Check sizes of x, y and z
+  if (have_z)
+    if (!size_equal (x, y, z))
+      error ("stem3: inconsistent size of x, y and z");
+    else
+      x = x(:);
+      y = y(:);
+      z = z(:);
+    endif
+  else
+    if (isvector (x))
+      x = x(:);
+      if (isvector (y))
+	if (length (x) != length (y))
+	  error ("stem: inconsistent size of x and y");
+	else
+	  y = y(:);
+	endif
+      else
+	if (length (x) == rows (y))
+	  x = repmat (x(:), 1, columns (y));
+	else
+	  error ("stem: inconsistent size of x and y");
+	endif
+      endif
+    elseif (!size_equal (x, y ))
+      error ("stem: inconsistent size of x and y");
+    endif
+  endif
+
 endfunction
 
 function [lc, ls, mc, ms] = stem_line_spec (caller, str)
@@ -312,8 +415,103 @@
 
 function [lc, ls, mc, ms] = set_default_values ()
   ## set default values
-  mc = [1, 0, 0];
-  lc = [1, 0, 0];
+  mc = [];
+  lc = [];
   ls = "-";
   ms = "o";
 endfunction
+
+function update_xlim (h, d)
+  kids = get (h, "children");
+  xlim = get (h, "xlim");
+
+  for i = 1 : length (kids)
+    obj = get (kids (i));
+    if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline"))
+      if (get (obj.baseline, "xdata") != xlim)
+	set (obj.baseline, "xdata", xlim);
+      endif
+    endif
+  endfor
+endfunction
+
+function update_baseline (h, d)
+  visible = get (h, "visible");
+  ydata = get (h, "ydata")(1);
+
+  kids = get (get (h, "parent"), "children");
+  for i = 1 : length (kids)
+    obj = get (kids (i));
+    if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline") 
+	&& obj.baseline == h)
+      ## Only alter if changed to avoid recursion of the listener functions
+      if (! strcmp (get (kids(i), "showbaseline"), visible))
+	set (kids (i), "showbaseline", visible);
+      endif
+      if (! strcmp (get (kids(i), "basevalue"), visible))
+	set (kids (i), "basevalue", ydata);
+      endif
+    endif
+  endfor
+endfunction
+
+function show_baseline (h, d)
+  set (get (h, "baseline"), "visible", get (h, "showbaseline"));
+endfunction
+
+function move_baseline (h, d)
+  b0 = get (h, "basevalue");
+  bl = get (h, "baseline");
+
+  if (get (bl, "ydata") != [b0, b0])
+    set (bl, "ydata", [b0, b0]);
+  endif
+
+  kids = get (h, "children");
+  yt = get(h, "ydata")(:)';
+  ny = length (yt);
+  yt = [b0 * ones(1, ny); yt; NaN(1, ny)](:);
+  set (kids(1), "ydata", yt);
+endfunction
+
+function update_props (h, d)
+  kids = get (h, "children");
+  set (kids(1), "color", get (h, "color"), 
+       "linewidth", get (h, "linewidth"),
+       "linestyle", get (h, "linestyle"));
+  set (kids(2), "color", get (h, "color"), 
+       "marker", get (h, "marker"),
+       "markerfacecolor", get (h, "markerfacecolor"),
+       "markersize", get (h, "markersize"));
+endfunction
+
+function update_data (h, d)
+  x = get (h, "xdata");
+  y = get (h, "ydata");
+  z = get (h, "zdata");
+
+  if (!isempty (z) && size_equal (x, y, z))
+    error ("stem3: inconsistent size of x, y and z");
+  elseif (numel(x) != numel (y))
+    error ("stem: inconsistent size of x and y");
+  else
+    bl = get (h, "basevalue");
+    nx = numel (x);
+    x = x(:)';
+    xt = [x; x; NaN(1, nx)](:);
+    if (! isempty (z))
+      y = y(:)';
+      yt = [y; y; NaN(1, nx)](:);
+      z = z(:)';
+      zt = [bl * ones(1, nx); z; NaN(1, nx)](:);
+    else
+      y = y(:)';
+      yt = [bl * ones(1, nx); y; NaN(1, nx)](:);
+      zt = [];
+    endif
+
+    kids = get (h, "children");
+    set (kids(1), "xdata", xt, "ydata", yt, "zdata", zt)
+    set (kids(2), "xdata", x, "ydata", y, "zdata", z)
+  endif
+endfunction
--- a/scripts/plot/stem.m	Fri Aug 22 16:29:17 2008 -0400
+++ b/scripts/plot/stem.m	Mon Aug 25 15:45:24 2008 -0400
@@ -18,74 +18,51 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {Function File} {@var{h} =} stem (@var{x}, @var{y}, @var{linespec})
-## Plot a stem graph and return the handles of the line and marker
-## objects used to draw the stems.  The default color is @code{"r"}
-## (red).  The default line style is @code{"-"} and the default marker is
-## @code{"o"}.
-##
-## For example,
-## @example
-## x = 1:10;
-## stem (x);
-## @end example
-## @noindent
-## plots 10 stems with heights from 1 to 10;
+## @deftypefnx {Function File} {@var{h} =} stem (@dots{}, "filled")
+## Plot a stem graph from two vectors of x-y data. If only one argument
+## is given, it is taken as the y-values and the x coordinates are taken
+## from the indicies of the elements.
 ##
-## @example
-## x = 1:10;
-## y = ones (1, length (x))*2.*x;
-## stem (x, y);
-## @end example
-## @noindent
-## plots 10 stems with heights from 2 to 20;
-## 
-## @example
-## x = 1:10;
-## y = ones (size (x))*2.*x;
-## h = stem (x, y, "b");
-## @end example
-## @noindent
-## plots 10 bars with heights from 2 to 20
-## (the color is blue, and @var{h} is a 2-by-10 array of handles in
-## which the first row holds the line handles and
-## the second row holds the marker handles);
+## If @var{y} is a matrix, then each column of the matrix is plotted as
+## a separate stem graph. In this case @var{x} can either be a vector,
+## the same length as the number of rows in @var{y}, or it can be a
+## matrix of the same size as @var{y}.
+##
+## The default color is @code{"r"} (red). The default line style is
+## @code{"-"} and the default marker is @code{"o"}. The line style can
+## be altered by the @code{linespec} argument in the same manner as the
+## @code{plot} command. For example
 ##
 ## @example
+## @group
 ## x = 1:10;
-## y = ones (size (x))*2.*x;
-## h = stem (x, y, "-.k");
+## y = ones (1, length (x))*2.*x;
+## stem (x, y, "b");
+## @end group
 ## @end example
+##
 ## @noindent
-## plots 10 stems with heights from 2 to 20
-## (the color is black, line style is @code{"-."}, and @var{h} is a 2-by-10
-## array of handles in which the first row holds the line handles and
-## the second row holds the marker handles);
+## plots 10 stems with heights from 2 to 20 in blue;
+## 
+## The return value of @code{stem} is a vector if "stem series" graphics
+## handles, with one handle per column of the variable @var{y}. This
+## handle regroups the elements of the stem graph together as the
+## children of the "stem series" handle, allowing them to be altered
+## together. For example
 ##
 ## @example
-## x = 1:10;
-## y = ones (size (x))*2.*x;
-## h = stem (x, y, "-.k.");
+## @group
+## x = [0 : 10].';
+## y = [sin(x), cos(x)]
+## h = stem (x, y);
+## set (h(2), "color", "g");
+## set (h(1), "basevalue", -1)
+## @end group
 ## @end example
-## @noindent
-## plots 10 stems with heights from 2 to 20
-## (the color is black, line style is @code{"-."} and the marker style
-## is @code{"."}, and @var{h} is a 2-by-10 array of handles in which the
-## first row holds the line handles and the second row holds the marker
-## handles);
 ##
-## @example
-## x = 1:10;
-## y = ones (size (x))*2.*x;
-## h = stem (x, y, "fill");
-## @end example
 ## @noindent
-## plots 10 stems with heights from 2 to 20
-## (the color is rgb-triple defined, the line style is @code{"-"},
-## the marker style is @code{"o"}, and @var{h} is a 2-by-10 array of
-## handles in which the first row holds the line handles and the second
-## row holds the marker handles).
-##
-## Color definitions with rgb-triples are not valid!
+## changes the color of the second "stem series"  and moves the base line
+## of the first.
 ## @seealso{bar, barh, plot}
 ## @end deftypefn
 
@@ -134,3 +111,10 @@
 %! x = 1:10;
 %! y = ones (size (x))*2.*x;
 %! h = stem (x, y, "fill");
+
+%!demo
+%! x = [0 : 10].';
+%! y = [sin(x), cos(x)];
+%! h = stem (x, y);
+%! set (h(2), "color", "g");
+%! set (h(1), "basevalue", -1)
--- a/scripts/plot/stem3.m	Fri Aug 22 16:29:17 2008 -0400
+++ b/scripts/plot/stem3.m	Mon Aug 25 15:45:24 2008 -0400
@@ -19,9 +19,9 @@
 ## -*- texinfo -*-
 ## @deftypefn {Function File} {@var{h} =} stem3 (@var{x}, @var{y}, @var{z}, @var{linespec})
 ## Plot a three-dimensional stem graph and return the handles of the line
-## and marker objects used to draw the stems.  The default color is @code{"r"}
-## (red).  The default line style is @code{"-"} and the default marker is
-## @code{"o"}.
+## and marker objects used to draw the stems as "stem series" object.
+## The default color is @code{"r"} (red).  The default line style is
+## @code{"-"} and the default marker is @code{"o"}.
 ##
 ## For example,
 ## @example
--- a/src/ChangeLog	Fri Aug 22 16:29:17 2008 -0400
+++ b/src/ChangeLog	Mon Aug 25 15:45:24 2008 -0400
@@ -1,3 +1,14 @@
+2008-08-25  David Bateman  <dbateman@free.fr>
+
+	* graphics.cc (void gh_manager::do_execute_callback 
+	(const graphics_handle&, const octave_value&, const
+	octave_value&)): Don't pass the function handle as first arg of
+	property listener functions
+
+	* graphics.h.in (class base_properties): Add functor for caseless
+	string comparison. Use it in the property map, so that user added
+	properties are found in a case insensitive fashion.
+
 2008-08-22  John W. Eaton  <jwe@octave.org>
 
 	* symtab.h (symbol_table::inherit): Pass reference to symbol table
--- a/src/graphics.cc	Fri Aug 22 16:29:17 2008 -0400
+++ b/src/graphics.cc	Mon Aug 25 15:45:24 2008 -0400
@@ -3743,8 +3743,8 @@
       fcn = c(0).function_value ();
       if (! error_state)
         {
-          for (int i = 0; i < c.length () ; i++)
-            args(2+i) = c(i);
+          for (int i = 1; i < c.length () ; i++)
+            args(1+i) = c(i);
         }
     }
   else
--- a/src/graphics.h.in	Fri Aug 22 16:29:17 2008 -0400
+++ b/src/graphics.h.in	Mon Aug 25 15:45:24 2008 -0400
@@ -1793,7 +1793,20 @@
   handle_property uicontextmenu;
 
 protected:
-  std::map<caseless_str, property> all_props;
+  struct cmp_caseless_str 
+    {
+      bool operator () (const caseless_str &a, const caseless_str &b) const
+        {
+	  std::string a1 = a;
+	  std::transform (a1.begin (), a1.end (), a1.begin (), tolower);
+	  std::string b1 = b;
+	  std::transform (b1.begin (), b1.end (), b1.begin (), tolower);
+
+          return a1 < b1;
+        }
+    };
+
+  std::map<caseless_str, property, cmp_caseless_str> all_props;
 
 protected:
   void insert_static_property (const std::string& name, base_property& p)