changeset 17475:0b6f44d31edc default tip Latex-interpreter

Merge with main after adding Windows name fot GS.
author Andrej Lojdl <andrej.lojdl@gmail.com>
date Thu, 19 Sep 2013 22:53:49 +0200
parents 981103844b51 (current diff) 2fee3022ac2f (diff)
children
files libinterp/corefcn/graphics.cc
diffstat 21 files changed, 750 insertions(+), 688 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/graphics.cc
+++ b/libinterp/corefcn/graphics.cc
@@ -8532,6 +8532,7 @@
        properties of @qcode{\"position\"}, @qcode{\"units\"},\n\
        @qcode{\"windowstyle\"} and @qcode{\"paperunits\"} and the default axes\n\
        properties of @qcode{\"position\"} and @qcode{\"units\"} are not reset.\n\
+@seealso{cla, clf}\n\
        @end deftypefn")
 {
   int nargin = args.length ();
--- a/scripts/miscellaneous/fileparts.m
+++ b/scripts/miscellaneous/fileparts.m
@@ -25,38 +25,38 @@
 
 function [directory, name, extension, version] = fileparts (filename)
 
-  if (nargin == 1)
-    if (ischar (filename))
-      ds = strchr (filename, filesep ("all"), 1, "last");
-      if (isempty (ds))
-        ds = 0;
-      endif
-      es = rindex (filename, ".");
-      ## These can be the same if they are both 0 (no dir or ext).
-      if (es <= ds)
-        es = length (filename)+1;
-      endif
-      if (ds == 0)
-        directory = "";
-      elseif (ds == 1)
-        directory = filename(1);
-      else
-        directory = filename(1:ds-1);
-      endif
-      name = filename(ds+1:es-1);
-      if (es > 0 && es <= length (filename))
-        extension = filename(es:end);
-      else
-        extension = "";
-      endif
-      version = "";
-    else
-      error ("fileparts: expecting FILENAME argument to be a string");
-    endif
-  else
+  if (nargin != 1)
     print_usage ();
   endif
 
+  if (! ischar (filename) || rows (filename) > 1)
+    error ("fileparts: FILENAME must be a single string");
+  endif
+
+  ds = strchr (filename, filesep ("all"), 1, "last");
+  if (isempty (ds))
+    ds = 0;
+  endif
+  es = rindex (filename, ".");
+  ## These can be the same if they are both 0 (no dir or ext).
+  if (es <= ds)
+    es = length (filename)+1;
+  endif
+  if (ds == 0)
+    directory = "";
+  elseif (ds == 1)
+    directory = filename(1);
+  else
+    directory = filename(1:ds-1);
+  endif
+  name = filename(ds+1:es-1);
+  if (es > 0 && es <= length (filename))
+    extension = filename(es:end);
+  else
+    extension = "";
+  endif
+  version = "";
+
 endfunction
 
 
@@ -96,3 +96,9 @@
 %! [d, n, e] = fileparts (".ext");
 %! assert (strcmp (d, "") && strcmp (n, char (zeros (1, 0))) && strcmp (e, ".ext"));
 
+%% Test input validation
+%!error fileparts ()
+%!error fileparts (1,2)
+%!error <FILENAME must be a single string> fileparts (1)
+%!error <FILENAME must be a single string> fileparts (["a"; "b"])
+
--- a/scripts/plot/area.m
+++ b/scripts/plot/area.m
@@ -65,35 +65,40 @@
     print_usage ();
   endif
 
-  idx = 1;
   x = y = [];
   bv = 0;
-  args = {};
-  ## Check for (X) or (X,Y) arguments and possible base value.
-  if (nargin >= idx && ismatrix (varargin{idx}))
-    y = varargin{idx};
-    idx++;
-    if (nargin >= idx)
-      if (isscalar (varargin{idx}))
-        bv = varargin{idx};
-        idx++;
-      elseif (ismatrix (varargin{idx}))
-        x = y;
-        y = varargin{idx};
-        idx++;
-        if (nargin >= idx && isscalar (varargin{idx}))
-          bv = varargin{idx};
-          idx++;
-        endif
+
+  num_numeric = find (cellfun ("isclass", varargin, "char"), 1) - 1;
+  if (isempty (num_numeric))
+    num_numeric = nargin;     
+  endif
+
+  switch (num_numeric)
+    case 1
+      y = varargin{1};
+    case 2
+      if (isscalar (varargin{2})) 
+        y = varargin{1};
+        bv = varargin{2};
+      else
+        x = varargin{1};
+        y = varargin{2};
       endif
-    endif
-  else
-    print_usage ();
+    case 3
+      x = varargin{1};
+      y = varargin{2};
+      bv = varargin{3};
+    otherwise
+      print_usage ();
+  endswitch
+
+  if (! isreal (x) || ! isreal (y))
+    error ("area: X and Y must be real vectors or matrices");
   endif
-  ## Check for additional args.
-  if (nargin >= idx)
-    args = {varargin{idx:end}};
+  if (! isreal (bv) || ! isscalar (bv))
+    error ("area: LVL must be a real scalar");
   endif
+
   if (isvector (y))
     y = y(:);
   endif
@@ -109,7 +114,7 @@
   endif
   unwind_protect
     hax = newplot (hax);
-    htmp = __area__ (hax, x, y, bv, args{:});
+    htmp = __area__ (hax, x, y, bv, varargin{num_numeric+1:end});
   unwind_protect_cleanup
     if (! isempty (oldfig))
       set (0, "currentfigure", oldfig);
@@ -128,12 +133,16 @@
   y0 = zeros (1, rows (y));
   retval = [];
   for i = 1: columns (y);
+
+    lc = __next_line_color__ ();
+
+    ## Must occur after __next_line_color__ in order to work correctly.
     hg = hggroup ();
     retval = [retval; hg];
     args = __add_datasource__ ("area", hg, {"x", "y"}, varargin{:});
 
-    x1 = x(:, 1).';
-    y1 = y (:, i).';
+    x1 = x(:, 1)';
+    y1 = y(:, i)';
     addproperty ("xdata", hg, "data", x1);
     addproperty ("ydata", hg, "data", y1);
 
@@ -142,11 +151,11 @@
 
     if (i == 1)
       h = patch (ax, [x1(1), x1, fliplr(x1)], [bv, y1, bv*ones(1, length(y1))],
-                 __next_line_color__ (), "parent", hg);
+                     lc, "parent", hg);
     else
       y1 = y0 + y1;
       h = patch (ax, [x1(1), x1, fliplr(x1)], [y0(1), y1, fliplr(y0)],
-                 __next_line_color__ (), "parent", hg);
+                     lc, "parent", hg);
     endif
 
     y0 = y1;
@@ -155,14 +164,14 @@
     addlistener (hg, "basevalue", @move_baseline);
 
     addproperty ("edgecolor", hg, "patchedgecolor", get (h, "edgecolor"));
-    addproperty ("linewidth", hg, "patchlinewidth", get (h, "linewidth"));
+    addproperty ("facecolor", hg, "patchfacecolor", get (h, "facecolor"));
     addproperty ("linestyle", hg, "patchlinestyle", get (h, "linestyle"));
-    addproperty ("facecolor", hg, "patchfacecolor", get (h, "facecolor"));
+    addproperty ("linewidth", hg, "patchlinewidth", get (h, "linewidth"));
 
     addlistener (hg, "edgecolor", @update_props);
-    addlistener (hg, "linewidth", @update_props);
+    addlistener (hg, "facecolor", @update_props);
     addlistener (hg, "linestyle", @update_props);
-    addlistener (hg, "facecolor", @update_props);
+    addlistener (hg, "linewidth", @update_props);
 
     addproperty ("areagroup", hg, "data");
     set (retval, "areagroup", retval);
@@ -177,9 +186,9 @@
 function update_props (h, d)
   kids = get (h, "children");
   set (kids, "edgecolor", get (h, "edgecolor"),
-             "linewidth", get (h, "linewidth"),
+             "facecolor", get (h, "facecolor"),
              "linestyle", get (h, "linestyle"),
-             "facecolor", get (h, "facecolor"));
+             "linewidth", get (h, "linewidth"));
 endfunction
 
 function move_baseline (h, d)
@@ -259,3 +268,13 @@
 %! set (h, 'ydata', sort (get (h, 'ydata')))
 %! title ('area() plot of sorted data');
 
+%% Test input validation
+%!error area ()
+%!error area (1,2,3,4)
+%!error <X and Y must be real vectors or matrices> area ({1})
+%!error <X and Y must be real vectors or matrices> area (1+i)
+%!error <X and Y must be real vectors or matrices> area (1:2, {1, 2})
+%!error <X and Y must be real vectors or matrices> area (1:2, [1 1+i])
+%!error <LVL must be a real scalar> area (1, i)
+%!error <LVL must be a real scalar> area (1, 2, ones (2,2))
+
--- a/scripts/plot/caxis.m
+++ b/scripts/plot/caxis.m
@@ -17,21 +17,23 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} caxis (@var{limits})
+## @deftypefn  {Function File} {} caxis ([cmin cmax])
 ## @deftypefnx {Function File} {} caxis ("auto")
 ## @deftypefnx {Function File} {} caxis ("manual")
 ## @deftypefnx {Function File} {} caxis (@var{hax}, @dots{})
 ## @deftypefnx {Function File} {@var{limits} =} caxis ()
 ## Query or set color axis limits for plots.
 ##
-## The argument @var{limits} should be a 2-element vector specifying the
+## The limits argument should be a 2-element vector specifying the
 ## lower and upper limits to assign to the first and last value in the
-## colormap.  Values outside this range are clamped to the first and last
+## colormap.  Data values outside this range are clamped to the first and last
 ## colormap entries.
 ##
