changeset 17671:ddfc1600a311

Overhaul quiver/quiver3 functions. * scripts/plot/draw/private/__quiver__.m: Scale arrowsize parameter internally from 0.2 to 1/3 to match Matlab visual results. Assume meshgridded input for 2-D inputs. For vectors, assume a square grid with side length = sqrt (numel (x)). Use __next_line_color__, rather than assuming 'k', if no colorspec is given. Ignore second input to listeners with '~'. Set multiple graphic properties at onec to reduce overhead in calling get/set. * scripts/plot/draw/quiver.m: Update docstring. Replace 'retval' with 'h' to match function documentation. Use common unwind_protect sequence with call to newplot. Add titles to %!demos. * scripts/plot/draw/quiver3.m: Update docstring. Replace 'retval' with 'h' to match function documentation. Use common unwind_protect sequence with call to newplot. Add titles to %!demos.
author Rik <rik@octave.org>
date Thu, 17 Oct 2013 08:58:50 -0700
parents ea9df126c9a5
children 36917b3db6b2
files scripts/plot/draw/private/__quiver__.m scripts/plot/draw/quiver.m scripts/plot/draw/quiver3.m
diffstat 3 files changed, 172 insertions(+), 201 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/plot/draw/private/__quiver__.m	Wed Oct 16 15:24:40 2013 -0700
+++ b/scripts/plot/draw/private/__quiver__.m	Thu Oct 17 08:58:50 2013 -0700
@@ -27,15 +27,19 @@
   is3d = varargin{2};
 
   autoscale = 0.9;
-  arrowsize = 0.2;
+  ## Matlab uses 0.2, but Octave's algorithm produces equivalent visual
+  ## results if arrowsize=0.33.  Since this is just a non-dimensional
+  ## scaling factor we scale the arrowsize property value by 0.33/0.20
+  ## in order to get equivalent visual results while keeping equivalent
+  ## property values.
+  arrowsize = 0.20;
 
-  firstnonnumeric = Inf;
-  for i = 3:nargin
-    if (! isnumeric (varargin{i}))
-      firstnonnumeric = i;
-      break;
-    endif
-  endfor
+  firstnonnumeric = find (! cellfun ("isnumeric", varargin(3:nargin)), 1);
+  if (isempty (firstnonnumeric))
+    firstnonnumeric = Inf;
+  else
+    firstnonnumeric += 2;
+  endif
 
   ioff = 3;
   if (nargin < (6 + is3d) || firstnonnumeric < (6 + is3d))
@@ -88,34 +92,37 @@
       [linespec, valid] = __pltopt__ ("quiver", arg, false);
       if (valid)
         have_line_spec = true;
-        if (strcmp (linespec.linestyle, "none"))
+        if (isempty (linespec.linestyle) || strcmp (linespec.linestyle, "none"))
           linespec.linestyle = "-";
         endif
       else
-        args {end + 1} = arg;
+        args{end+1} = arg;
         if (ioff <= nargin)
-          args {end + 1} = varargin{ioff++};
+          args{end+1} = varargin{ioff++};
         endif
       endif
     else
-      args {end + 1} = arg;
+      args{end+1} = arg;
       if (ioff <= nargin)
-        args {end + 1} = varargin{ioff++};
+        args{end+1} = varargin{ioff++};
       endif
     endif
   endwhile
 
+  ## Normalize 0.20 to 1/3 for plotting
+  arrowsize /= 0.20 * 3;
+
   if (autoscale && numel (u) > 1)
     ## Scale the arrows to fit in the grid
     if (isvector (x))
-      ny = nx = length (x);
+      nx = ny = sqrt (length (x));
     else
-      [nx, ny] = size (x);
+      [ny, nx] = size (x);  # assume meshgrid fmt, x in columns, y in rows
     endif
-    dx = (max (x(:)) - min (x(:))) ./ nx;
-    dy = (max (y(:)) - min (y(:))) ./ ny;
+    dx = (max (x(:)) - min (x(:))) / nx;
+    dy = (max (y(:)) - min (y(:))) / ny;
     if (is3d)
-      dz = (max (z(:)) - min (z(:))) ./ max (size (z));
+      dz = (max (z(:)) - min (z(:))) / max (nx, ny);
       len = max (sqrt (u(:).^2 + v(:).^2 + w(:).^2));
     else
       dz = 0;
