octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Changeset]: Add area, bar, quiver and stair series objects


From: David Bateman
Subject: [Changeset]: Add area, bar, quiver and stair series objects
Date: Tue, 26 Aug 2008 17:43:33 +0200
User-agent: Thunderbird 2.0.0.16 (X11/20080725)

Subject says it all

D.

--
David Bateman                                address@hidden
Motorola Labs - Paris +33 1 69 35 48 04 (Ph) Parc Les Algorithmes, Commune de St Aubin +33 6 72 01 06 33 (Mob) 91193 Gif-Sur-Yvette FRANCE +33 1 69 35 77 01 (Fax) The information contained in this communication has been classified as: [x] General Business Information [ ] Motorola Internal Use Only [ ] Motorola Confidential Proprietary

# HG changeset patch
# User David Bateman <address@hidden>
# Date 1219765329 -7200
# Node ID 541f747484a40bad18d1f027444233b8d01ef897
# Parent  926624ba256e6c6679666ecae2d215178403c1b7
Add area, bar, quiver and stair series graphics objects. Document them

diff --git a/doc/ChangeLog b/doc/ChangeLog
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@ 2008-08-21  David Bateman  <address@hidden
+2008-08-26  David Bateman  <address@hidden>
+
+       * interpreter/plot.txi: Document the group objects (bar, stem,
+       stair, quiver and area series), and cllback functions.
+
 2008-08-21  David Bateman  <address@hidden>
 
        * interpreter/plot.txi: Document ezplot.
diff --git a/doc/interpreter/plot.txi b/doc/interpreter/plot.txi
--- a/doc/interpreter/plot.txi
+++ b/doc/interpreter/plot.txi
@@ -439,7 +439,9 @@ at the Octave prompt should display a th
 * Colors::
 * Line Styles::
 * Marker Styles::
-* Interaction with gnuplot::    
+* Callbacks::
+* Object Groups::
+* Graphics backends::
 @end menu
 
 @node Graphics Objects
@@ -1340,9 +1342,385 @@ of 2 is twice as large as the default, e
 of 2 is twice as large as the default, etc.
 @end table
 