-## If @var{limits} is @qcode{"auto"}, then automatic colormap scaling is
-## applied, whereas if @var{limits} is @qcode{"manual"} the colormap scaling
-## is set to manual.
+## If the @qcode{"auto"} option is given then automatic colormap limits are
+## applied.  The automatic algorithm sets @var{cmin} to the minimum data value
+## and @var{cmax} to the maximum data value.  If @qcode{"manual"} is specified
+## then the @qcode{"climmode"} property is set to @qcode{"manual"} and the
+## numeric values in the @qcode{"clim"} property are used for limits.
 ##
 ## If the first argument @var{hax} is an axes handle, then operate on
 ## this axis rather than the current axes returned by @code{gca}.
--- a/scripts/plot/cla.m
+++ b/scripts/plot/cla.m
@@ -33,7 +33,7 @@
 ##
 ## If the first argument @var{hax} is an axes handle, then operate on
 ## this axis rather than the current axes returned by @code{gca}.
-## @seealso{clf}
+## @seealso{clf, delete, reset}
 ## @end deftypefn
 
 ## Author: Ben Abbott <bpabbott@mac.com>
--- a/scripts/plot/clf.m
+++ b/scripts/plot/clf.m
@@ -37,7 +37,7 @@
 ## 
 ## The optional return value @var{h} is the graphics handle of the figure
 ## window that was cleared.
-## @seealso{cla, close, delete}
+## @seealso{cla, close, delete, reset}
 ## @end deftypefn
 
 ## Author: jwe
--- a/scripts/plot/close.m
+++ b/scripts/plot/close.m
@@ -23,10 +23,6 @@
 ## @deftypefnx {Command} {} close all hidden
 ## Close figure window(s).
 ##
-## @code{close} operates by calling the function specified by the
-## @qcode{"closerequestfcn"} property for each figure.  By default, the function
-## @code{closereq} is used.
-##
 ## When called with no arguments, close the current figure.  This is equivalent
 ## to @code{close (gcf)}.  If the input @var{h} is a graphic handle, or vector
 ## of graphics handles, then close each figure in @var{h}.
@@ -37,10 +33,12 @@
 ## If the argument @qcode{"all hidden"} is given then all figures, including
 ## hidden ones, are closed.
 ##
-## Implementation Note: @code{close} calls a function to dispose of the figure.
-## It is possible that the function will delay or abort removing the figure.
-## To remove a figure without executing any callback functions use
-## @code{delete}.
+## Implementation Note: @code{close} operates by calling the function specified
+## by the @qcode{"closerequestfcn"} property for each figure.  By default, the
+## function @code{closereq} is used.  It is possible that the function invoked
+## will delay or abort removing the figure.  To remove a figure without
+## executing any callback functions use @code{delete}.  When writing a callback
+## function to close a window do not use @code{close} to avoid recursion.
 ##
 ## @seealso{closereq, delete}
 ## @end deftypefn
--- a/scripts/plot/closereq.m
+++ b/scripts/plot/closereq.m
@@ -19,6 +19,9 @@
 ## -*- texinfo -*-
 ## @deftypefn {Function File} {} closereq ()
 ## Close the current figure and delete all graphics objects associated with it.
+##
+## By default, the @qcode{"closerequestfcn"} property of a new plot figure
+## points to this function.
 ## @seealso{close, delete}
 ## @end deftypefn
 
@@ -26,18 +29,18 @@
 
 function closereq ()
 
-  if (nargin == 0)
-    cf = gcbf ();
-    if (isempty (cf))
-      warning ("closereq: calling closereq from octave prompt is not supported, use 'close' instead");
-      cf = get (0, "currentfigure");
-    endif
-    if (! isempty (cf) && isfigure (cf))
-      delete (cf);
-    endif
-  else
+  if (nargin != 0)
     print_usage ();
   endif
 
+  cf = gcbf ();
+  if (isempty (cf))
+    warning ("closereq: calling closereq from octave prompt is not supported, use 'close' instead");
+    cf = get (0, "currentfigure");
+  endif
+  if (! isempty (cf) && isfigure (cf))
+    delete (cf);
+  endif
+
 endfunction
 
--- a/scripts/plot/compass.m
+++ b/scripts/plot/compass.m
@@ -46,56 +46,58 @@
 ## @end group
 ## @end example
 ##
-## @seealso{polar, quiver, feather, plot}
+## @seealso{polar, feather, quiver, rose, plot}
 ## @end deftypefn
 
 function h = compass (varargin)
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("compass", varargin{:});
 
-  if (nargin == 0)
+  if (nargin == 0 || nargin > 3)
     print_usage ();
-  elseif (nargin == 1 || (nargin == 2 && ! isnumeric (varargin{2})))
-    ioff = 2;
+  endif
+
+  if (nargin == 1 || (nargin == 2 && ! isnumeric (varargin{2})))
     z = varargin{1}(:).';
     u = real (z);
     v = imag (z);
-  elseif (nargin > 1 && isnumeric (varargin{2}))
-    ioff = 3;
+    have_line_spec = (nargin == 2);
+  elseif (nargin >= 2 && isnumeric (varargin{2}))
     u = varargin{1}(:).';
     v = varargin{2}(:).';
+    have_line_spec = (nargin == 3);
+  else
+    print_usage ();
   endif
 
-  arrowsize = 0.25;
-  line_spec = "b-";
-  have_line_spec = false;
-  while (ioff <= nargin)
-    arg = varargin{ioff++};
-    if ((ischar (arg) || iscell (arg)) && ! have_line_spec)
-      [linespec, valid] = __pltopt__ ("compass", arg, false);
+  arrowsize = 0.20;
+  line_spec = "-b";
+
+  if (have_line_spec)
+    arg = varargin{end};
+    if (ischar (arg) || iscellstr (arg))
+      [~, valid] = __pltopt__ ("compass", arg, false);
       if (valid)
         line_spec = arg;
-        have_line_spec = true;
-        break;
       else
-        error ("compass: invalid linespec");
+        error ("compass: invalid linestyle STYLE");
       endif
     else
-      error ("compass: unrecognized argument");
+      error ("compass: invalid linestyle STYLE");
     endif
-  endwhile
+  endif
 
-  ## Matlab draws compass plots, with the arrow head as one continous
-  ## line, and each arrow separately. This is completely different than
-  ## quiver and quite ugly.
+  ## Matlab draws compass plots with the arrow head as one continous line,
+  ## and each arrow separately.  This is completely different than quiver
+  ## and quite ugly.
   n = length (u);
   xend = u;
   xtmp = u .* (1 - arrowsize);
   yend = v;
   ytmp = v .* (1 - arrowsize);