@@ -124,14 +131,14 @@
     if (len > 0)
       sd = sqrt (dx.^2 + dy.^2 + dz.^2) / len;
       if (sd != 0)
-        s = sqrt (2) * autoscale * sd;
-      else # special case of identical points with multiple vectors
+        s = autoscale * sd;
+      else  # special case of identical points with multiple vectors
         s = autoscale;
       endif
       uu = s * u;
       vv = s * v;
       if (is3d)
-        ww = s*w;
+        ww = s * w;
       endif
     endif
   else
@@ -144,6 +151,16 @@
 
   hstate = get (h, "nextplot");
   unwind_protect
+
+    if (have_line_spec)
+      ls = linespec.linestyle;
+      lc = linespec.color;
+    else
+      ls = "-";
+      lc = __next_line_color__ ();
+    endif
+
+    ## Must occur after __next_line_color__ in order to work correctly.
     hg = hggroup ();
     if (is3d)
       args = __add_datasource__ ("quiver3", hg,
@@ -183,105 +200,64 @@
       zend = z + ww(:);
     endif
 
+    ## Draw arrow shaft as one line object
+    if (is3d)
+      h1 = plot3 ([x.'; xend.'; NaN(1, length (x))](:),
+                  [y.'; yend.'; NaN(1, length (y))](:),
+                  [z.'; zend.'; NaN(1, length (z))](:),
+                  "linestyle", ls, "color", lc, "parent", hg);
+    else
+      h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
+                 [y.'; yend.'; NaN(1, length (y))](:),
+                 "linestyle", ls, "color", lc, "parent", hg);
+    endif
+
+    xtmp = x + uu(:) * (1 - arrowsize);
+    ytmp = y + vv(:) * (1 - arrowsize);
+
+    if (is3d)
+      xydist = sqrt (uu(:).^2 + vv(:).^2 + ww(:).^2) ./ ...
+                 (sqrt (uu(:).^2 + vv(:).^2) + eps);
+      xarrw1 = xtmp + vv(:) .* xydist * arrowsize / 4;
+      xarrw2 = xtmp - vv(:) .* xydist * arrowsize / 4;
+      yarrw1 = ytmp - uu(:) .* xydist * arrowsize / 4;
+      yarrw2 = ytmp + uu(:) .* xydist * arrowsize / 4;
+      zarrw1 = zarrw2 = zend - ww(:) * arrowsize;
+    else
+      xarrw1 = xtmp + vv(:) * arrowsize / 3;
+      xarrw2 = xtmp - vv(:) * arrowsize / 3;
+      yarrw1 = ytmp - uu(:) * arrowsize / 3;
+      yarrw2 = ytmp + uu(:) * arrowsize / 3;
+    endif
+
+    ## Draw arrowhead as one line object
     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, "parent", hg);
-      else
-        h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
-                   [y.'; yend.'; NaN(1, length (y))](:),
-                   "linestyle", linespec.linestyle,
-                    "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))](:),
-                    "color", "black", "parent", hg);
-      else
-        h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
-                   [y.'; yend.'; NaN(1, length (y))](:),
-                   "parent", hg);
+      if (! isempty (linespec.marker) && ! strcmp (linespec.marker, "none"))
+        ls = "none";  # No arrowhead drawn when marker present
       endif
     endif
 
-    xtmp = x + uu(:) .* (1 - arrowsize);
-    ytmp = y + vv(:) .* (1 - arrowsize);
-
     if (is3d)
-      xarrw1 = xtmp + sqrt((y - yend).^2 + (z - zend).^2) * arrowsize / 3;
-      xarrw2 = xtmp - sqrt((y - yend).^2 + (z - zend).^2) * arrowsize / 3;
-      yarrw1 = ytmp - sqrt((x - xend).^2 + (z - zend).^2) * arrowsize / 3;
-      yarrw2 = ytmp + sqrt((x - xend).^2 + (z - zend).^2) * arrowsize / 3;
-
-      zarrw1 = zarrw2 = zend - ww(:) * arrowsize;
-    else
-      xarrw1 = xtmp + (y - yend) * arrowsize / 3;
-      xarrw2 = xtmp - (y - yend) * arrowsize / 3;
-      yarrw1 = ytmp - (x - xend) * arrowsize / 3;
-      yarrw2 = ytmp + (x - xend) * arrowsize / 3;
-    endif
-
-    if (have_line_spec)
-      if (isfield (linespec, "marker")
-          && ! strcmp (linespec.marker, "none"))
-        if (is3d)
-          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", "parent", hg);
-        else
-          h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
-                     [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
-                     "linestyle", "none", "parent", hg);
-        endif
-      else
-        if (is3d)
-          h2 = plot3 ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
-                      [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
-                      [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
-                      "linestyle", linespec.linestyle,
-                      "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, "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))](:),
-                  "color", "black", "parent", hg);
+                  "linestyle", ls, "color", lc, "parent", hg);
     else
       h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
                  [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
-                 "parent", hg);
+                  "linestyle", ls, "color", lc, "parent", hg);
     endif
 