address@hidden Callbacks
address@hidden Callbacks
+
+Callback functions can be associated with graphics objects and triggered
+after certain events occur. The basic structure of all callback function
+is 
+
address@hidden
address@hidden
+function mycallback (src, data)
address@hidden
+endfunction
address@hidden group
address@hidden example
+
+where @code{src} gives a handle to the source of the callback, and
address@hidden gives some event specific data. This can then be associated
+with an object either at the objects creation or later with the
address@hidden function. For example
+
address@hidden
+plot (x, "DeleteFcn", @@(s, e) disp("Window Deleted"))
address@hidden example
+
address@hidden
+where at the moment that the plot is deleted, the message "Window
+Deleted" will be displayed.
+
+Additional user arguments can be passed to callback functions, and will
+be passed after the 2 default arguments. For example
+
address@hidden
+plot (x, "DeleteFcn", {@@mycallback, "1"})
address@hidden
+function mycall (src, data, a1)
+  fprintf ("Closing plot %d\n", a1);
+endfunction
address@hidden example
+
+The basic callback functions that are available for all graphics objects
+are
+
address@hidden @bullet
address@hidden CreateFcn
+This is the callback that is called at the moment of the objects
+creation. It is not called if the object is altered in any way, and so
+it only makes sense to define this callback in the function call that
+defines the object. Callbacks that are added to @code{CreateFcn} later with
+the @code{set} function will never be executed.
+
address@hidden DeleteFcn
+This is the callback that is called at the moment an object is deleted.
+
address@hidden ButtonDownFcn
+This is the callback that is called if a mouse button is pressed while
+the pointer is over this object. Note, that the gnuplot interface does
+not respect this callback.
address@hidden itemize
+
+The object and figure that the event occurred in that resulted in the
+callback being called can be found with the @code{gcbo} and @code{gcbf}
+functions.
+
address@hidden(gcbo)
+
address@hidden(gcbf)
+
+Callbacks can equally be added to properties with the @code{addlistener}
+function described below.
+
address@hidden Object Groups
address@hidden Object Groups
+
+A number of Octave high level plot functions return groups of other
+graphics objects or they return graphics objects that are have their
+properties linked in such a way that changes to one of the properties
+results in changes in the others. A graphic object that groups other
+objects is an @code{hggroup}
+
address@hidden(hggroup)
+
+For example a simple use of a @code{hggroup} might be
+
address@hidden
address@hidden
+x = 0:0.1:10;
+hg = hggroup ();
+plot (x, sin (x), "color", [1, 0, 0], "parent", hg);
+hold on
+plot (x, cos (x), "color", [0, 1, 0], "parent", hg);
+set (hg, "visible", "off");
address@hidden group
address@hidden example
+
address@hidden
+which groups the two plots into a single object and contols their
+visiblity directly. The default properties of an @code{hggroup} are
+the same as the set of common properties for the other graphics
+objects. Additional properties can be added with the @code{addproperty}
+function. 
+
address@hidden(addproperty)
+
+Once a property in added to an @code{hggroup}, it is not linked to any
+other property of either the children of the group, or any other
+graphics object. Add so to control the way in which this newly added
+property is used, the @code{addlistener} function is used to define a
+callback function that is executed when the property is altered.
+
address@hidden(addlistener)
+
+An example of the use of these two functions might be
+
address@hidden
address@hidden
+x = 0:0.1:10;
+hg = hggroup ();
+h = plot (x, sin (x), "color", [1, 0, 0], "parent", hg);
+addproperty ("linestyle", hg, "linelinestyle", get (h, "linestyle"));
+addlistener (hg, "linestyle", @@update_props);
+hold on
+plot (x, cos (x), "color", [0, 1, 0], "parent", hg);
+
+function update_props (h, d)
+  set (get (h, "children"), "linestyle", get (h, "linestyle"));
+endfunction
address@hidden group
address@hidden example
+
address@hidden
+that adds a @code{linestyle} property to the @code{hggroup} and
+propagating any changes its its value to the children of the group.
+
+These capabilities are used in a number of basic graphics objects. 
+The @code{hggroup} objects created by the functions of Octave contain
+one or more graphics object and are used to:
+
address@hidden @bullet
address@hidden group together multiple graphics objects,
address@hidden create linked properties between different graphics objects, and
address@hidden to hide the nominal user data, from the actual data of the 
objects.
address@hidden itemize
+
address@hidden
+For example the @code{stem} function creates a stem series where each
address@hidden of the stem series contains two line objects representing
+the body and head of the stem. The @code{ydata} property of the
address@hidden of the stem series represents the head of the stem,
+whereas the body of the stem is between the baseline and this value. For
+example
+
address@hidden
address@hidden
+h = stem (1:4)
+get (h, "xdata")
address@hidden [  1   2   3   4]'
+get (get (h, "children")(1), "xdata")
address@hidden [  1   1 NaN   2   2 NaN   3   3 NaN   4   4 NaN]'
address@hidden group
address@hidden example
+
address@hidden
+shows the the difference between the @code{xdata} of the @code{hggroup}
+of a stem series object and the underlying line.
+
+The basic properties of such group objects is that they consist of one 
+or more linked @code{hggroup}, and that changes in certain properties of
+these groups are propagated to other members of the group. Whereas,
+certain properties of the members of the group only apply to the current
+member.
+
+In addition the members of the group can also be linked to other
+graphics objects through callback functions. For example the baseline of
+the @code{bar} or @code{stem} functions is a line object, whose length
+and position are automatically adjusted, based on changes to the
+corresponding hggroup elements.
+
address@hidden
+* Area series::
+* Bar series::
+* Contour groups::
+* Error bar series::
+* Line series::
+* Quiver group::
+* Scatter group::
+* Stair group::
+* Stem Series::
+* Surface group::
address@hidden menu
+
address@hidden Area series
address@hidden Area series
+
+Area series objects are created by the @code{area} function. Each of the
address@hidden elements contains a single patch object. The properties
+of the area series are
+
address@hidden @code
address@hidden basevalue
+The value where the base of the area plot is drawn.
+
address@hidden linewidth
address@hidden linestyle
+The line width and style of the edge of the patch objects making up the
+areas. @xref{Line Styles}.
+
address@hidden edgecolor
address@hidden facecolor
+The line and fill color of the patch objects making up the areas. 
@xref{Colors}.
+
address@hidden xdata
address@hidden ydata
+The x and y coordinates of the original columns of the data passed to
address@hidden prior to the cummulative summation used in the @code{area}
+function. 
address@hidden table
+
address@hidden Bar series
address@hidden Bar series
+
+Bar series objects are created by the @code{bar} or @code{barh}
+functions. Each @code{hgrroup} element contains a single patch object. 
+The properties of the bar series are
+
address@hidden @code
address@hidden showbaseline
address@hidden baseline
address@hidden basevalue
+The property @code{showbaseline} flags whether the baseline of the bar
+series is displayed (default is "on"). The handle of the graphics object
+representing the baseline is given by the @code{baseline} property and
+the y-value of the baseline by the @code{basevalue} property. 
+
+Changes to any of these property are propagated to the other members of
+the bar series and to the baseline itself. Equally changes in the
+properties of the base line itself are propagated to the members of the
+corresponding bar series.
+
address@hidden barwidth
address@hidden barlayout
address@hidden horizontal
+The property @code{barwidth} is the width of the bar corresponding to
+the @var{width} variable passed to @code{bar} or @var{barh}. Whether the
+bar series is "grouped" or "stacked" is determined by the
address@hidden property and whether the bars are horizontal or
+vertical by the @code{horizontal} property.
+
+Changes to any of these property are propagated to the other members of
+the bar series.
+
address@hidden linewidth
address@hidden linestyle
+The line width and style of the edge of the patch objects making up the
+bars. @xref{Line Styles}.
+
address@hidden edgecolor
address@hidden facecolor
+The line and fill color of the patch objects making up the bars. @xref{Colors}.
+
address@hidden xdata
+The nominal x positions of the bars. Changes in this property and
+propagated to the other members of the bar series. 
+
address@hidden ydata
+The y value of the bars in the @code{hggroup}.
address@hidden table
+
address@hidden Contour groups
address@hidden Contour groups
+
+TO BE WRITTEN
+
address@hidden Error bar series
address@hidden Error bar series
+
+TO BE WRITTEN
+
address@hidden Line series
address@hidden Line series
+
+TO BE WRITTEN
+
address@hidden Quiver group
address@hidden Quiver group
+
+Quiver series objects are created by the @code{quiver} or @code{quiver3}
+functions. Each @code{hggroup} element of the series contains three line
+objects as children representing the body and head of the arrow,
+together with a marker as the point of original of the arrows. The 
+properties of the quiver series are
+
address@hidden @code
address@hidden autoscale
address@hidden autoscalefactor
+Flag whether the length of the arrows is scaled or defined directly from
+the @var{u}, @var{v} and @var{w} data. If the arrow length is falgged
+as being scaled by the @code{autoscale} property, then the length of the
+autoscaled arrow is controlled by the @code{autoscalefactor}. 
+
address@hidden maxheadsize
+This property controls the size of the head of the arrows in the quiver
+series. The default value is 0.2.
+
address@hidden showarrowhead
+Flag whether the arrow heads are displayed in the quiver plot.
+
address@hidden color
+The RGB color or color name of the line objects of the quiver. @xref{Colors}.
+
address@hidden linewidth
address@hidden linestyle
+The line width and style of the line objects of the quiver. @xref{Line Styles}.
+
address@hidden marker
address@hidden markerfacecolor
address@hidden markersize
+The line and fill color of the marker objects at the original of the
+arrows. @xref{Colors}.
+
address@hidden xdata
address@hidden ydata
address@hidden zdata
+The origins of the values of the vector field.
+
address@hidden udata
address@hidden vdata
address@hidden wdata
+The values of the vector field to plot.
address@hidden table
+
address@hidden Scatter group
address@hidden Scatter group
+
+TO BE WRITTEN
+
address@hidden Stair group
address@hidden Stair group
+
+Stair series objects are created by the @code{stair} function. Each
address@hidden element of the series contains a single line object as a
+child representing the stair. The properties of the stair series are
+
address@hidden @code
address@hidden color
+The RGB color or color name of the line objects of the stairs. @xref{Colors}.
+
address@hidden linewidth
address@hidden linestyle
+The line width and style of the line objects of the stairs. @xref{Line Styles}.
+
address@hidden marker
address@hidden markeredgecolor
address@hidden markerfacecolor
address@hidden markersize
+The line and fill color of the markers on the stairs. @xref{Colors}.
+
address@hidden xdata
address@hidden ydata
+The original x and y data of the stairs.
address@hidden table
+
address@hidden Surface group
address@hidden Surface group
+
+TO BE WRITTEN
+
address@hidden Graphics backends
address@hidden Graphics backends
+
address@hidden(available_backends)
+
address@hidden
+* Interaction with gnuplot::
address@hidden menu
+
 @node Interaction with gnuplot