-  x = [zeros(1, n); xend; xtmp  - v * arrowsize / 3; xend; ...
+  x = [zeros(1, n); xend; xtmp - v * arrowsize / 3; xend; ...
        xtmp + v * arrowsize / 3];
-  y = [zeros(1, n); yend; ytmp  + u * arrowsize / 3; yend; ...
+  y = [zeros(1, n); yend; ytmp + u * arrowsize / 3; yend; ...
        ytmp - u * arrowsize / 3];
   [r, p] = cart2pol (x, y);
 
--- a/scripts/plot/errorbar.m
+++ b/scripts/plot/errorbar.m
@@ -197,3 +197,24 @@
 %! legend ("X-Y errbars", "X-Y errboxes");
 %! title ('errorbar() with X-Y errorbars and error boxes');
 
+## Invisible figure used for tests
+%!shared hf, hax
+%! hf = figure ("visible", "off");
+%! hax = axes;
+
+%!error errorbar ()
+%!error errorbar (1)
+%!error <data argument 1 must be numeric> errorbar (hax, {1}, 2)
+%!error <data argument 2 must be numeric> errorbar (hax, 1, {2})
+%!error <size of argument 2 does not match others> errorbar (hax, 1, 1:2)
+%!error <size of argument 3 does not match others> errorbar (hax, 1, 2, 3:4)
+%!error <too many arguments to plot> errorbar (1,2,3,4,5,6,7)
+
+%!error <2 column errorplot is only valid for xerr> errorbar (1,2, "~>")
+%!error <6 columns only valid for xyerr and boxxy> errorbar (1,2,3,4,5,6, "~")
+%!error <error plot requires 2, 3, 4, or 6 arguments> errorbar (1,2,3,4,5)
+
+## Close figure used for testing
+%!test
+%! close (hf);
+
--- a/scripts/plot/private/__errcomm__.m
+++ b/scripts/plot/private/__errcomm__.m
@@ -31,45 +31,45 @@
     print_usage (caller);
   endif
 
-  nargs = length (varargin);
   retval = [];
+  data = cell (6,1);
+  nargs = numel (varargin);
   k = 1;
-  data = cell (6,1);
   while (k <= nargs)
-    a = varargin{k++};
-    if (isvector (a))
-      a = a(:);
-    elseif (ismatrix (a))
-      ;
-    else
-      usage ("%s (...)", caller);
+    arg = varargin{k++};
+    if (! ismatrix (arg))
+      error ("%s: data argument %d must be numeric", caller, k-1);
     endif
-    sz = size (a);
+    if (isvector (arg))
+      arg = arg(:);
+    endif
+    sz = size (arg);
     ndata = 1;
-    data{ndata} = a;
+    data{ndata} = arg;
     while (k <= nargs)
-      a = varargin{k++};
-      if (ischar (a) || iscellstr (a))
-        retval = [retval; __errplot__(a, hax, data{1:ndata})];
+      arg = varargin{k++};
+      if (ischar (arg) || iscellstr (arg))
+        retval(end+1,1) = __errplot__(arg, hax, data{1:ndata});
         break;
-      elseif (isvector (a))
-        a = a(:);
-      elseif (ismatrix (a))
-        ;
-      else
-        error ("%s: wrong argument types", caller);
+      endif
+      if (! ismatrix (arg))
+        error ("%s: data argument %d must be numeric", caller, k-1);
       endif
-      if (size (a) != sz)
-        error ("%s: argument sizes do not match", caller);
+      if (isvector (arg))
+        arg = arg(:);
       endif
-      data{++ndata} = a;
+      if (any (size (arg) != sz))
+        error ("%s: size of argument %d does not match others", caller, k-1);
+      endif
+      data{++ndata} = arg;
       if (ndata > 6)
         error ("%s: too many arguments to plot", caller);
       endif
     endwhile
   endwhile
 
-  if (! (ischar (a) || iscellstr (a)))
+  ## No format code found, use yerrorbar
+  if (! (ischar (arg) || iscellstr (arg)))
     retval = [retval; __errplot__("~", hax, data{1:ndata})];
   endif
 
--- a/scripts/plot/private/__errplot__.m
+++ b/scripts/plot/private/__errplot__.m
@@ -27,119 +27,124 @@
 
 function h = __errplot__ (fstr, hax, varargin)
 
-  [fmt, valid] = __pltopt__ ("__errplot__", fstr);
-
-  [len, nplots] = size (varargin{1});
-  h = [];
+  fmt = __pltopt__ ("__errplot__", fstr);
 
-  for i = 1:nplots
-    ## Set the plot type based on linestyle.
-
-    if (strcmp (fmt.errorstyle, "~"))
+  ## Set the plot type based on linestyle.
+  switch (fmt.errorstyle) 
+    case "~"
       ifmt = "yerr";
-    elseif (strcmp (fmt.errorstyle, ">"))
+    case ">"
       ifmt = "xerr";
-    elseif (strcmp (fmt.errorstyle, "~>"))
+    case "~>"
       ifmt = "xyerr";
-    elseif (strcmp (fmt.errorstyle, "#"))
+    case "#"
       ifmt = "box";
-    elseif (strcmp (fmt.errorstyle, "#~"))
+    case "#~"
       ifmt = "boxy";
-    elseif (strcmp (fmt.errorstyle, "#~>"))
+    case "#~>"
       ifmt = "boxxy";
+    otherwise
+      ifmt = "yerr";
+  endswitch
+
+  h = [];
+  nplots = columns (varargin{1});
+  for i = 1:nplots
+
+    if (isempty (fmt.color))
+      lc = __next_line_color__ ();
     else
-      ifmt = "yerr";
+      lc = fmt.color ();
+    endif
+    if (isempty (fmt.marker) && isempty (fmt.linestyle))
+      [ls, mk] = __next_line_style__ ();
+    else
+      ls = fmt.linestyle;
+      mk = fmt.marker;
     endif
 
+    ## Must occur after __next_line_color__ in order to work correctly.
     hg = hggroup ("parent", hax);
     h = [h; hg];
     args = __add_datasource__ ("__errplot__", hg,
                                {"x", "y", "l", "u", "xl", "xu"});
 
-    if (isempty (fmt.color))
-      fmt.color = __next_line_color__ ();
-    endif
-    if (isempty (fmt.marker) && isempty (fmt.linestyle))
-      [fmt.linestyle, fmt.marker] = __next_line_style__ ();
-    endif
-    hl = [(__line__ (hg, "linestyle", fmt.linestyle, "marker", fmt.marker,
-                   "color", fmt.color)),
-          (__line__ (hg, "linestyle", "-", "marker", "none",
-                   "color", fmt.color))];
+    hl = [(__line__ (hg, "color", lc, "linestyle", ls, "marker", mk)),
+          (__line__ (hg, "color", lc, "linestyle", "-", "marker", "none"))];
 
     switch (numel (varargin))
       case 2
         ydata = varargin{1}(:,i);
         xdata = 1:numel (ydata);
-        if (strcmp (ifmt, "xerr") || strcmp (ifmt, "box"))
+        if (strcmp (ifmt, "yerr") || strcmp (ifmt, "boxy"))
+          ldata  = varargin{2}(:,i);
+          udata  = ldata;
+          xldata = [];
+          xudata = [];
+        elseif (strcmp (ifmt, "xerr") || strcmp (ifmt, "box"))
           xldata = varargin{2}(:,i);
           xudata = ldata;
-          ldata = [];
-          udata = [];
-        elseif (strcmp (ifmt, "yerr") || strcmp (ifmt, "boxy"))
-          ldata = varargin{2}(:,i);
-          udata = ldata;
-          xldata = [];
-          xudata = [];
+          ldata  = [];
+          udata  = [];
         else
           error ("errorbar: 2 column errorplot is only valid for xerr or yerr");
         endif
       case 3
-        if (strcmp (ifmt, "boxxy") || strcmp (ifmt, "xyerr"))
-          ydata = varargin{1}(:,i);
-          xdata = 1:numel (ydata);
+        if (strcmp (ifmt, "yerr") || strcmp (ifmt, "boxy"))
+          xdata  = varargin{1}(:,i);
+          ydata  = varargin{2}(:,i);
+          ldata  = varargin{3}(:,i);
+          udata  = ldata;
+          xldata = [];
+          xudata = [];
+        elseif (strcmp (ifmt, "xyerr") || strcmp (ifmt, "boxxy"))
+          ydata  = varargin{1}(:,i);
+          xdata  = 1:numel (ydata);
           xldata = varargin{2}(:,i);
           xudata = xldata;
-          ldata = varargin{3}(:,i);
-          udata = ldata;
-        elseif (strcmp (ifmt, "xerr") || strcmp (ifmt, "box"))
-          xdata = varargin{1}(:,i);
-          ydata = varargin{2}(:,i);
-          xldata = varargin{3}(:,i);
-          xudata = xldata;
-          ldata = [];
-          udata = [];
-        else # yerr or boxy
-          xdata = varargin{1}(:,i);
-          ydata = varargin{2}(:,i);
-          ldata = varargin{3}(:,i);
-          udata = ldata;
-          xldata = [];
-          xudata = [];
-        endif
-      case 4
-        if (strcmp (ifmt, "boxxy") || strcmp (ifmt, "xyerr"))
-          xdata = varargin{1}(:,i);
-          ydata = varargin{2}(:,i);
+          ldata  = varargin{3}(:,i);
+          udata  = ldata;
+        else  # xerr or box
+          xdata  = varargin{1}(:,i);
+          ydata  = varargin{2}(:,i);
           xldata = varargin{3}(:,i);
           xudata = xldata;
-          ldata = varargin{4}(:,i);
-          udata = ldata;
-        elseif (strcmp (ifmt, "xerr") || strcmp (ifmt, "box"))
-          xdata = varargin{1}(:,i);
-          ydata = varargin{2}(:,i);
+          ldata  = [];
+          udata  = [];
+        endif
+      case 4
+        if (strcmp (ifmt, "yerr") || strcmp (ifmt, "boxy"))
+          xdata  = varargin{1}(:,i);
+          ydata  = varargin{2}(:,i);
+          ldata  = varargin{3}(:,i);
+          udata  = varargin{4}(:,i);
+          xldata = [];
+          xudata = [];
+        elseif (strcmp (ifmt, "xyerr") || strcmp (ifmt, "boxxy"))
+          xdata  = varargin{1}(:,i);
+          ydata  = varargin{2}(:,i);
+          xldata = varargin{3}(:,i);
+          xudata = xldata;
+          ldata  = varargin{4}(:,i);
+          udata  = ldata;
+        else  # xerr or box
+          xdata  = varargin{1}(:,i);
+          ydata  = varargin{2}(:,i);
           xldata = varargin{3}(:,i);
           xudata = varargin{4}(:,i);
-          ldata = [];
-          udata = [];
-        else # yerr or boxy
-          xdata = varargin{1}(:,i);
-          ydata = varargin{2}(:,i);
-          ldata = varargin{3}(:,i);
-          udata = varargin{4}(:,i);
-          xldata = [];
-          xudata = [];
+          ldata  = [];
+          udata  = [];
         endif
-      case 6 # boxxy, xyerr
-        if (strcmp (ifmt, "boxxy") || strcmp (ifmt, "xyerr"))
-          xdata = varargin{1}(:,i);
-          ydata = varargin{2}(:,i);
+      case 6  # xyerr, boxxy
+        if (strcmp (ifmt, "xyerr") || strcmp (ifmt, "boxxy"))
+          xdata  = varargin{1}(:,i);
+          ydata  = varargin{2}(:,i);
           xldata = varargin{3}(:,i);
           xudata = varargin{4}(:,i);
-          ldata = varargin{5}(:,i);
-          udata = varargin{6}(:,i);
+          ldata  = varargin{5}(:,i);
+          udata  = varargin{6}(:,i);
         else
-          error ("errorbar: error plot with 6 columns only valid for boxxy and xyerr");
+          error ("errorbar: error plot with 6 columns only valid for xyerr and boxxy");
         endif
       otherwise
         error ("errorbar: error plot requires 2, 3, 4, or 6 arguments");
@@ -154,21 +159,22 @@
     addproperty ("format", hg, "string", ifmt);
 
     addproperty ("color", hg, "linecolor", get (hl(1), "color"));
+    addproperty ("linestyle", hg, "linelinestyle", get (hl(1), "linestyle"));
     addproperty ("linewidth", hg, "linelinewidth", get (hl(1), "linewidth"));
-    addproperty ("linestyle", hg, "linelinestyle", get (hl(1), "linestyle"));
     addproperty ("marker", hg, "linemarker", get (hl(1), "marker"));
+    addproperty ("markeredgecolor", hg, "linemarkerfacecolor",
+                 get (hl(1), "markeredgecolor"));
     addproperty ("markerfacecolor", hg, "linemarkerfacecolor",
                  get (hl(1), "markerfacecolor"));
-    addproperty ("markeredgecolor", hg, "linemarkerfacecolor",
-                 get (hl(1), "markeredgecolor"));
     addproperty ("markersize", hg, "linemarkersize",
                  get (hl(1), "markersize"));
 
     fcn = {@update_props, hl};
     addlistener (hg, "color", fcn);
+    addlistener (hg, "linestyle", fcn);
     addlistener (hg, "linewidth", fcn);
-    addlistener (hg, "linestyle", fcn);
     addlistener (hg, "marker", fcn);
+    addlistener (hg, "markeredgecolor", fcn);
     addlistener (hg, "markerfacecolor", fcn);
     addlistener (hg, "markersize", fcn);
 
@@ -250,7 +256,7 @@
     ylo = ydata/ry;
     yhi = ydata*ry;
   endif
-  nans = NaN + xdata(:);
+  nans = NaN + xdata(:);  # fast way to do NaN (size (xdata(:)))
   if (strcmp (ifmt, "yerr"))
     xdata = [xdata, xdata, nans, ...
              xlo, xhi, nans, ...
@@ -289,7 +295,7 @@
     ydata = [y1; y2];
     return;
   else
-    error ("errorbar: valid error bar types are xerr, yerr, boxxy, and xyerr");
+    error ("errorbar: valid error bar types are xerr, yerr, xyerr, box, boxy, boxxy");
   endif
 
   xdata = xdata.'(:);
@@ -297,17 +303,17 @@
 
 endfunction
 
-function update_props (hg, dummy, hl)
+function update_props (hg, ~, hl)
   set (hl, "color", get (hg, "color"),
-           "linewidth", get (hg, "linewidth"));,
+           "linewidth", get (hg, "linewidth"));
   set (hl(1), "linestyle", get (hg, "linestyle"),
               "marker", get (hg, "marker"),
-              "markersize", get (hg, "markersize"),
+              "markeredgecolor", get (hg, "markeredgecolor"),
               "markerfacecolor", get (hg, "markerfacecolor"),
-              "markeredgecolor", get (hg, "markeredgecolor"));
+              "markersize", get (hg, "markersize"));
 endfunction
 
-function update_data (hg, dummy, hl)
+function update_data (hg, ~, hl)
 
   if (strcmp (get (hg, "type"), "axes"))
     hax = hg;
@@ -318,10 +324,10 @@
   xscale = get (hax, "xscale");
   yscale = get (hax, "yscale");
 
-  xdata = get (hg, "xdata");
-  ydata = get (hg, "ydata");
-  ldata = get (hg, "ldata");
-  udata = get (hg, "udata");
+  xdata  = get (hg, "xdata");
+  ydata  = get (hg, "ydata");
+  ldata  = get (hg, "ldata");
+  udata  = get (hg, "udata");
   xldata = get (hg, "xldata");
   xudata = get (hg, "xudata");
   ifmt = get (hg, "format");
--- a/scripts/plot/private/__next_line_color__.m
+++ b/scripts/plot/private/__next_line_color__.m
@@ -37,17 +37,17 @@
   else
     ## Find and return the next line color
     ca = gca ();
-    colorOrder = get (ca, "ColorOrder");
+    colororder = get (ca, "colororder");
     if (reset_colors)
       color_index = 1;
       reset_colors = false;
     else
       ## Executed when "hold all" is active
-      nChildren = length (get (ca, "Children"));
-      nColors = rows (colorOrder);
-      color_index = mod (nChildren, nColors) + 1;
+      n_kids = length (get (ca, "children"));
+      n_colors = rows (colororder);
+      color_index = mod (n_kids, n_colors) + 1;
     endif
-    rgb = colorOrder(color_index,:);
+    rgb = colororder(color_index,:);
   endif
 
 endfunction
--- a/scripts/plot/private/__plt__.m
+++ b/scripts/plot/private/__plt__.m
@@ -495,8 +495,8 @@
   endif
 
   retval = line (x, y, "color", color,
-            "linestyle", linestyle,
-            "marker", marker, properties{:});
+                 "linestyle", linestyle,
+                 "marker", marker, properties{:});
 
 endfunction
 