-    if (! have_line_spec
-        || (isfield (linespec, "marker")
-            && strcmp (linespec.marker, "none")))
-      if (is3d)
-        h3 = plot3 (x, y, z, "linestyle", "none", "marker", "none",
-                    "parent", hg);
-      else
-        h3 = plot (x, y, "linestyle", "none", "marker", "none", "parent", hg);
-      endif
+    ## Draw arrow base marker as a third line object
+    if (! have_line_spec || isempty (linespec.marker))
+      mk = "none";
     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
+      mk = linespec.marker;
+    endif
+    if (is3d)
+      h3 = plot3 (x, y, z, "linestyle", "none", "marker", mk, "parent", hg);
+    else
+      h3 = plot (x, y, "linestyle", "none", "marker", mk, "parent", hg);
     endif
     if (have_filled)
       ## FIXME: gnuplot doesn't respect the markerfacecolor field
@@ -299,23 +275,23 @@
     addlistener (hg, "autoscale", @update_data);
     addlistener (hg, "autoscalefactor", @update_data);
 
-    addproperty ("maxheadsize", hg, "data", arrowsize);
+    addproperty ("maxheadsize", hg, "data", arrowsize * .20*3);
     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 ("linestyle", hg, "linelinestyle", get (h1, "linestyle"));
     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, "linestyle", @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);
@@ -332,7 +308,8 @@
 
 endfunction
 
-function update_data (h, d)
+function update_data (h, ~)
+
   x = get (h, "xdata");
   y = get (h, "ydata");
   z = get (h, "zdata");
@@ -343,6 +320,7 @@
 
   s = get (h, "autoscalefactor");
   arrowsize = get (h, "maxheadsize");
+  arrowsize /= 0.20 * 3;
 
   kids = get (h, "children");
 
@@ -352,17 +330,17 @@
     is3d = true;
   endif
 
-  if (strcmpi (get (h, "autoscale"), "on") && s != 0)
+  if (strcmp (get (h, "autoscale"), "on") && s != 0)
     ## Scale the arrows to fit in the grid
     if (isvector (x))
-      ny = nx = length (x);
+      nx = ny = sqrt (length (x));
     else
-      [nx, ny] = size (x);
+      [ny, nx] = size (x);
     endif
-    dx = (max (x(:)) - min (x(:))) ./ nx;
-    dy = (max (y(:)) - min (y(:))) ./ ny;
+    dx = (max (x(:)) - min (x(:))) / nx;
+    dy = (max (y(:)) - min (y(:))) / ny;
     if (is3d)
-      dz = (max (z(:)) - min (z(:))) ./ max (size (z));
+      dz = (max (z(:)) - min (z(:))) / max (nx, ny);
       len = max (sqrt (u(:).^2 + v(:).^2 + w(:).^2));
     else
       dz = 0;
@@ -371,12 +349,12 @@
     if (len > 0)
       sd = sqrt (dx.^2 + dy.^2 + dz.^2) / len;
       if (sd != 0)
-        s *= sqrt (2) * sd;
+        s *= sd;
       endif
       u = s * u;
       v = s * v;
       if (is3d)
-        w = s*w;
+        w = s * w;
       endif
     endif
   endif
@@ -390,59 +368,57 @@
     zend = z + w(:);
   endif
 