address@hidden Interaction with @code{gnuplot}
address@hidden Interaction with @code{gnuplot}
 
 @DOCSTRING(gnuplot_binary)
 
 @DOCSTRING(gnuplot_use_title_option)
+
diff --git a/scripts/ChangeLog b/scripts/ChangeLog
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -1,3 +1,23 @@ 2008-08-25  Thomas L. Scofield  <scofiel
+2008-08-26  David Bateman  <address@hidden>
+
+       * plot/__area__.m: Use __next_line_color__ rather than fixed set
+       of colors. Convert to use area series objects.
+       * plot/area.m: Update documentation to correspond to
+       the area series usage.
+       * plot/__bar.m: Pass the original rather than scaled width to
+       __bars__. 
+       * plot/__bars__.m: Convert to use bar series objects.
+       * plot/bar.m, plor/barh.m:  Update documentation to correspond to
+       the bar series usage.
+       * plot/__quiver__.m: Convert to use quiver series objects. Change
+       the default scaling and arrowsize for compatibility.
+       * plot/quiver.m:  Update documentation to correspond to
+       the quiver series usage.
+       * plot/stairs.m: Convert to use stair series objects.
+       * plot/stem.m: Don't include baseline in xlim calculation. Correct
+       test of whether baseline xdata needs updating in the update_xlim
+       callback.
+
 2008-08-25  Thomas L. Scofield  <address@hidden>
 
        * image/imwrite.m: Add ras and tiff to the list of accepted formats.
@@ -5,11 +25,14 @@ 2008-08-25  Thomas L. Scofield  <scofiel
        
 2008-08-25  David Bateman  <address@hidden>
 
+       * plot/__stem__.m: Use property inheritance and don't explicitly
+       call drawnow.
+
        * 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
+       * plot/stem.m, plot/stem3.m: Update documentation to correspond to
        the stem series usage.
 
 2008-08-22  John W. Eaton  <address@hidden>
@@ -36,11 +59,6 @@ 2008-08-20  Jaroslav Hajek <address@hidden
 
        * pkg/pkg.m (configure_make): Pass handle to is_architecture_dependent
        directly.
-
-2008-08-25  David Bateman  <address@hidden>
-
-       * plot/__stem__.m: Use property inheritance and don't explicitly
-       call drawnow.
 
 2008-08-20  David Bateman  <address@hidden>
 
diff --git a/scripts/plot/__area__.m b/scripts/plot/__area__.m
--- a/scripts/plot/__area__.m
+++ b/scripts/plot/__area__.m
@@ -20,20 +20,99 @@
 
 function retval = __area__ (ax, x, y, bv, varargin)
 
-  colors = [1, 0, 0; 0, 1, 0; 0, 0, 1; 1, 1, 0; 1, 0, 1; 0, 1, 1];
+  y0 = bv * ones (1, rows (y));
+  y0 = zeros (1, rows (y));
+  retval = [];
+  for i = 1: size (y, 2);
+    hg = hggroup ();
+    x1 = x(:, 1).';
+    y1 = y (:, i).';
+    addproperty ("xdata", hg, "data", x1);
+    addproperty ("ydata", hg, "data", y1);
 
-  x = [x(1,:); x; x(end,:)];
+    addlistener (hg, "xdata", @update_data);
+    addlistener (hg, "ydata", @update_data);
 
-  y = cumsum ([[bv, ones(1, size (y, 2) - 1)]; y;
-              [bv, ones(1, size (y, 2) - 1)]], 2);
+    if (i == 1)
+      h = patch (ax, [x1(1), x1, fliplr(x1)], [bv, y1, bv*ones(1, length(y1))],
+                __next_line_color__ (), "parent", hg, varargin{:});
+    else
+      y1 = y0 + y1;
+      h = patch (ax, [x1(1), x1, fliplr(x1)], [y0(1), y1, fliplr(y0)],
+                __next_line_color__ (), "parent", hg, varargin{:});
+    endif
 
-  retval = patch (ax, x(:,1), y(:,1), colors(1,:), varargin{:});
+    y0 = y1;
 
-  for i = 2:size(y,2)
-    tmp = patch (ax, [x(:,i); flipud(x(:,i))],
-                [y(:,i) ; flipud(y(:, i-1))], colors(i,:), varargin{:});
+    addproperty ("basevalue", hg, "data", bv);
+    addlistener (hg, "basevalue", @move_baseline); 
 
-    retval = [retval; tmp];
+    addproperty ("edgecolor", hg, "patchedgecolor", get (h, "edgecolor"));
+    addproperty ("linewidth", hg, "patchlinewidth", get (h, "linewidth"));
+    addproperty ("linestyle", hg, "patchlinestyle", get (h, "linestyle"));
+    addproperty ("facecolor", hg, "patchfacecolor", get (h, "facecolor"));
+
+    addlistener (hg, "edgecolor", @update_props);
+    addlistener (hg, "linewidth", @update_props); 
+    addlistener (hg, "linestyle", @update_props); 
+    addlistener (hg, "facecolor", @update_props); 
+
+    retval = [retval; hg];
+    addproperty ("areagroup", hg, "data");
+    set (retval, "areagroup", retval);
   endfor
 
 endfunction