--- a/scripts/plot/private/__scatter__.m
+++ b/scripts/plot/private/__scatter__.m
@@ -75,9 +75,9 @@
     if (isvector (c) && columns (c) != 3)
       c = c(:);
     endif
-  ## Compare only first 4 letters of "fill" as that is what Matlab uses.
   elseif (firstnonnumeric == istart && ischar (varargin{istart})
-          && ! strncmpi (varargin{istart}, "filled", 4))
+          && ! (   strcmpi (varargin{istart}, "filled")
+                || strcmpi (varargin{istart}, "fill")))
     c = varargin{istart};
     firstnonnumeric++;
   else
@@ -91,7 +91,7 @@
   iarg = firstnonnumeric;
   while (iarg <= nargin)
     arg = varargin{iarg++};
-    if (ischar (arg) && strncmpi (arg, "filled", 4))
+    if (ischar (arg) && (strcmpi (arg, "filled") || strcmpi (arg, "fill")))
       filled = true;
     elseif ((ischar (arg) || iscell (arg)) && ! have_marker)
       [linespec, valid] = __pltopt__ (fcn, arg, false);
@@ -119,6 +119,7 @@
     c = __next_line_color__ ();
   endif
 
+  ## Must occur after __next_line_color__ in order to work correctly.
   hg = hggroup ();
   newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
                                 newargs{:});
--- a/scripts/plot/private/__stem__.m
+++ b/scripts/plot/private/__stem__.m
@@ -35,7 +35,7 @@
   [hax, varargin, nargin] = __plt_get_axis_arg__ (caller, varargin{:});
 
   [x, y, z, dofill, llc, ls, mmc, ms, varargin] = ...
-      check_stem_arg (have_z, varargin{:});
+                                           check_stem_arg (have_z, varargin{:});
 
   oldfig = [];
   if (! isempty (hax))
@@ -63,10 +63,6 @@
         yt = [zeros(1, nx); yt; NaN(1, nx)](:);
       endif
 
-      hg = hggroup ();
-      h = [h; hg];
-      args = __add_datasource__ (caller, hg, {"x", "y", "z"}, varargin{:});
-
       if (isempty (llc))
         lc = __next_line_color__ ();
       else
@@ -85,32 +81,34 @@
         fc = "none";
       endif
 
+      ## Must occur after __next_line_color__ in order to work correctly.
+      hg = hggroup ();
+      h = [h; hg];
+      args = __add_datasource__ (caller, hg, {"x", "y", "z"}, varargin{:});
+
       if (have_z)
-        h_stems = plot3 (hax, xt, yt, zt, "color", lc, "linestyle", ls,
-                         "parent", hg, x, y, z, "color", mc,
-                         "marker", ms, "linestyle", "none",
-                         "markerfacecolor", fc, "parent", hg);
-
+        __line__ (hax, xt, yt, zt, "color", lc, "linestyle", ls, "parent", hg);
+        __line__ (hax, x, y, z, "color", mc, "linestyle", "none",
+                       "marker", ms, "markerfacecolor", fc, "parent", hg);
         h_baseline = [];
       else
-        h_stems = plot (hax, xt, yt, "color", lc, "linestyle", ls,
-                        "parent", hg, x(:,i), y(:, i), "color", mc, "marker",
-                        ms, "linestyle", "none", "markerfacecolor",
-                        fc, "parent", hg);
-
+        __line__ (hax, xt, yt, "color", lc, "linestyle", ls, "parent", hg);
+        __line__ (hax, x(:,i), y(:, i), "color", mc, "linestyle", "none",
+                       "marker", ms, "markerfacecolor", fc, "parent", hg);
         x_axis_range = get (hax, "xlim");
         h_baseline = line (hax, x_axis_range, [0, 0], "color", [0, 0, 0]);
-        set (h_baseline, "handlevisibility", "off");
-        set (h_baseline, "xliminclude", "off");
+        set (h_baseline, "handlevisibility", "off", "xliminclude", "off");
         addlistener (hax, "xlim", @update_xlim);
-        addlistener (h_baseline, "ydata", @update_baseline);
-        addlistener (h_baseline, "visible", @update_baseline);
+        addproperty ("basevalue", h_baseline, "data", 0);
+        addlistener (h_baseline, "basevalue", {@update_baseline, 0});
+        addlistener (h_baseline, "ydata", {@update_baseline, 1});
+        addlistener (h_baseline, "visible", {@update_baseline, 2});
       endif
 
       ## Setup the hggroup and listeners.
       addproperty ("showbaseline", hg, "radio", "{on}|off");
+      addproperty ("baseline", hg, "data", h_baseline);
       addproperty ("basevalue", hg, "data", 0);
-      addproperty ("baseline", hg, "data", h_baseline);
 
       if (! have_z)
         addlistener (hg, "showbaseline", @show_baseline);
@@ -118,16 +116,18 @@
       endif
 
       addproperty ("color", hg, "linecolor", lc);
+      addproperty ("linestyle", hg, "linelinestyle", ls);
       addproperty ("linewidth", hg, "linelinewidth", 0.5);
-      addproperty ("linestyle", hg, "linelinestyle", ls);
       addproperty ("marker", hg, "linemarker", ms);
+      addproperty ("markeredgecolor", hg, "linemarkerfacecolor", mc);
       addproperty ("markerfacecolor", hg, "linemarkerfacecolor", fc);
       addproperty ("markersize", hg, "linemarkersize", 6);
 
       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, "markeredgecolor", @update_props);
       addlistener (hg, "markerfacecolor", @update_props);
       addlistener (hg, "markersize", @update_props);
 
@@ -165,317 +165,171 @@
 
 endfunction
 
-function [x, y, z, dofill, lc, ls, mc, ms, newargs] = check_stem_arg (have_z, varargin)
-
-  ## FIXME: There seems to be a lot of duplicated code in this function.
-  ##        It seems like it should be possible to simplify things by
-  ##        combining some of the nearly identical code sections into
-  ##        additional subfunctions.
-  ## FIXME: The code is so convoluted that certain options, such as "filled",
-  ##        are not being processed correctly.
+function [x, y, z, dofill, lc, ls, mc, ms, args] = check_stem_arg (have_z, varargin)
 
   if (have_z)
     caller = "stem3";
   else
     caller = "stem";
   endif
+  nargin = nargin - 1;  # account for have_z argument 
 