-  set (kids (3), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
-  set (kids (3), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
+  set (kids(3), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
+  set (kids(3), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
   if (is3d)
-    set (kids (3), "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;
+    set (kids(3), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
   endif
 
-  set (kids (2), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
-  set (kids (2), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
+  xtmp = x + u(:) * (1 - arrowsize);
+  ytmp = y + v(:) * (1 - arrowsize);
+
   if (is3d)
-    set (kids (2), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
+    xydist = sqrt (u(:).^2 + v(:).^2 + w(:).^2) ./ ...
+               (sqrt (u(:).^2 + v(:).^2) + eps);
+    xarrw1 = xtmp + v(:) .* xydist * arrowsize / 4;
+    xarrw2 = xtmp - v(:) .* xydist * arrowsize / 4;
+    yarrw1 = ytmp - u(:) .* xydist * arrowsize / 4;
+    yarrw2 = ytmp + u(:) .* xydist * arrowsize / 4;
+    zarrw1 = zarrw2 = zend - w(:) * arrowsize;
+  else
+    xarrw1 = xtmp + v(:) * arrowsize / 3;
+    xarrw2 = xtmp - v(:) * arrowsize / 3;
+    yarrw1 = ytmp - u(:) * arrowsize / 3;
+    yarrw2 = ytmp + u(:) * arrowsize / 3;
   endif
 
-  set (kids (2), "xdata", [xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:));
-  set (kids (2), "ydata", [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:));
+  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", [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:));
+    set (kids(2), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
   endif
 
-  set (kids (1), "xdata", x);
-  set (kids (1), "ydata", y);
+  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 (1), "zdata", z);
+    set (kids(2), "zdata", [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:));
+  endif
+
+  set (kids(1), "xdata", x);
+  set (kids(1), "ydata", y);
+  if (is3d)
+    set (kids(1), "zdata", z);
   endif
 
 endfunction
 
-function update_props (h, d)
+function update_props (h, ~)
   kids = get (h, "children");
 
-  set (kids(3), "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 (strcmpi (get (h, "showarrowhead"), "on"))
-    set (kids (2), "visible", "on");
-  else
-    set (kids (2), "visible", "off");
-  endif
-  set (kids(1), "color", get (h, "color"),
-       "marker", get (h, "marker"),
-       "markerfacecolor", get (h, "markerfacecolor"),
-       "markersize", get (h, "markersize"));
+  set (kids([3 2]), {"color", "linestyle", "linewidth"},
+            get (h, {"color", "linestyle", "linewidth"}));
+  set (kids(2), "visible", get (h, "showarrowhead"));
+  set (kids(1), {"color", "marker", "markerfacecolor", "markersize"},
+        get (h, {"color", "marker", "markerfacecolor", "markersize"}));
 endfunction
 
--- a/scripts/plot/draw/quiver.m	Wed Oct 16 15:24:40 2013 -0700
+++ b/scripts/plot/draw/quiver.m	Thu Oct 17 08:58:50 2013 -0700
@@ -35,13 +35,13 @@
 ##
 ## The variable @var{s} is a scalar defining a scaling factor to use for
 ## the arrows of the field relative to the mesh spacing.  A value of 0
-## disables all scaling.  The default value is 1.
+## disables all scaling.  The default value is 0.9.
 ##
 ## The style to use for the plot can be defined with a line style @var{style}
 ## of the same format as the @code{plot} command.
 ## If a marker is specified then markers at the grid points of the vectors are
-## drawn rather than arrows.  If the argument @qcode{"filled"} is given then the
-## markers are filled.
+## drawn rather than arrows.  If the argument @qcode{"filled"} is given then
+## the markers are filled.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axis,
 ## rather than the current axes returned by @code{gca}.
@@ -50,6 +50,8 @@
 ## A quiver object regroups the components of the quiver plot (body, arrow,
 ## and marker), and allows them to be changed together.
 ##
+## Example:
+##
 ## @example
 ## @group
 ## [x, y] = meshgrid (1:2:20);
@@ -61,29 +63,29 @@
 ## @seealso{quiver3, compass, feather, plot}
 ## @end deftypefn
 
-function retval = quiver (varargin)
+function h = quiver (varargin)
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("quiver", varargin{:});
 
   if (nargin < 2)
     print_usage ();
-  else
+  endif
+
   oldfig = [];
   if (! isempty (hax))
     oldfig = get (0, "currentfigure");
   endif
-    unwind_protect
-      hax = newplot (hax);
-      htmp = __quiver__ (hax, false, varargin{:});
-    unwind_protect_cleanup
+  unwind_protect
+    hax = newplot (hax);
+    htmp = __quiver__ (hax, false, varargin{:});
+  unwind_protect_cleanup
     if (! isempty (oldfig))
       set (0, "currentfigure", oldfig);
     endif
-    end_unwind_protect
-  endif
+  end_unwind_protect
 
   if (nargout > 0)
-    retval = htmp;
+    h = htmp;
   endif
 
 endfunction
@@ -93,14 +95,15 @@
 %! clf;
 %! [x,y] = meshgrid (1:2:20);
 %! h = quiver (x,y, sin (2*pi*x/10), sin (2*pi*y/10));
-%! set (h, 'maxheadsize', 0.33);
+%! title ('quiver plot')
 
 %!demo
 %! clf;
-%! axis ('equal');
 %! x = linspace (0, 3, 80);
 %! y = sin (2*pi*x);
 %! theta = 2*pi*x + pi/2;
-%! quiver (x, y, sin (theta)/10, cos (theta)/10);
+%! quiver (x, y, sin (theta)/10, cos (theta)/10, 0.4);
+%! axis equal tight;
 %! hold on; plot (x,y,'r'); hold off;
+%! title ('quiver() with scaled arrows');
 
--- a/scripts/plot/draw/quiver3.m	Wed Oct 16 15:24:40 2013 -0700
+++ b/scripts/plot/draw/quiver3.m	Thu Oct 17 08:58:50 2013 -0700
@@ -35,7 +35,7 @@
 ##
 ## The variable @var{s} is a scalar defining a scaling factor to use for
 ## the arrows of the field relative to the mesh spacing.  A value of 0
-## disables all scaling.  The default value is 1.
+## disables all scaling.  The default value is 0.9.
 ##
 ## The style to use for the plot can be defined with a line style @var{style}
 ## of the same format as the @code{plot} command.
@@ -64,34 +64,34 @@
 ## @seealso{quiver, compass, feather, plot}
 ## @end deftypefn
 
-function retval = quiver3 (varargin)
+function h = quiver3 (varargin)
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("quiver3", varargin{:});
 
   if (nargin < 2)
     print_usage ();
-  else
+  endif
+
   oldfig = [];
   if (! isempty (hax))
     oldfig = get (0, "currentfigure");
   endif
-    unwind_protect
-      hax = newplot (hax);
-      htmp = __quiver__ (hax, true, varargin{:});
+  unwind_protect
+    hax = newplot (hax);
+    htmp = __quiver__ (hax, true, varargin{:});
 
-      if (! ishold (hax))
-        set (hax, "view", [-37.5, 30], "box", "off",
-                  "xgrid", "on", "ygrid", "on", "zgrid", "on");
-      endif
-    unwind_protect_cleanup
-      if (! isempty (oldfig))
-        set (0, "currentfigure", oldfig);
-      endif
-    end_unwind_protect
-  endif
+    if (! ishold (hax))
+      set (hax, "view", [-37.5, 30], "box", "off",
+                "xgrid", "on", "ygrid", "on", "zgrid", "on");
+    endif
+  unwind_protect_cleanup
+    if (! isempty (oldfig))
+      set (0, "currentfigure", oldfig);
+    endif
+  end_unwind_protect
 
   if (nargout > 0)
-    retval = htmp;
+    h = htmp;
   endif
 
 endfunction
@@ -100,24 +100,14 @@
 %!demo
 %! clf;
 %! colormap ('default');
-%! [x,y] = meshgrid (-1:0.1:1);
-%! z = sin (2*pi * sqrt (x.^2 + y.^2));
-%! theta = 2*pi * sqrt (x.^2 + y.^2) + pi/2;
-%! mesh (x, y, z);
-%! hold on;
-%! quiver3 (x, y, z, sin (theta), cos (theta), ones (size (z)));
-%! hold off;
-
-%!demo
-%! clf;
-%! colormap ('default');
 %! [x, y, z] = peaks (25);
 %! surf (x, y, z);
 %! hold on;
 %! [u, v, w] = surfnorm (x, y, z / 10);
 %! h = quiver3 (x, y, z, u, v, w);
-%! set (h, 'maxheadsize', 0.33);
+%! set (h, 'maxheadsize', 0.25);
 %! hold off;
+%! title ('quiver3 of surface normals to peaks() function');
 
 %!demo
 %! clf;
@@ -127,7 +117,9 @@
 %! hold on;
 %! [u, v, w] = surfnorm (x, y, z / 10);
 %! h = quiver3 (x, y, z, u, v, w);
-%! set (h, 'maxheadsize', 0.33);
+%! set (h, 'maxheadsize', 0.25);
 %! hold off;
 %! shading interp;
+%! title ({'quiver3 of surface normals to peaks() function'; ...
+%!         'shading "interp"'});