+
+function update_props (h, d)
+  kids = get (h, "children");
+  set (kids, "edgecolor", get (h, "edgecolor"), 
+       "linewidth", get (h, "linewidth"),
+       "linestyle", get (h, "linestyle"),
+       "facecolor", get (h, "facecolor"));
+endfunction
+
+function move_baseline (h, d)
+  persistent recursion = false;
+
+  ## Don't allow recursion
+  if (! recursion)
+    unwind_protect
+      recursion = true;
+      hlist = get (h, "areagroup");
+      b0 = get (h, "basevalue");
+
+      for hh = hlist(:)'
+       if (hh != h )
+         b1 = get (hh, "basevalue");
+         if (b1 != b0)
+           set (hh, "basevalue", b0);
+         endif
+       endif
+      endfor
+      update_data (h, d);
+    unwind_protect_cleanup
+      recursion = false;
+    end_unwind_protect
+  endif
+endfunction
+
+function update_data (h, d)
+  hlist = get (h, "areagroup");
+  bv = get (h, "basevalue");
+  for i = 1 : length (hlist)
+    hh = hlist(i);
+    x1 = get (hh, "xdata")(:);
+    y1 = get (hh, "ydata")(:);
+
+    set (get (hh, "children"), "xdata", [x1(1); x1; flipud(x1)]);
+    if (i == 1)
+      set (get (hh, "children"), "ydata", [bv; y1; bv*ones(length(y1), 1)]);
+    else
+      y1 = y0 + y1;
+      set (get (hh, "children"), "ydata", [y0(1); y1; flipud(y0)]);
+    endif      
+
+    y0 = y1;
+  endfor
+endfunction
diff --git a/scripts/plot/__bar__.m b/scripts/plot/__bar__.m
--- a/scripts/plot/__bar__.m
+++ b/scripts/plot/__bar__.m
@@ -110,18 +110,17 @@ function varargout = __bar__ (vertical, 
   endif
 
   ycols = size (y, 2);
+  cutoff = min (diff (double(x))) / 2;
   if (group)
-    width = width / ycols;
+    delta_p = delta_m = repmat (cutoff * width / ycols, size (x));
+  else
+    delta_p = delta_m = repmat (cutoff * width, size (x));
   endif
-
-  cutoff = min (diff (double(x))) / 2;
-  delta_p = delta_m = repmat (cutoff * width, size (x));
   x1 = (x - delta_m)(:)';
   x2 = (x + delta_p)(:)';
   xb = repmat ([x1; x1; x2; x2](:), 1, ycols);
 
   if (group)
-    width = width / ycols;
     offset = ((delta_p + delta_m) * [-(ycols - 1) / 2 : (ycols - 1) / 2]);
     xb(1:4:4*ylen,:) += offset;
     xb(2:4:4*ylen,:) += offset;
diff --git a/scripts/plot/__bars__.m b/scripts/plot/__bars__.m
--- a/scripts/plot/__bars__.m
+++ b/scripts/plot/__bars__.m
@@ -20,43 +20,245 @@
 
 ## Author: jwe
 
-function tmp = __bars__ (h, vertical, x, y, xb, yb, width, group, 
have_color_spec, base_value, varargin)
-
-  ## Note, base_value is used by the Jhandles backend, which replaces
-  ## this function with its own version.
+function tmp = __bars__ (ax, vertical, x, y, xb, yb, width, group, 
have_color_spec, base_value, varargin)
 
   ycols = columns (y);
-  clim = get (h, "clim");
-
-  if (vertical)
-    tmp = [];
-    for i = 1:ycols
+  clim = get (ax, "clim");
+  tmp = [];
+
+  for i = 1:ycols
+    hg = hggroup ();
+    tmp = [tmp; hg];
+
+    if (vertical)
       if (! have_color_spec)
        if (ycols == 1)
          lev = clim(1);
        else
          lev = (i - 1) * (clim(2) - clim(1)) / (ycols - 1) - clim(1);
        endif
-       tmp = [tmp; patch(xb(:,:,i), yb(:,:,i), "FaceColor", "flat", 
-                         "cdata", lev, varargin{:})];
+       h = patch(xb(:,:,i), yb(:,:,i), "FaceColor", "flat", 
+                 "cdata", lev, "parent", hg, varargin{:});
       else
-       tmp = [tmp; patch(xb(:,:,i), yb(:,:,i), varargin{:})];
-      endif
-    endfor
-  else
-    tmp = [];
-    for i = 1:ycols
+       h = patch(xb(:,:,i), yb(:,:,i), "parent", hg, varargin{:});
+      endif
+    else
       if (! have_color_spec)
        if (ycols == 1)
          lev = clim(1)
        else
          lev = (i - 1) * (clim(2) - clim(1)) / (ycols - 1) - clim(1);
        endif
-       tmp = [tmp; patch(yb(:,:,i), xb(:,:,i), "FaceColor", "flat", 
-                         "cdata", lev, varargin{:})];
+       h = patch(yb(:,:,i), xb(:,:,i), "FaceColor", "flat", 
+                 "cdata", lev, "parent", hg, varargin{:});
       else
-       tmp = [tmp; patch(yb(:,:,i), xb(:,:,i), varargin{:})];
-      endif
-    endfor
-  endif
-endfunction
+       h = patch(yb(:,:,i), xb(:,:,i), "parent", hg, varargin{:});
+      endif
+    endif
+
+    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");
+      set (h_baseline, "xliminclude", "off");
+      addlistener (ax, "xlim", @update_xlim);
+      addlistener (h_baseline, "ydata", @update_baseline);
+      addlistener (h_baseline, "visible", @update_baseline);
+    endif
+
+    ## Setup the hggroup and listeners
+    addproperty ("showbaseline", hg, "radio", "{on}|off");
+    addproperty ("basevalue", hg, "data", base_value);
+    addproperty ("baseline", hg, "data", h_baseline);
+
+    addlistener (hg, "showbaseline", @show_baseline);
+    addlistener (hg, "basevalue", @move_baseline); 
+
+    addproperty ("barwidth", hg, "data", width);
+    if (group)
+      addproperty ("barlayout", hg, "radio", "stacked|{grouped}", "grouped");
+    else
+      addproperty ("barlayout", hg, "radio", "{stacked}|grouped", "stacked");
+    endif
+    if (vertical)
+      addproperty ("horizontal", hg, "radio", "on|{off}", "off")
+    else
+      addproperty ("horizontal", hg, "radio", "{on}|off", "on")
+    endif
+
+    addlistener (hg, "barwidth", @update_group);
+    addlistener (hg, "barlayout", @update_group);
+    addlistener (hg, "horizontal", @update_group);
+
+    addproperty ("edgecolor", hg, "patchedgecolor", get (h, "edgecolor"));
+    addproperty ("linewidth", hg, "patchlinewidth", get (h, "linewidth"));
+    addproperty ("linestyle", hg, "patchlinestyle", get (h, "linestyle"));
+    addproperty ("facecolor", hg, "patchfacecolor", get (h, "facecolor"));
+
+    addlistener (hg, "edgecolor", @update_props);
+    addlistener (hg, "linewidth", @update_props); 
+    addlistener (hg, "linestyle", @update_props); 
+    addlistener (hg, "facecolor", @update_props); 
+
+    if (isvector (x))
+      addproperty ("xdata", hg, "data", x);
+    else
+      addproperty ("xdata", hg, "data", x(:, i));
+    endif
+    addproperty ("ydata", hg, "data", y(:, i));
+ 
+    addlistener (hg, "xdata", @update_data);
+    addlistener (hg, "ydata", @update_data);
+
+    addproperty ("bargroup", hg, "data");
+    set (tmp, "bargroup", tmp);
+  endfor
+
+  update_xlim (ax, []);
+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 (any (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)
+  persistent recursion = false;
+
+  ## Don't allow recursion
+  if (! recursion)
+    unwind_protect
+      recursion = true;
+      hlist = get (h, "bargroup");
+      showbaseline = get (h, "showbaseline");
+      for hh = hlist(:)'
+       if (hh != h)
+         set (hh, "showbaseline", showbaseline);
+       endif
+      endfor
+      set (get (h, "baseline"), "visible", showbaseline);
+    unwind_protect_cleanup
+      recursion = false;
+    end_unwind_protect
+  endif
+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
+
+  if (strcmp (get (h, "barlayout"), "grouped"))
+    update_data (h, d);
+  endif
+endfunction
+
+function update_props (h, d)
+  kids = get (h, "children");
+  set (kids, "edgecolor", get (h, "edgecolor"), 
+       "linewidth", get (h, "linewidth"),
+       "linestyle", get (h, "linestyle"),
+       "facecolor", get (h, "facecolor"));
+endfunction
+
+function update_data (h, d)
+  persistent recursion = false;
+
+  ## Don't allow recursion
+  if (! recursion)
+    unwind_protect
+      recursion = true;
+      hlist = get (h, "bargroup");
+      x = get (h, "xdata");
+      if (!isvector (x))
+       x = x(:);
+      endif
+      y = [];
+      for hh = hlist(:)'
+       ytmp = get (hh, "ydata");
+       y = [y ytmp(:)];
+      endfor
+
+      [xb, yb] = bar (x, y, get (h, "barwidth"), get (h, "barlayout"),
+                     "basevalue", get (h, "basevalue"));
+      ny = columns (y);
+      vert = strcmp (get (h, "horizontal"), "off");
+
+      for i = 1:ny
+       hp = get (hlist(i), "children");
+       if (vert)
+         set (hp, "xdata", xb(:,:,i), "ydata", yb(:,:,i));
+       else
+         set (hp, "xdata", yb(:,:,i), "ydata", xb(:,:,i));
+       endif
+      endfor
+    unwind_protect_cleanup
+      recursion = false;
+    end_unwind_protect
+  endif
+endfunction
+
+function update_group (h, d)
+  persistent recursion = false;
+
+  ## Don't allow recursion
+  if (! recursion)
+    unwind_protect
+      recursion = true;
+      hlist = get (h, "bargroup");
+      barwidth = get(h, "barwidth");
+      barlayout = get (h, "barlayout");
+      horizontal = get (h, "horizontal");
+
+      ## To prevent recursion, only change if modified
+      for hh = hlist(:)'
+       if (hh != h)
+         if (get (hh, "barwidth") != barwidth)
+           set (hh, "barwidth", barwidth);
+         endif
+         if (! strcmp (get (hh, "barlayout"), barlayout))
+           set (hh, "barlayout", barlayout);
+         endif
+         if (! strcmp (get (hh, "horizontal"), horizontal))
+           set (hh, "horizontal", horizontal);
+         endif
+       endif
+      endfor
+      update_data (h, d);
+    unwind_protect_cleanup
+      recursion = false;
+    end_unwind_protect
+  endif
+endfunction
diff --git a/scripts/plot/__quiver__.m b/scripts/plot/__quiver__.m
--- a/scripts/plot/__quiver__.m
+++ b/scripts/plot/__quiver__.m
@@ -18,13 +18,13 @@
 
 ## Undocumented internal function
 
-function hlist = __quiver__ (varargin)
+function hg = __quiver__ (varargin)
 
   h = varargin{1};
   is3d = varargin{2};
 
-  s = 1;
-  arrowsize = 0.33;
+  autoscale = 0.9;
+  arrowsize = 0.2;
 
   firstnonnumeric = Inf;
   for i = 3:nargin
@@ -46,7 +46,7 @@ function hlist = __quiver__ (varargin)
     endif
     if (nargin >= ioff && isnumeric (varargin{ioff})
        && isscalar (varargin{ioff}))
-      s = varargin{ioff++};
+      autoscale = varargin{ioff++};
     endif
   else
     x = varargin{ioff++};
@@ -69,7 +69,7 @@ function hlist = __quiver__ (varargin)
     endif
     if (nargin >= ioff && isnumeric (varargin{ioff})
        && isscalar (varargin{ioff}))
-      s = varargin{ioff++};
+      autoscale = varargin{ioff++};
     endif
   endif
 
@@ -95,7 +95,7 @@ function hlist = __quiver__ (varargin)
     endif
   endwhile
 
-  if (s)
+  if (autoscale)
     ## Scale the arrows to fit in the grid
     dx = (max(x(:)) - min(x(:))) ./ size (x, 2);
     dy = (max(y(:)) - min(y(:))) ./ size (y, 1);
@@ -108,59 +108,83 @@ function hlist = __quiver__ (varargin)
       dz = 0;
     endif
     if (len > 0)
-      s = s / sqrt (2) * sqrt (dx.^2 + dy.^2 + dz.^2) / len; 
-      u = s * u;
-      v = s * v;
-      if (is3d)
-       w = s*w;
-      endif
-    endif
-  endif
-
-  x = x(:);
-  y = y(:);
-  xend = x + u(:);
-  yend = y + v(:);
-  if (is3d)
-    z = z(:);
-    zend = z + w(:);
+      s = 2 * autoscale / sqrt (2) * sqrt (dx.^2 + dy.^2 + dz.^2) / len; 
+      uu = s * u;
+      vv = s * v;
+      if (is3d)
+       ww = s*w;
+      endif
+    endif
   endif
 
   hstate = get (h, "nextplot");
   unwind_protect
+    hg = hggroup ();
+    hold on;
+
+    addproperty ("xdata", hg, "data", x);
+    addproperty ("ydata", hg, "data", y);
+
+    addproperty ("udata", hg, "data", u);
+    addproperty ("vdata", hg, "data", v);
+    if (is3d)
+      addproperty ("zdata", hg, "data", z);
+      addproperty ("wdata", hg, "data", w);
+    else
+      addproperty ("zdata", hg, "data", []);
+      addproperty ("wdata", hg, "data", []);
+    endif
+
+    addlistener (hg, "xdata", @update_data);
+    addlistener (hg, "ydata", @update_data);
+    addlistener (hg, "zdata", @update_data);
+    addlistener (hg, "udata", @update_data);
+    addlistener (hg, "vdata", @update_data);
+    addlistener (hg, "wdata", @update_data);
+
+    x = x(:);
+    y = y(:);
+    xend = x + uu(:);
+    yend = y + vv(:);
+    if (is3d)
+      z = z(:);
+      zend = z + ww(:);
+    endif
+
     if (have_line_spec)
       if (is3d)
        h1 = plot3 ([x.'; xend.'; NaN(1, length (x))](:),
                    [y.'; yend.'; NaN(1, length (y))](:),
                    [z.'; zend.'; NaN(1, length (z))](:),
                    "linestyle", linespec.linestyle, 
-                   "color", linespec.color);
+                   "color", linespec.color, "parent", hg);
       else
        h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
                   [y.'; yend.'; NaN(1, length (y))](:),
                   "linestyle", linespec.linestyle, 
-                   "color", linespec.color);
+                   "color", linespec.color, "parent", hg);
       endif
     else
       if (is3d)
        h1 = plot3 ([x.'; xend.'; NaN(1, length (x))](:),
                    [y.'; yend.'; NaN(1, length (y))](:),
-                   [z.'; zend.'; NaN(1, length (z))](:));
+                   [z.'; zend.'; NaN(1, length (z))](:),
+                   "parent", hg);
       else
        h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