-  ## Remove prop/val pairs from data to consider.
-  i = 2;
-  newargs = {};
-  while (i < length (varargin))
-    if (ischar (varargin{i}) && !(strcmpi ("fill", varargin{i})
-                                  || strcmpi ("filled", varargin{i})))
-      newargs{end + 1} = varargin{i};
-      newargs{end + 1} = varargin{i + 1};
-      nargin = nargin - 2;
-      varargin(i:i+1) = [];
-    else
-      i++;
-    endif
-  endwhile
+  num_numeric = find (cellfun ("isclass", varargin, "char"), 1) - 1;
+  if (isempty (num_numeric))
+    num_numeric = nargin;     
+  endif
 
-  ## set specifiers to default values.
-  [lc, ls, mc, ms] = set_default_values ();
-  dofill = 0;
-  fill_2 = 0;
-  linespec_2 = 0;
-  z = [];
+  if (num_numeric < 1 || num_numeric > 3)
+    print_usage (caller);
+  endif
 
-  ## Check input arguments.
-  if (nargin == 2)
+  x = y = z = [];
+  if (num_numeric == 1)
     if (have_z)
       z = varargin{1};
-      x = 1:rows (z);
-      y = 1:columns (z);
     else
       y = varargin{1};
+    endif
+  elseif (num_numeric == 2)
+    if (have_z)
+      error ("stem3: must define X, Y, and Z");
+    else
+      x = varargin{1};
+      y = varargin{2};
+    endif
+  else  # nun_numeric == 3
+    if (have_z)
+      x = varargin{1};
+      y = varargin{2};
+      z = varargin{3};
+    else
+      error ("stem: can not define Z for 2-D stem plot");
+    endif
+  endif
+
+  ## Validate numeric data
+  if (have_z)
+    if (isempty (x))
+      [nr, nc] = size (z);
+      if (nr >= nc)
+        x = repmat ([1:nc], nr, 1);
+        y = repmat ([1:nr]', 1, nc);
+      else
+        x = repmat ([1:nc], nr, 1);
+        y = repmat ([1:nr]', 1, nc);
+      endif
+    endif
+    if (! (ismatrix (x) && ismatrix (y) && ismatrix (z)))
+      error ("stem3: X, Y, and Z must be numeric");
+    endif
+  else
+    if (isempty (x))
       if (isvector (y))
         x = 1:length (y);
       elseif (ismatrix (y))
         x = 1:rows (y);
-      else
-        error ("stem: Y must be a matrix");
-      endif # in each case, x & y will be defined
-    endif
-  elseif (nargin == 3)
-    ## Several possibilities
-    ##
-    ## 1. the real y data
-    ## 2. 'filled'
-    ## 3. line spec
-    if (ischar (varargin{2}))
-      ## Only 2. or 3. possible.
-      if (strcmpi ("fill", varargin{2}) || strcmpi ("filled", varargin{2}))
-        dofill = 1;
-      else
-        ## Parse the linespec.
-        [lc, ls, mc, ms] = stem_line_spec (caller, varargin{2});
-      endif
-      if (have_z)
-        z = varargin{1};
-        x = 1:rows (z);
-        y = 1:columns (z);
-      else
-        y = varargin{1};
-        if (isvector (y))
-          x = 1:length (y);
-        elseif (ismatrix (y))
-          x = 1:rows (y);
-        else
-          error ("stem: Y must be a matrix");
-        endif # in each case, x & y will be defined
-      endif
-    else
-      if (have_z)
-        error ("stem3: must define X, Y and Z");
-      else
-        ## Must be the real y data.
-        x = varargin{1};
-        y = varargin{2};
-        if (! (ismatrix (x) && ismatrix (y)))
-          error ("stem: X and Y must be matrices");
-        endif
       endif
     endif
-  elseif (nargin == 4)
-    ## Again, several possibilities:
-    ##
-    ## arg2 1. real y
-    ## arg2 2. 'filled' or linespec
-    ## arg3 1. real z
-    ## arg3 2. 'filled' or linespec
-    if (ischar (varargin{2}))
-      ## Only arg2 2. / arg3 1. & arg3 3. are possible.
-      if (strcmpi ("fill", varargin{2}) || strcmpi ("filled", varargin{2}))
-        dofill = 1;
-        fill_2 = 1; # Be sure, no second "fill" is in the arguments.
-      else
-        ## Must be a linespec.
-        [lc, ls, mc, ms] = stem_line_spec (caller, varargin{2});
-        linespec_2 = 1;
-      endif
-      if (have_z)
-        z = varargin{1};
-        x = 1:rows (z);
-        y = 1:columns (z);
-      else
-        y = varargin{1};
-        if (isvector (y))
-          x = 1:length (y);
-        elseif (ismatrix (y))
-          x = 1:rows (y);
-        else
-          error ("stem: Y must be a matrix");
-        endif # in each case, x & y will be defined
-      endif
-    else
-      if (have_z)
-        x = varargin{1};
-        y = varargin{2};
-        z = varargin{3};
-        if (! (ismatrix (x) && ismatrix (y) && ismatrix (z)))
-          error ("stem3: X, Y and Z must be matrices");
-        endif
-      else
-        ## must be the real y data.
-        x = varargin{1};
-        y = varargin{2};
-        if (! (ismatrix (x) && ismatrix (y)))
-          error ("stem: X and Y must be matrices");
-        endif
-      endif
-    endif # if ischar (varargin{2})
-    if (! have_z)
-      ## varargin{3} must be char.
-      ## Check for "fill.
-      if ((strcmpi (varargin{3}, "fill") || strcmpi (varargin{3}, "filled"))
-          && fill_2)
-        error ("stem: duplicate fill argument");
-      elseif (strcmpi ("fill", varargin{3}) && linespec_2)
-        ## Must be "fill".
-        dofill = 1;
-        fill_2 = 1;
-      elseif ((strcmpi (varargin{3}, "fill") || strcmpi (varargin{3}, "filled"))
-          && !linespec_2)
-        ## Must be "fill".
-        dofill = 1;
-        fill_2 = 1;
-      elseif (! linespec_2)
-        ## Must be linespec.
-        [lc, ls, mc, ms] = stem_line_spec (caller, varargin{3});
-        linespec_2 = 1;
-      endif
+    if (! (ismatrix (x) && ismatrix (y)))
+      error ("stem: X and Y must be numeric");
     endif
-  elseif (nargin == 5)
-    if (have_z)
-      x = varargin{1};
-      y = varargin{2};
-      z = varargin{3};
-      if (! (ismatrix (x) && ismatrix (y) && ismatrix (z)))
-        error ("stem3: X, Y and Z must be matrices");
-      endif
-    else
-      x = varargin{1};
-      y = varargin{2};
-      if (! (ismatrix (x) && ismatrix (y)))
-        error ("stem: X and Y must be matrices");
-      endif
-    endif
-
-    if (! have_z)
-      if (strcmpi (varargin{3}, "fill") || strcmpi (varargin{3}, "filled"))
-        dofill = 1;
-        fill_2 = 1; # Be sure, no second "fill" is in the arguments.
-      else
-        ## Must be a linespec.
-        [lc, ls, mc, ms] = stem_line_spec (caller, varargin{3});
-        linespec_2 = 1;
-      endif
-    endif
-
-    ## Check for "fill".
-    if ((strcmpi (varargin{4}, "fill") || strcmpi (varargin{4}, "filled"))
-        && fill_2)
-      error ("%s: duplicate fill argument", caller);
-    elseif ((strcmpi (varargin{4}, "fill") || strcmpi (varargin{4}, "filled"))
-        && linespec_2)
-      ## Must be "fill".
-      dofill = 1;
-      fill_2 = 1;
-    elseif (!strcmpi (varargin{4}, "fill") && !strcmpi (varargin{4}, "filled")
-        && !linespec_2)
-      ## Must be linespec.
-      [lc, ls, mc, ms] = stem_line_spec (caller, varargin{4});
-      linespec_2 = 1;
-    endif
-  elseif (nargin == 6 && have_z)
-    x = varargin{1};
-    y = varargin{2};
-    z = varargin{3};
-    if (! (ismatrix (x) && ismatrix (y) && ismatrix (z)))
-      error ("stem3: X, Y and Z must be matrices");
-    endif
-
-    if (strcmpi (varargin{4}, "fill") || strcmpi (varargin{4}, "filled"))
-      dofill = 1;
-      fill_2 = 1; # be sure, no second "fill" is in the arguments
-    else
-      ## Must be a linespec.
-      [lc, ls, mc, ms] = stem_line_spec (caller, varargin{4});
-      linespec_2 = 1;
-    endif
-
-    ## check for "fill" ..
-    if ((strcmpi (varargin{5}, "fill") || strcmpi (varargin{5}, "filled"))
-        && fill_2)
-      error ("stem3: duplicate fill argument");
-    elseif ((strcmpi (varargin{5}, "fill") || strcmpi (varargin{5}, "filled"))
-        && linespec_2)
-      ## Must be "fill".
-      dofill = 1;
-      fill_2 = 1;
-    elseif (!strcmpi (varargin{5}, "fill") && !strcmpi (varargin{5}, "filled")
-            && !linespec_2)
-      ## Must be linespec.
-      [lc, ls, mc, ms] = stem_line_spec (caller, varargin{5});
-      linespec_2 = 1;
-    endif
-  else
-    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(:);
+    if (! size_equal (x, y, z))
+      error ("stem3: inconsistent sizes for X, Y, and Z");
     endif
+    x = x(:);
+    y = y(:);
+    z = z(:);
   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(:);
+          error ("stem: inconsistent sizes for X and Y");
         endif
+        y = y(:);
       else
         if (length (x) == rows (y))
           x = repmat (x(:), 1, columns (y));
         else
-          error ("stem: inconsistent size of x and y");
+          error ("stem: inconsistent sizes for X and Y");
         endif
       endif
-    elseif (!size_equal (x, y))
-      error ("stem: inconsistent size of x and y");
+    elseif (! size_equal (x, y))
+      error ("stem: inconsistent sizes for X and Y");
     endif
   endif
 
+  dofill = false;
+  have_line_spec = false;
+  ## set specifiers to default values.
+  [lc, ls, mc, ms] = set_default_values ();
+
+  args = {};
+  ioff = num_numeric + 1;
+  while (ioff <= nargin)
+    arg = varargin{ioff++};
+    if (ischar (arg) && any (strcmpi (arg, {"fill", "filled"})))
+      dofill = true;
+    elseif ((ischar (arg) || iscell (arg)) && ! have_line_spec)
+      [linespec, valid] = __pltopt__ (caller, arg, false);
+      if (valid)
+        have_line_spec = true;
+        [lc, ls, mc, ms] = stem_line_spec (linespec);
+      else
+        args{end+1} = arg;
+        if (ioff <= nargin)
+          args{end+1} = varargin{ioff++};
+        else
+          error ('%s: No value specified for property "%s"', caller, arg);
+        endif
+      endif
+    else
+      args{end+1} = arg;
+      if (ioff <= nargin)
+        args{end+1} = varargin{ioff++};
+      else
+        error ('%s: No value specified for property "%s"', caller, arg);
+      endif
+    endif
+  endwhile
+
+endfunction
+
+function [lc, ls, mc, ms] = stem_line_spec (lspec)
+
+  [lc, ls, mc, ms] = set_default_values ();
+
+  if (! isempty (lspec.color))
+    lc = mc = lspec.color;
+  endif
+
+  if (! isempty (lspec.linestyle) && ! strcmp (lspec.linestyle, "none"))
+    ls = lspec.linestyle;
+  endif
+
+  if (! isempty (lspec.marker) && ! strcmp (lspec.marker, "none"))
+    ms = lspec.marker;
+  endif
+
 endfunction
 
-function [lc, ls, mc, ms] = stem_line_spec (caller, str)
-  if (! ischar (str))
-    error ("%s: expecting argument to be \"fill\" or a string of specifiers",
-           caller);
-  endif
-  [lc, ls, mc, ms] = set_default_values ();
-  ## Parse the line specifier string.
-  cur_props = __pltopt__ ("stem", str, false);
-  for i = 1:length (cur_props)
-    if (isfield (cur_props(i), "color") && ! isempty (cur_props(i).color)); # means line color
-      mc = lc = cur_props(i).color;
-    elseif (isfield (cur_props(i), "linestyle"))
-      ls = cur_props(i).linestyle;
-      if (isempty (ls))
-        ls = __next_line_style__ ();
-      endif
-    elseif (isfield (cur_props(i), "marker") && ! strcmpi (cur_props(i).marker, "none"))
-      ms = cur_props(i).marker;
-      if (isempty (ms))
-        [dummy, ms] = __next_line_style__ ();
-      endif
-    endif
-  endfor
-endfunction
-
 function [lc, ls, mc, ms] = set_default_values ()
-  ## set default values
   mc = [];
   lc = [];
   ls = "-";
   ms = "o";
 endfunction
 
-function update_xlim (h, d)
+function update_xlim (h, ~)
   kids = get (h, "children");
   xlim = get (h, "xlim");
 
   for i = 1 : length (kids)
-    obj = get (kids (i));
+    obj = get (kids(i));
     if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline"))
       if (any (get (obj.baseline, "xdata") != xlim))
         set (obj.baseline, "xdata", xlim);
@@ -484,37 +338,39 @@
   endfor
 endfunction
 
-function update_baseline (h, d)
+function update_baseline (h, ~, src)
   visible = get (h, "visible");
-  ydata = get (h, "ydata")(1);
+  if (src == 0)
+    basevalue = get (h, "basevalue");
+  else
+    basevalue = get (h, "ydata")(1);
+  endif
 
   kids = get (get (h, "parent"), "children");
   for i = 1 : length (kids)
-    obj = get (kids (i));
+    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 (! strcmpi (get (kids(i), "showbaseline"), visible))
-        set (kids (i), "showbaseline", visible);
+      ## Avoid lots of unnecessary listener updates
+      if (! strcmp (get (kids(i), "showbaseline"), visible))
+        set (kids(i), "showbaseline", visible);
       endif
-      if (! strcmpi (get (kids(i), "basevalue"), visible))
-        set (kids (i), "basevalue", ydata);
+      if (get (kids(i), "basevalue") != basevalue)
+        set (kids(i), "basevalue", basevalue);
       endif
     endif
   endfor
 endfunction
 
-function show_baseline (h, d)
+function show_baseline (h, ~)
   set (get (h, "baseline"), "visible", get (h, "showbaseline"));
 endfunction
 
-function move_baseline (h, d)
+function move_baseline (h, ~)
   b0 = get (h, "basevalue");
   bl = get (h, "baseline");
 
-  if (get (bl, "ydata") != [b0, b0])
-    set (bl, "ydata", [b0, b0]);
-  endif
+  set (bl, "ydata", [b0, b0]);
 
   kids = get (h, "children");
   yt = get (h, "ydata")(:)';
@@ -523,18 +379,18 @@
   set (kids(2), "ydata", yt);
 endfunction
 
-function update_props (h, d)
+function update_props (h, ~)
   kids = get (h, "children");
   set (kids(2), "color", get (h, "color"),
-       "linewidth", get (h, "linewidth"),
-       "linestyle", get (h, "linestyle"));
-  set (kids(1), "color", get (h, "color"),
-       "marker", get (h, "marker"),
-       "markerfacecolor", get (h, "markerfacecolor"),
-       "markersize", get (h, "markersize"));
+                "linestyle", get (h, "linestyle"),
+                "linewidth", get (h, "linewidth"));
+  set (kids(1), "color", get (h, "markeredgecolor"),
+                "marker", get (h, "marker"),
+                "markerfacecolor", get (h, "markerfacecolor"),
+                "markersize", get (h, "markersize"));
 endfunction
 
-function update_data (h, d)
+function update_data (h, ~)
   x = get (h, "xdata");
   y = get (h, "ydata");
   z = get (h, "zdata");
--- a/scripts/plot/stairs.m
+++ b/scripts/plot/stairs.m
@@ -70,27 +70,28 @@
 
   if (nargin < 1)
     print_usage ();
-  else
-    if (nargout > 1)
-      [h, xs, ys] = __stairs__ (false, varargin{:});
-    else
-  oldfig = [];
-  if (! isempty (hax))
-    oldfig = get (0, "currentfigure");
   endif
-      unwind_protect
-        hax = newplot (hax);
-        [htmp, xxs, yys] = __stairs__ (true, varargin{:});
-      unwind_protect_cleanup
-        if (! isempty (oldfig))
-          set (0, "currentfigure", oldfig);
-        endif
-      end_unwind_protect
-      if (nargout == 1)
-        xs = htmp;
+
+  if (nargout < 2)
+    oldfig = [];
+    if (! isempty (hax))
+      oldfig = get (0, "currentfigure");
+    endif
+    unwind_protect
+      hax = newplot (hax);
+      [htmp, xxs, yys] = __stairs__ (true, varargin{:});
+    unwind_protect_cleanup
+      if (! isempty (oldfig))
+        set (0, "currentfigure", oldfig);
       endif
+    end_unwind_protect
+    if (nargout == 1)
+      xs = htmp;
     endif
+  else
+    [~, xs, ys] = __stairs__ (false, varargin{:});
   endif
+
 endfunction
 
 function [h, xs, ys] = __stairs__ (doplot, varargin)
@@ -98,42 +99,35 @@
   if (nargin == 2 || ischar (varargin{2}))
     y = varargin{1};
     varargin(1) = [];
-    if (ismatrix (y))
-      if (isvector (y))
-        y = y(:);
-      endif
-      x = 1:rows (y);
+    if (! ismatrix (y) || ndims (y) > 2)
+      error ("stairs: Y must be a numeric 2-D vector or matrix");
     endif
+    if (isvector (y))
+      y = y(:);
+    endif
+    x = 1:rows (y);
   else
     x = varargin{1};
     y = varargin{2};
     varargin(1:2) = [];
-  endif
-
-  if (ndims (x) > 2 || ndims (y) > 2)
-    error ("stairs: X and Y must be 2-D objects");
+    if (! ismatrix (x) || ! ismatrix (y) || ndims (x) > 2 || ndims (y) > 2)
+      error ("stairs: X and Y must be numeric 2-D vectors or matrices");
+    endif
   endif
 
   vec_x = isvector (x);
-
   if (vec_x)
     x = x(:);
   endif
 
   if (isvector (y))
     y = y(:);
+  elseif (ismatrix (y) && vec_x)
+    x = repmat (x, [1, columns(y)]);
   endif
 
-  if (ismatrix (y))
-    [nr, nc] = size (y);
-    if (vec_x)
-      x = repmat (x, [1, nc]);
-    else
-      [x_nr, x_nc] = size (x);
-      if (x_nr != nr || x_nc != nc)
-        error ("stairs: argument size mismatch");
-      endif
-    endif
+  if (! size_equal (x, y))
+    error ("stairs: X and Y sizes must match");
   endif
 
   len = 2*nr - 1;
@@ -153,9 +147,9 @@
   ys(ridx,:) = y(2:nr,:);
 
   have_line_spec = false;
-  for i = 1 : length (varargin)
+  for i = 1:2:numel (varargin)
     arg = varargin{i};
-    if ((ischar (arg) || iscell (arg)) && ! have_line_spec)
+    if (ischar (arg) || iscell (arg))
       [linespec, valid] = __pltopt__ ("stairs", arg, false);
       if (valid)
         have_line_spec = true;
@@ -170,6 +164,27 @@
     hold_state = get (gca (), "nextplot");
     unwind_protect
       for i = 1 : columns (y)
+
+        if (have_line_spec)
+          lc = linespec.color;
+          if (isempty (lc))
+            lc = __next_line_color__ ();
+          endif
+          ls = linespec.linestyle;
+          if (isempty (ls))
+            ls = "-";
+          endif
+          mk = linespec.marker;
+          if (isempty (mk))
+            mk = "none";
+          endif
+        else
+          lc = __next_line_color__ ();
+          ls = "-";
+          mk = "none";
+        endif
+
+        ## Must occur after __next_line_color__ in order to work correctly.
         hg = hggroup ();
         h = [h; hg];
         args = __add_datasource__ ("stairs", hg, {"x", "y"}, varargin{:});
@@ -180,32 +195,27 @@
         addlistener (hg, "xdata", @update_data);
         addlistener (hg, "ydata", @update_data);
 
-        if (have_line_spec)
-          htmp = line (xs(:,i).', ys(:,i).', "color", linespec.color,
-                       "parent", hg);
-        else
-          htmp = line (xs(:,i).', ys(:,i).', "color", __next_line_color__ (),
-                       "parent", hg);
-        endif
+        htmp = line (xs(:,i).', ys(:,i).', "color", lc, "linestyle", ls,
+                                           "marker", mk, "parent", hg);
 
         addproperty ("color", hg, "linecolor", get (htmp, "color"));
+        addproperty ("linestyle", hg, "linelinestyle", get (htmp, "linestyle"));
         addproperty ("linewidth", hg, "linelinewidth", get (htmp, "linewidth"));
-        addproperty ("linestyle", hg, "linelinestyle", get (htmp, "linestyle"));
 
         addproperty ("marker", hg, "linemarker", get (htmp, "marker"));
+        addproperty ("markeredgecolor", hg, "linemarkeredgecolor",
+                     get (htmp, "markeredgecolor"));
         addproperty ("markerfacecolor", hg, "linemarkerfacecolor",
                      get (htmp, "markerfacecolor"));
-        addproperty ("markeredgecolor", hg, "linemarkeredgecolor",
-                     get (htmp, "markeredgecolor"));
         addproperty ("markersize", hg, "linemarkersize",
                      get (htmp, "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, "markeredgecolor", @update_props);
         addlistener (hg, "markerfacecolor", @update_props);
-        addlistener (hg, "markeredgecolor", @update_props);
         addlistener (hg, "markersize", @update_props);
 
         if (! isempty (args))
@@ -221,57 +231,18 @@
 
 endfunction
 
-
-%!demo
-%! clf;
-%! x = 1:10;
-%! rand_1x10_data1 = [0.073, 0.455, 0.837, 0.124, 0.426, 0.781, 0.004, 0.024, 0.519, 0.698];
-%! y = rand_1x10_data1;
-%! stairs (x, y);
-
-%!demo
-%! clf;
-%! x = 1:10;
-%! rand_1x10_data2 = [0.014, 0.460, 0.622, 0.394, 0.531, 0.378, 0.466, 0.788, 0.342, 0.893];
-%! y = rand_1x10_data2;
-%! [xs, ys] = stairs (x, y);
-%! plot (xs, ys);
-
-%!demo
-%! clf;
-%! stairs (1:9);
-
-%!demo
-%! clf;
-%! [xs, ys] = stairs (9:-1:1);
-%! plot (xs, ys);
-
-%!demo
-%! clf;
-%! N = 11;
-%! x = 0:(N-1);
-%! y = rand (1, N);
-%! hs = stairs (x(1), y(1));
-%! axis ([1, N-1 0, 1]);
-%! for k=2:N
-%!   set (hs, 'xdata', x(1:k), 'ydata', y(1:k));
-%!   drawnow ();
-%!   pause (0.2);
-%! end
-
-
-function update_props (h, d)
+function update_props (h, ~)
   set (get (h, "children"),
        "color", get (h, "color"),
+       "linestyle", get (h, "linestyle"),
        "linewidth", get (h, "linewidth"),
-       "linestyle", get (h, "linestyle"),
        "marker", get (h, "marker"),
+       "markeredgecolor", get (h, "markeredgecolor"),
        "markerfacecolor", get (h, "markerfacecolor"),
-       "markeredgecolor", get (h, "markeredgecolor"),
        "markersize", get (h, "markersize"));
 endfunction
 
-function update_data (h, d)
+function update_data (h, ~)
   x = get (h, "xdata");
   y = get (h, "ydata");
 
@@ -298,3 +269,62 @@
   set (get (h, "children"), "xdata", xs, "ydata", ys);
 endfunction
 
+
+%!demo
+%! clf;
+%! rand_1x10_data1 = [0.073, 0.455, 0.837, 0.124, 0.426, 0.781, 0.004, 0.024, 0.519, 0.698];
+%! y = rand_1x10_data1;
+%! stairs (y);
+%! title ('stairs() plot of y-data');
+
+%!demo
+%! clf;
+%! x = 1:10;
+%! rand_1x10_data2 = [0.014, 0.460, 0.622, 0.394, 0.531, 0.378, 0.466, 0.788, 0.342, 0.893];
+%! y = rand_1x10_data2;
+%! [xs, ys] = stairs (x, y);
+%! plot (xs, ys);
+%! title ('plot() of stairs() generated data');
+
+%!demo
+%! clf;
+%! stairs (1:9, '-o');
+%! title ('stairs() plot with linespec to modify marker');
+
+%!demo
+%! clf;
+%! stairs (9:-1:1, 'marker', 's', 'markersize', 10, 'markerfacecolor', 'm');
+%! title ('stairs() plot with prop/val pairs to modify appearance');
+
+%!demo
+%! clf;
+%! N = 11;
+%! x = 0:(N-1);
+%! y = rand (1, N);
+%! hs = stairs (x(1), y(1));
+%! axis ([1, N-1 0, 1]);
+%! title ('stairs plot data modified through handle');
+%! for k = 2:N
+%!   set (hs, 'xdata', x(1:k), 'ydata', y(1:k));
+%!   drawnow ();
+%!   pause (0.2);
+%! end
+
+## Invisible figure used for tests
+%!shared hf, hax
+%! hf = figure ("visible", "off");
+%! hax = axes;
+
+%!error stairs ()
+%!error <Y must be a numeric 2-D vector> stairs (hax, {1})
+%!error <Y must be a numeric 2-D vector> stairs (ones (2,2,2))
+%!error <X and Y must be numeric 2-D vector> stairs ({1}, 1)
+%!error <X and Y must be numeric 2-D vector> stairs (1, {1})
+%!error <X and Y must be numeric 2-D vector> stairs (ones (2,2,2), 1)
+%!error <X and Y must be numeric 2-D vector> stairs (1, ones (2,2,2))
+%!error <X and Y sizes must match> stairs (1:2, 1:3)
+
+## Close figure used for testing
+%!test
+%! close (hf);
+
--- a/scripts/plot/stem.m
+++ b/scripts/plot/stem.m
@@ -57,11 +57,13 @@
 ## If the first argument @var{hax} is an axes handle, then plot into this axis,
 ## rather than the current axes returned by @code{gca}.
 ##
-## The optional return value @var{h} is a vector of "stem series" graphics
-## handles with one handle per column of the variable @var{y}.  The
-## 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,
+## The optional return value @var{h} is a handle to a "stem series" hggroup.
+## The single hggroup handle has all of the graphical elements comprising the
+## plot as its children; This allows the properties of multiple graphics
+## objects to be changed by modifying just a single property of the
+## "stem series" hggroup.
+##
+## For example,
 ##
 ## @example
 ## @group
@@ -76,6 +78,40 @@
 ## @noindent
 ## changes the color of the second "stem series" and moves the base line
 ## of the first.
+##
+## Stem Series Properties
+##
+## @table @asis
+## @item linestyle
+## The linestyle of the stem.  (Default: @qcode{"-"})
+##
+## @item linewidth
+## The width of the stem.  (Default: 0.5)
+##
+## @item color
+## The color of the stem, and if not separately specified, the marker.
+## (Default: "b" [blue])
+##
+## @item marker
+## The marker symbol to use at the top of each stem.  (Default: @qcode{"o"})
+##
+## @item markeredgecolor
+## The edge color of the marker.  (Default: @qcode{"color"} property)
+##
+## @item markerfacecolor
+## The color to use for "filling" the marker.  (Default: @qcode{"none"}
+## [unfilled])
+##
+## @item markersize
+## The size of the marker.  (Default: 6)
+##
+## @item baseline
+## The handle of the line object which implements the baseline.  Use @code{set}
+## with the returned handle to change graphic properties of the baseline.
+##
+## @item basevalue
+## The y-value where the baseline is drawn.  (Default: 0)
+## @end table
 ## @seealso{stem3, bar, hist, plot, stairs}
 ## @end deftypefn
 
@@ -99,38 +135,51 @@
 
 %!demo
 %! clf;
-%! x = 1:10;
-%! stem (x);
+%! y = 1:10;
+%! stem (y);
+%! title ('stem plot of y-values only');
 
 %!demo
 %! clf;
 %! x = 1:10;
 %! y = 2*x;
 %! stem (x, y);
+%! title ('stem plot of x and y-values');
 
 %!demo
 %! clf;
 %! x = 1:10;
 %! y = 2*x;
 %! h = stem (x, y, 'r');
+%! title ('stem plot with modified color');
 
 %!demo
 %! clf;
 %! x = 1:10;
 %! y = 2*x;
 %! h = stem (x, y, '-.k');
+%! title ('stem plot with modified line style and color');
 
 %!demo
 %! clf;
 %! x = 1:10;
 %! y = 2*x;
-%! h = stem (x, y, '-.k.');
+%! h = stem (x, y, '-.ks');
+%! title ('stem plot with modified line style, color, and marker');
 
 %!demo
 %! clf;
 %! x = 1:10;
 %! y = 2*x;
 %! h = stem (x, y, 'filled');
+%! title ('stem plot with "filled" markers');
+
+%!demo
+%! clf;
+%! x = 1:10;
+%! y = 2*x;
+%! h = stem (x, y, 'markerfacecolor', [1 0 1]);
+%! title ('stem plot modified with property/value pair');
 
 %!demo
 %! clf;
@@ -139,6 +188,7 @@
 %! h = stem (x, y);
 %! set (h(2), 'color', 'g');
 %! set (h(1), 'basevalue', -1);
+%! title ('stem plots modified through hggroup handle');
 
 %!demo
 %! clf;
@@ -147,9 +197,19 @@
 %! y = rand (1, N);
 %! hs = stem (x(1), y(1));
 %! set (gca (), 'xlim', [1, N-1], 'ylim', [0, 1]);
+%! title ('stem plot data modified through hggroup handle');
 %! for k=2:N
 %!   set (hs, 'xdata', x(1:k), 'ydata', y(1:k))
 %!   drawnow ();
 %!   pause (0.2);
 %! end
 
+%!error stem ()
+%!error <can not define Z for 2-D stem plot> stem (1,2,3)
+%!error <X and Y must be numeric> stem ({1})
+%!error <X and Y must be numeric> stem (1, {1})
+%!error <inconsistent sizes for X and Y> stem (1:2, 1:3)
+%!error <inconsistent sizes for X and Y> stem (1:2, ones (3,3))
+%!error <inconsistent sizes for X and Y> stem (ones (2,2), ones (3,3))
+%!error <No value specified for property "FOO"> stem (1, "FOO")
+
--- a/scripts/plot/stem3.m
+++ b/scripts/plot/stem3.m
@@ -39,8 +39,9 @@
 ## If the first argument @var{hax} is an axes handle, then plot into this axis,
 ## rather than the current axes returned by @code{gca}.
 ##
-## The optional return value @var{h} is a vector with the handles of the line
-## and marker objects used to draw the stems as a "stem series" object.
+## The optional return value @var{h} is a handle to the "stem series" hggroup
+## containing the line and marker objects used for the plot.
+## @xref{XREFstem,,stem}, for a description of the "stem series" object.
 ##
 ## Example:
 ##
@@ -60,7 +61,7 @@
 
 function h = stem3 (varargin)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -79,3 +80,12 @@
 %! stem3 (cos (theta), sin (theta), theta);
 %! title ('stem3() plot');
 
+%!error stem3 ()
+%!error <must define X, Y, and Z> stem3 (1,2)
+%!error <X, Y, and Z must be numeric> stem3 ({1}, 1, 1)
+%!error <X, Y, and Z must be numeric> stem3 (1, {1}, 1)
+%!error <X, Y, and Z must be numeric> stem3 (1, 1, {1})
+%!error <inconsistent sizes for X, Y, and Z> stem3 (ones (2,2), 1, 1);
+%!error <inconsistent sizes for X, Y, and Z> stem3 (1, ones (2,2), 1);
+%!error <inconsistent sizes for X, Y, and Z> stem3 (1, 1, ones (2,2));
+%!error <No value specified for property "FOO"> stem3 (1, "FOO")
--- a/scripts/plot/trimesh.m
+++ b/scripts/plot/trimesh.m
@@ -39,7 +39,9 @@
 ## change the colormap to control the appearance.
 ##
 ## Optionally, the color of the mesh can be specified independently of @var{z}
-## by supplying a color matrix, @var{c}.
+## by supplying a color matrix, @var{c}.  If @var{z} has N elements, then
+## @var{c} should be an Nx1 vector for colormap data or an Nx3 matrix for
+## RGB data.
 ##
 ## Any property/value pairs are passed directly to the underlying patch object.
 ##
@@ -55,21 +57,39 @@
   endif
 
   if (nargin == 3)
-    triplot (tri, x, y);
+    htmp = triplot (tri, x, y);
   elseif (ischar (z))
-    triplot (tri, x, y, z, varargin{:});
+    htmp = triplot (tri, x, y, z, varargin{:});
   else
+    ## Process color argument
+    if (nargin > 4 && isnumeric (varargin{1}))
+      c = varargin{1};
+      varargin(1) = [];
+      if (isvector (c))
+        if (numel (c) != numel (z))
+          error ("trimesh: C must have 'numel (Z)' elements");
+        endif
+        c = c(:);
+      elseif (rows (c) != numel (z) || columns (c) != 3)
+        error ("trimesh: TrueColor C matrix must be 'numel (Z)' rows by 3 columns");
+      endif
+    else
+      c = z(:);
+    endif
+
     hax = newplot ();
-    handle = patch ("Vertices", [x(:), y(:), z(:)], "Faces", tri,
-                    "FaceColor", "none", "EdgeColor", __next_line_color__ (),
-                    varargin{:});
+
+    htmp = patch ("Vertices", [x(:), y(:), z(:)], "Faces", tri,
+                  "FaceVertexCdata", c, "EdgeColor", "flat", "FaceColor", "w",
+                  varargin{:});
     if (! ishold ())
-      set (hax, "view", [-37.5, 30],
+      set (hax, "view", [-37.5, 30], "box", "off",
                 "xgrid", "on", "ygrid", "on", "zgrid", "on");
     endif
-    if (nargout > 0)
-      h = handle;
-    endif
+  endif
+
+  if (nargout > 0)
+    h = htmp;
   endif
 
 endfunction
@@ -87,3 +107,12 @@
 %! tri = delaunay (x(:), y(:));
 %! trimesh (tri, x(:), y(:), z(:));
 
+%% Test input validation
+%!error trimesh ()
+%!error trimesh (1)
+%!error trimesh (1,2)
+%!error <C must have 'numel \(Z\)' elements> trimesh (1,2,3,4,[5 6])
+%!error <C must have 'numel \(Z\)' elements> trimesh (1,2,3,4,[5 6]')
+%!error <TrueColor C matrix must> trimesh ([1;1],[2;2],[3;3],[4;4],zeros(3,3))
+%!error <TrueColor C matrix must> trimesh ([1;1],[2;2],[3;3],[4;4],zeros(2,2))
+
--- a/scripts/plot/trisurf.m
+++ b/scripts/plot/trisurf.m
@@ -37,7 +37,9 @@
 ## change the colormap to control the appearance.
 ##
 ## Optionally, the color of the mesh can be specified independently of @var{z}
-## by supplying a color matrix, @var{c}.
+## by supplying a color matrix, @var{c}.  If @var{z} has N elements, then
+## @var{c} should be an Nx1 vector for colormap data or an Nx3 matrix for
+## RGB data.
 ##
 ## Any property/value pairs are passed directly to the underlying patch object.
 ##
@@ -48,43 +50,49 @@
 
 function h = trisurf (tri, x, y, z, varargin)
 
-  if (nargin < 3)
+  if (nargin < 4)
     print_usage ();
   endif
 
-  if (nargin == 3)
-    triplot (tri, x, y);
-  elseif (ischar (z))
-    triplot (tri, x, y, z, varargin{:});
-  else
-    if (nargin > 4 && isnumeric (varargin{1}))
-      c = varargin{1};
-      varargin(1) = [];
-    else
-      c = z;
-    endif
-    if (! any (strcmpi (varargin, "FaceColor")))
-      nfc = numel (varargin) + 1;
-      varargin(nfc+(0:1)) = {"FaceColor", "flat"};
-    else
-      nfc = find (any (strcmpi (varargin, "FaceColor")), 1);
+  if (nargin > 4 && isnumeric (varargin{1}))
+    c = varargin{1};
+    varargin(1) = [];
+    if (isvector (c))
+      if (numel (c) != numel (z))
+        error ("trisurf: C must have 'numel (Z)' elements");
+      endif
+      c = c(:);
+    elseif (rows (c) != numel (z) || columns (c) != 3)
+      error ("trisurf: TrueColor C matrix must be 'numel (Z)' rows by 3 columns");
     endif
-    if (! any (strcmpi (varargin, "EdgeColor"))
-        && strcmpi (varargin{nfc+1}, "interp"))
-      varargin(end+(1:2)) = {"EdgeColor", "none"};
-    endif
-    hax = newplot ();
-    htmp = patch ("Faces", tri, "Vertices", [x(:), y(:), z(:)],
-                  "FaceVertexCData", reshape (c, numel (c), 1),
-                  varargin{:});
-    if (nargout > 0)
-      h = htmp;
-    endif
+  else
+    c = z(:);
+  endif
+  ## FIXME: Is all this extra input parsing necessary?
+  ##        Is it for Matlab compatibility?
+  if (! any (strcmpi (varargin, "FaceColor")))
+    nfc = numel (varargin) + 1;
+    varargin(nfc+(0:1)) = {"FaceColor", "flat"};
+  else
+    nfc = find (any (strcmpi (varargin, "FaceColor")), 1);
+  endif
+  if (! any (strcmpi (varargin, "EdgeColor"))
+      && strcmpi (varargin{nfc+1}, "interp"))
+    varargin(end+(1:2)) = {"EdgeColor", "none"};
+  endif
 
-    if (! ishold ())
-      set (hax, "view", [-37.5, 30],
-                "xgrid", "on", "ygrid", "on", "zgrid", "on");
-    endif
+  hax = newplot ();
+
+  htmp = patch ("Faces", tri, "Vertices", [x(:), y(:), z(:)],
+                "FaceVertexCData", c, varargin{:});
+
+  if (! ishold ())
+    set (hax, "view", [-37.5, 30], "box", "off",
+              "xgrid", "on", "ygrid", "on", "zgrid", "on");
+  endif
+
+  if (nargout > 0)
+    h = htmp;
   endif
 
 endfunction
@@ -154,3 +162,13 @@
 %! tri = delaunay (x, y);
 %! trisurf (tri, x, y, z, 'facecolor', 'interp', 'edgecolor', 'k');
 
+%% Test input validation
+%!error trisurf ()
+%!error trisurf (1)
+%!error trisurf (1,2)
+%!error trisurf (1,2,3)
+%!error <C must have 'numel \(Z\)' elements> trisurf (1,2,3,4,[5 6])
+%!error <C must have 'numel \(Z\)' elements> trisurf (1,2,3,4,[5 6]')
+%!error <TrueColor C matrix must> trisurf ([1;1],[2;2],[3;3],[4;4],zeros(3,3))
+%!error <TrueColor C matrix must> trisurf ([1;1],[2;2],[3;3],[4;4],zeros(2,2))
+