-                  [y.'; yend.'; NaN(1, length (y))](:));
-      endif
-    endif
-    hold on;
-
-    xtmp = x + u(:) .* (1 - arrowsize);
-    ytmp = y + v(:) .* (1 - arrowsize);
+                  [y.'; yend.'; NaN(1, length (y))](:),
+                  "parent", hg);
+      endif
+    endif
+
+    xtmp = x + uu(:) .* (1 - arrowsize);
+    ytmp = y + vv(:) .* (1 - arrowsize);
     xarrw1 = xtmp + (y - yend) * arrowsize / 3;
     xarrw2 = xtmp - (y - yend) * arrowsize / 3;
     yarrw1 = ytmp - (x - xend) * arrowsize / 3;
     yarrw2 = ytmp + (x - xend) * arrowsize / 3;
     if (is3d)
-      zarrw1 = zarrw2 = zend - w(:) * arrowsize;
+      zarrw1 = zarrw2 = zend - ww(:) * arrowsize;
     endif
 
     if (have_line_spec)
@@ -170,11 +194,11 @@ function hlist = __quiver__ (varargin)
          h2 = plot3 ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
                      [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
                      [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
-                     "linestyle", "none");
+                     "linestyle", "none", "parent", hg);
        else
          h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
                     [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
-                    "linestyle", "none");
+                    "linestyle", "none", "parent", hg);
        endif
       else
        if (is3d)
@@ -182,47 +206,190 @@ function hlist = __quiver__ (varargin)
                      [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
                      [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
                      "linestyle", linespec.linestyle,
-                     "color", linespec.color);
+                     "color", linespec.color, "parent", hg);
        else
          h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
                     [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
                     "linestyle", linespec.linestyle,
-                     "color", linespec.color);
+                     "color", linespec.color, "parent", hg);
        endif
       endif
     elseif (is3d)
       h2 = plot3 ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
                  [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
-                 [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:));
+                 [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
+                 "parent", hg);
     else
       h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
-                [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:));
+                [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
+                "parent", hg);
     endif
 
     if (! have_line_spec
        || (isfield (linespec, "marker")
            && strncmp (linespec.marker, "none", 4)))
       if (is3d)
-       h3 = plot3 (x, y, z, "linestyle", "none", "marker", "none");
-      else
-       h3 = plot (x, y, "linestyle", "none", "marker", "none");
-      endif
-    else
-      if (is3d)
-       h3 = plot3 (x, y, z, "linestyle", "none", "marker", linespec.marker);
-      else
-
-       h3 = plot (x, y, "linestyle", "none", "marker", linespec.marker);
+       h3 = plot3 (x, y, z, "linestyle", "none", "marker", "none", 
+                   "parent", hg);
+      else
+       h3 = plot (x, y, "linestyle", "none", "marker", "none", "parent", hg);
+      endif
+    else
+      if (is3d)
+       h3 = plot3 (x, y, z, "linestyle", "none", "marker", linespec.marker,
+                   "parent", hg);
+      else
+
+       h3 = plot (x, y, "linestyle", "none", "marker", linespec.marker,
+                  "parent", hg);
       endif
     endif
     if (have_filled)
       ## FIXME gnuplot doesn't respect the markerfacecolor field
       set (h3, "markerfacecolor", get (h1, "color")); 
     endif
+
+    ## Set up the hggroup properties and listeners
+    if (autoscale)
+      addproperty ("autoscale", hg, "radio", "{on}|off", "on");
+      addproperty ("autoscalefactor", hg, "data", autoscale)
+    else
+      addproperty ("autoscale", hg, "radio", "{on}|off", "off");
+      addproperty ("autoscalefactor", hg, "data", 1.0)
+    endif
+    addlistener (hg, "autoscale", @update_data)
+    addlistener (hg, "autoscalefactor", @update_data)
+
+    addproperty ("maxheadsize", hg, "data", arrowsize)
+    addlistener (hg, "maxheadsize", @update_data);
+
+    addproperty ("showarrowhead", hg, "radio", "{on}|off", "on");
+    addlistener (hg, "showarrowhead", @update_props);
+
+    addproperty ("color", hg, "linecolor", get (h1, "color"));
+    addproperty ("linewidth", hg, "linelinewidth", get (h1, "linewidth"));
+    addproperty ("linestyle", hg, "linelinestyle", get (h1, "linestyle"));
+    addproperty ("marker", hg, "linemarker", get (h3, "marker"));
+    addproperty ("markerfacecolor", hg, "linemarkerfacecolor",
+                get (h3, "markerfacecolor"));
+    addproperty ("markersize", hg, "linemarkersize", get (h3, "markersize"));
+
+    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);
+
   unwind_protect_cleanup
     set (h, "nextplot", hstate);
   end_unwind_protect
 
-  hlist = [h1; h2; h3];
-
 endfunction
+
+function update_data (h, d)
+  x = get (h, "xdata");
+  y = get (h, "ydata");
+  z = get (h, "zdata");
+
+  u = get (h, "udata");
+  v = get (h, "vdata");
+  w = get (h, "wdata");
+
+  s = get (h, "autoscalefactor");
+  arrowsize = get (h, "maxheadsize");
+
+  kids = get (h, "children");
+
+  if (isempty (z) || isempty (w))
+    is3d = false;
+  else
+    is3d = true;
+  endif
+
+  if (strcmp (get (h, "autoscale"), "on") && s != 0)
+    ## Scale the arrows to fit in the grid
+    dx = (max(x(:)) - min(x(:))) ./ size (x, 2);
+    dy = (max(y(:)) - min(y(:))) ./ size (y, 1);
+    if (is3d)
+      ## What should this be divided by? The below seems right
+      dz = (max(z(:)) - min(z(:))) ./ max (size (z));
+      len = max (sqrt (u(:).^2 + dy(:).^2) + dz(:).^2);
+    else
+      len = max (sqrt (u(:).^2 + dy(:).^2));
+      dz = 0;
+    endif
+    if (len > 0)
+      s = 2 * s / sqrt (2) * sqrt (dx.^2 + dy.^2 + dz.^2) / len; 
+      u = s * u;
+      v = s * v;
+      if (is3d)
+       w = s*w;
+      endif
+    endif
+  endif
+
+  x = x(:);
+  y = y(:);
+  xend = x + u(:);
+  yend = y + v(:);
+  if (is3d)
+    z = z(:);
+    zend = z + w(:);
+  endif
+
+  set (kids (1), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
+  set (kids (1), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
+  if (is3d)
+    set (kids (1), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
+  endif
+
+  xtmp = x + u(:) .* (1 - arrowsize);
+  ytmp = y + v(:) .* (1 - arrowsize);
+  xarrw1 = xtmp + (y - yend) * arrowsize / 3;
+  xarrw2 = xtmp - (y - yend) * arrowsize / 3;
+  yarrw1 = ytmp - (x - xend) * arrowsize / 3;
+  yarrw2 = ytmp + (x - xend) * arrowsize / 3;
+  if (is3d)
+    zarrw1 = zarrw2 = zend - w(:) * arrowsize;
+  endif
+
+  set (kids (2), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
+  set (kids (2), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
+  if (is3d)
+    set (kids (2), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
+  endif
+
+  set (kids (2), "xdata", [xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:));
+  set (kids (2), "ydata", [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:));
+  if (is3d)
+    set (kids (2), "zdata", [zarrw1.'; zend.'; zarrw2.'; NaN(1, length 
(z))](:));
+  endif
+
+  set (kids (3), "xdata", x);
+  set (kids (3), "ydata", y);
+  if (is3d)
+    set (kids (3), "zdata", z);
+  endif
+
+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"), 
+       "linewidth", get (h, "linewidth"),
+       "linestyle", get (h, "linestyle"));
+  if (strcmp (get (h, "showarrowhead"), "on"))
+    set (kids (2), "visible", "on");
+  else
+    set (kids (2), "visible", "off");
+  endif
+  set (kids(3), "color", get (h, "color"), 
+       "marker", get (h, "marker"),
+       "markerfacecolor", get (h, "markerfacecolor"),
+       "markersize", get (h, "markersize"));
+endfunction
diff --git a/scripts/plot/__stem__.m b/scripts/plot/__stem__.m
--- a/scripts/plot/__stem__.m
+++ b/scripts/plot/__stem__.m
@@ -97,6 +97,7 @@ function h = __stem__ (have_z, varargin)
          x_axis_range = get (ax, "xlim");
          h_baseline = line (x_axis_range, [0, 0], "color", [0, 0, 0]);
          set (h_baseline, "handlevisibility", "off");
+         set (h_baseline, "xliminclude", "off");
          addlistener (ax, "xlim", @update_xlim);
          addlistener (h_baseline, "ydata", @update_baseline);
          addlistener (h_baseline, "visible", @update_baseline);
@@ -428,7 +429,7 @@ function update_xlim (h, d)
   for i = 1 : length (kids)
     obj = get (kids (i));
     if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline"))
-      if (get (obj.baseline, "xdata") != xlim)
+      if (any (get (obj.baseline, "xdata") != xlim))
        set (obj.baseline, "xdata", xlim);
       endif
     endif
diff --git a/scripts/plot/area.m b/scripts/plot/area.m
--- a/scripts/plot/area.m
+++ b/scripts/plot/area.m
@@ -34,7 +34,7 @@
 ##
 ## Additional arguments to the @code{area} function are passed to the 
 ## @code{patch}. The optional return value @var{h} provides a handle to 
-## the list of patch objects.
+## area series object representing the patches of the areas.
 ## @seealso{plot, patch}
 ## @end deftypefn
 
diff --git a/scripts/plot/bar.m b/scripts/plot/bar.m
--- a/scripts/plot/bar.m
+++ b/scripts/plot/bar.m
@@ -37,12 +37,27 @@
 ## argument, which can take the values @code{"grouped"} (the default),
 ## or @code{"stacked"}.
 ##
-## The optional return value @var{h} provides a handle to the patch object.
-## Whereas the option input handle @var{h} allows an axis handle to be passed.
-## Properties of the patch graphics object can be changed using 
+## The optional return value @var{h} provides a handle to the "bar series"
+## object with one handle per column of the variable @var{y}. This
+## series allows common elements of the group of bar series objects to
+## be changed in a single bar series and the same properties are changed
+## in the other "bar series". For example
+##
+## @example
+## @group
+## h = bar (rand (5, 10));
+## set (h(1), "basevalue", 0.5);
+## @end group
+## @end example
+##
+## @noindent
+## changes the position on the base of all of the bar series.
+##
+## The optional input handle @var{h} allows an axis handle to be passed.
+## Properties of the patch graphics object can be changed using
 ## @var{prop}, @var{val} pairs.
 ##
-## @seealso{barh, plot}
+## @seealso{barh, plot} 
 ## @end deftypefn
 
 ## Author: jwe
diff --git a/scripts/plot/barh.m b/scripts/plot/barh.m
--- a/scripts/plot/barh.m
+++ b/scripts/plot/barh.m
@@ -36,9 +36,11 @@
 ## argument, which can take the values @code{"grouped"} (the default),
 ## or @code{"stacked"}.
 ##
-## The optional return value @var{h} provides a handle to the patch object.
-## Whereas the option input handle @var{h} allows an axis handle to be passed.
-## Properties of the patch graphics object can be changed using 
+## The optional return value @var{h} provides a handle to the bar series
+## object. See @code{bar} for a description of the use of the bar series.
+##
+## The optional input handle @var{h} allows an axis handle to be passed.
+## Properties of the patch graphics object can be changed using
 ## @var{prop}, @var{val} pairs.
 ##
 ## @seealso{bar, plot}
diff --git a/scripts/plot/quiver.m b/scripts/plot/quiver.m
--- a/scripts/plot/quiver.m
+++ b/scripts/plot/quiver.m
@@ -43,13 +43,15 @@
 ## printed rather than arrows. If the argument 'filled' is given then the
 ## markers as filled.
 ##
-## The optional return value @var{h} provides a list of handles to the 
-## the parts of the vector field (body, arrow and marker).
+## The optional return value @var{h} provides a quiver group that
+## regroups the components of the quiver plot (body, arrow and marker),
+## and allows them to be changed together
 ##
 ## @example
 ## @group
 ## [x, y] = meshgrid (1:2:20);
-## quiver (x, y, sin (2*pi*x/10), sin (2*pi*y/10));
+## h = quiver (x, y, sin (2*pi*x/10), sin (2*pi*y/10));
+## set (h, "maxheadsize", 0.33);
 ## @end group
 ## @end example
 ##
@@ -81,7 +83,8 @@ endfunction
 
 %!demo
 %! [x,y] = meshgrid(1:2:20);
-%! quiver(x,y,sin(2*pi*x/10),sin(2*pi*y/10))
+%! h = quiver(x,y,sin(2*pi*x/10),sin(2*pi*y/10))
+%! set (h, "maxheadsize", 0.33);
 
 %!demo
 %! axis("equal");
diff --git a/scripts/plot/quiver3.m b/scripts/plot/quiver3.m
--- a/scripts/plot/quiver3.m
+++ b/scripts/plot/quiver3.m
@@ -43,8 +43,9 @@
 ## printed rather than arrows. If the argument 'filled' is given then the
 ## markers as filled.
 ##
-## The optional return value @var{h} provides a list of handles to the 
-## the parts of the vector field (body, arrow and marker).
+## The optional return value @var{h} provides a quiver group that
+## regroups the components of the quiver plot (body, arrow and marker),
+## and allows them to be changed together
 ##
 ## @example
 ## @group
@@ -52,7 +53,8 @@
 ## surf (x, y, z);
 ## hold on;
 ## [u, v, w] = surfnorm (x, y, z / 10);
-## quiver3 (x, y, z, u, v, w);
+## h = quiver3 (x, y, z, u, v, w);
+## set (h, "maxheadsize", 0.33);
 ## @end group
 ## @end example
 ##
@@ -96,4 +98,5 @@ endfunction
 %! surf (x, y, z);
 %! hold on;
 %! [u, v, w] = surfnorm (x, y, z / 10);
-%! quiver3 (x, y, z, u, v, w);
+%! h = quiver3 (x, y, z, u, v, w);
+%! set (h, "maxheadsize", 0.33);
diff --git a/scripts/plot/stairs.m b/scripts/plot/stairs.m
--- a/scripts/plot/stairs.m
+++ b/scripts/plot/stairs.m
@@ -128,17 +128,59 @@ function [h, xs, ys] = __stairs__ (doplo
   xs(1,:) = x(1,:);
   ys(1,:) = y(1,:);
 
-  x = x(2:nr,:);
+  xtmp = x(2:nr,:);
   ridx = 2:2:len-1;
-  xs(ridx,:) = x;
+  xs(ridx,:) = xtmp;
   ys(ridx,:) = y(1:nr-1,:);
 
   ridx = 3:2:len;
-  xs(ridx,:) = x;
+  xs(ridx,:) = xtmp;
   ys(ridx,:) = y(2:nr,:);
 
   if (doplot)
-    h = plot (xs, ys, varargin{idx+1:end});
+    h = [];
+    unwind_protect
+      hold_state = get (gca (), "nextplot");
+      for i = 1 : size(y, 2)
+       hg = hggroup ();
+       h = [h; hg];
+
+       if (i == 1)
+         set (gca (), "nextplot", "add");
+       endif
+
+       addproperty ("xdata", hg, "data", x(:,i).');
+       addproperty ("ydata", hg, "data", y(:,i).');
+
+       addlistener (hg, "xdata", @update_data);
+       addlistener (hg, "ydata", @update_data);
+
+       tmp = line (xs(:,i).', ys(:,i).', "color", __next_line_color__ (),
+                   "parent", hg, varargin{idx+1:end});
+       
+        addproperty ("color", hg, "linecolor", get (tmp, "color"));
+       addproperty ("linewidth", hg, "linelinewidth", get (tmp, "linewidth"));
+       addproperty ("linestyle", hg, "linelinestyle", get (tmp, "linestyle"));
+
+       addproperty ("marker", hg, "linemarker", get (tmp, "marker"));
+       addproperty ("markerfacecolor", hg, "linemarkerfacecolor",
+                    get (tmp, "markerfacecolor"));
+       addproperty ("markeredgecolor", hg, "linemarkeredgecolor",
+                    get (tmp, "markeredgecolor"));
+       addproperty ("markersize", hg, "linemarkersize",
+                    get (tmp, "markersize"));
+
+       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, "markeredgecolor", @update_props); 
+       addlistener (hg, "markersize", @update_props); 
+      endfor
+    unwind_protect_cleanup
+      set (gca (), "nextplot", hold_state);
+    end_unwind_protect
   else
     h = 0;
   endif
@@ -148,10 +190,43 @@ endfunction
 %!demo
 %! x = 1:10;
 %! y = rand (1, 10);
-## stairs (x, y);
+%! stairs (x, y);
 
 %!demo
 %! x = 1:10;
 %! y = rand (1, 10);
 %! [xs, ys] = stairs (x, y);
 %! plot (xs, ys);
+
+function update_props (h, d)
+  set (get (h, "children"), "color", get (h, "color"), 
+       "linewidth", get (h, "linewidth"),
+       "linestyle", get (h, "linestyle"),
+       "marker", get (h, "marker"),
+       "markerfacecolor", get (h, "markerfacecolor"),
+       "markeredgecolor", get (h, "markeredgecolor"),
+       "markersize", get (h, "markersize"));
+endfunction
+
+function update_data (h, d)
+  x = get (h, "xdata");
+  y = get (h, "ydata");
+
+  nr = length (x);
+  len = 2 * nr - 1;
+  xs = ys = zeros (1, len);
+
+  xs(1) = x(1);
+  ys(1) = y(1);
+
+  xtmp = x(2:nr);
+  ridx = 2:2:len-1;
+  xs(ridx) = xtmp;
+  ys(ridx) = y(1:nr-1);
+
+  ridx = 3:2:len;
+  xs(ridx) = xtmp;
+  ys(ridx) = y(2:nr);
+
+  set (get (h, "children"), "xdata", xs, "ydata", ys);
+endfunction

reply via email to

[Prev in Thread] Current Thread [Next in Thread]