Index: trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 34584)
@@ -114,6 +114,8 @@
 $(SRC)/shift.$(ARCH).o		\
 $(SRC)/sort.$(ARCH).o		\
-$(SRC)/spline_apply.$(ARCH).o	\
-$(SRC)/spline_construct.$(ARCH).o \
+$(SRC)/spline.$(ARCH).o		\
+$(SRC)/spline_commands.$(ARCH).o \
+$(SRC)/imspline_apply.$(ARCH).o	\
+$(SRC)/imspline_construct.$(ARCH).o \
 $(SRC)/imstats.$(ARCH).o	   \
 $(SRC)/style.$(ARCH).o		   \
Index: trunk/Ohana/src/opihi/cmd.data/dbconnect.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/dbconnect.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/dbconnect.c	(revision 34584)
@@ -33,4 +33,6 @@
   password[i] = 0;
 # endif
+
+  // XXX do I need to call mysql_library_init()?
 
   mysql_init (&mysql);
Index: trunk/Ohana/src/opihi/cmd.data/dbselect.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/dbselect.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/dbselect.c	(revision 34584)
@@ -61,4 +61,5 @@
   ALLOCATE (vec, Vector *, Ncols);
   for (i = 0; i < Ncols; i++) {
+    char *name = fields[i].name ? fields[i].name : fields[i].org_name;
     if ((vec[i] = SelectVector (fields[i].name, ANYVECTOR, TRUE)) == NULL) {
       gprint (GP_ERR, "trouble creating vector named %s\n", fields[i].name);
Index: trunk/Ohana/src/opihi/cmd.data/grid.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/grid.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/grid.c	(revision 34584)
@@ -178,5 +178,5 @@
   graphmode.ptype = 100; /* connect a pair */
   graphmode.etype = 0;
-  PlotVectorPair (kapa, &Xvec, &Yvec, &graphmode);
+  PlotVectorPair (kapa, &Xvec, &Yvec, NULL, &graphmode);
 
   free (Xvec.elements.Flt);
Index: trunk/Ohana/src/opihi/cmd.data/imspline_apply.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/imspline_apply.c	(revision 34584)
+++ trunk/Ohana/src/opihi/cmd.data/imspline_apply.c	(revision 34584)
@@ -0,0 +1,98 @@
+# include "data.h"
+
+// need to rename this as an image function
+int imspline_apply (int argc, char **argv) {
+  
+  int i, j, I, J;
+  int nx, ny, Nx, Ny;
+  float rx, ry, x, y;
+  float *Tx1, *Tx2, *Txc, *Ty1, *Ty2, *Tyc, *V, *V1, *V2;
+  Buffer *out, *y1, *y2;
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: imspline_apply <Y> <Y2> <out> (x/y) Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((y1  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((y2  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[3], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  // xdir = FALSE;
+  // if (!strcmp (argv[4], "x")) xdir = TRUE; 
+
+  nx = atoi (argv[5]);
+  ny = atoi (argv[6]);
+
+  Nx = y1[0].matrix.Naxis[0];
+  Ny = y1[0].matrix.Naxis[1];
+
+  rx = Nx / (float) nx;
+  ry = Ny / (float) ny;
+
+  /* create an output matrix buffer with desired nx, ny */
+  gfits_free_matrix (&out[0].matrix);
+  gfits_free_header (&out[0].header);
+
+  out[0].bitpix = y1[0].bitpix;
+  out[0].unsign = y1[0].unsign;
+  out[0].bscale = y1[0].bscale;
+  out[0].bzero  = y1[0].bzero;
+  gfits_copy_header (&y1[0].header, &out[0].header);
+  gfits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  gfits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+  if ((y1[0].file[0] != '*') && (y1[0].file[0] != '(')) {
+    sprintf (out[0].file, "*%s", y1[0].file);
+  } else {
+    sprintf (out[0].file, "%s", y1[0].file);
+  }
+
+  ALLOCATE (Ty2, float, Ny);
+  ALLOCATE (Ty1, float, Ny);
+  ALLOCATE (Tyc, float, Ny);
+  for (i = 0; i < Ny; i++) { Tyc[i] = i; }
+
+  ALLOCATE (Tx1, float, Nx);
+  ALLOCATE (Tx2, float, Nx);
+  ALLOCATE (Txc, float, Nx);
+  for (i = 0; i < Nx; i++) { Txc[i] = i; }
+
+  V = (float *)(out[0].matrix.buffer);
+
+  for (J = 0; J < ny; J++) {
+    y = J * ry;
+
+    /* construct spline for each element in this row */
+    for (i = 0; i < Nx; i++) {
+      V1 = (float *)(y1[0].matrix.buffer) + i;
+      V2 = (float *)(y2[0].matrix.buffer) + i;
+      for (j = 0; j < Ny; j++, V1+=Nx, V2+=Nx) {
+	Ty1[j] = *V1;
+	Ty2[j] = *V2;
+      }
+      Tx1[i] = spline_apply_flt (Tyc, Ty1, Ty2, Ny, y);
+    }
+    spline_construct_flt (Txc, Tx1, Nx, Tx2);
+
+    /* apply x-dir spline to new image */
+    for (I = 0; I < nx; I++, V++) {
+      x = I * rx;
+      *V = spline_apply_flt (Txc, Tx1, Tx2, Nx, x);
+    }
+  }
+
+  free (Ty1);
+  free (Ty2);
+  free (Tyc);
+  
+  free (Tx1);
+  free (Tx2);
+  free (Txc);
+  
+  return (TRUE);
+
+}
Index: trunk/Ohana/src/opihi/cmd.data/imspline_construct.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/imspline_construct.c	(revision 34584)
+++ trunk/Ohana/src/opihi/cmd.data/imspline_construct.c	(revision 34584)
@@ -0,0 +1,72 @@
+# include "data.h"
+
+// need to rename this as an image function
+int imspline_construct (int argc, char **argv) {
+  
+  int i, j, Nx, Ny;
+  float *Tx, *Ty, *Ty2, *V;
+  Buffer *in, *out;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: imspline_construct <in> <out> (x/y)\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  // XXX move this to gfits_create_matrix
+  free (out[0].matrix.buffer);
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    sprintf (out[0].file, "*%s", in[0].file);
+  } else {
+    sprintf (out[0].file, "%s", in[0].file);
+  }
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  gfits_copy_matrix_info (&in[0].matrix, &out[0].matrix);
+  gfits_copy_header (&in[0].header, &out[0].header);
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+
+  // int xdir = FALSE;
+  // if (!strcmp (argv[3], "x")) xdir = TRUE; 
+  /* ideally, the resulting image should carry this info (in header?) */
+
+  Nx = in[0].matrix.Naxis[0];
+  Ny = in[0].matrix.Naxis[1];
+
+  ALLOCATE (Ty2, float, Ny);
+  ALLOCATE (Ty, float, Ny);
+  ALLOCATE (Tx, float, Ny);
+
+  /** for now only perform the operation for the ydir splines */
+
+  /* construct coordinate vector */
+  for (j = 0; j < Ny; j++) { Tx[j] = j; }
+  
+  for (i = 0; i < Nx; i++) {
+    
+    /* construct temp vector with values to spline */
+    V = (float *)(in[0].matrix.buffer) + i;
+    for (j = 0; j < Ny; j++, V+=Nx) {
+      Ty[j] = *V;
+    }
+  
+    spline_construct_flt (Tx, Ty, Ny, Ty2);
+  
+    /* copy derivatives to output buffer */
+    V = (float *)(out[0].matrix.buffer) + i;
+    for (j = 0; j < Ny; j++, V+=Nx) {
+      *V = Ty2[j];
+    }
+  }
+
+  free (Tx);
+  free (Ty);
+  free (Ty2);
+  
+  return (TRUE);
+
+}
Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 34584)
@@ -102,6 +102,7 @@
 int shift            PROTO((int, char **));
 int sort_vectors     PROTO((int, char **));
-int spline_apply_cmd PROTO((int, char **));
-int spline_construct_cmd PROTO((int, char **));
+int spline_command   PROTO((int, char **));
+int imspline_apply   PROTO((int, char **));
+int imspline_construct PROTO((int, char **));
 int stats            PROTO((int, char **));
 int imstats          PROTO((int, char **));
@@ -254,6 +255,7 @@
   {1, "shift",        shift,            "shift data in an image"},
   {1, "sort",         sort_vectors,     "sort list of vectors"},
-  {1, "spline.apply", spline_apply_cmd, "apply spline fit to generate an image"},
-  {1, "spline.const", spline_construct_cmd, "create spline 2nd deriv. terms"},
+  {1, "spline",       spline_command,   "shift data in an image"},
+  {1, "imspline.apply", imspline_apply, "apply spline fit to generate an image"},
+  {1, "imspline.const", imspline_construct, "create spline 2nd deriv. terms"},
   {1, "stats",        imstats,          "statistics on a portion of an image"},
   {1, "style",        style,            "set the style for graph plots"},
Index: trunk/Ohana/src/opihi/cmd.data/plot.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/plot.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/plot.c	(revision 34584)
@@ -3,5 +3,6 @@
 int plot (int argc, char **argv) {
   
-  int kapa, N, Npts;
+  char *out;
+  int kapa, N, Npts, valid, size, i;
   Graphdata graphmode;
   Vector *xvec, *yvec, *dxmvec, *dxpvec, *dymvec, *dypvec;
@@ -32,7 +33,27 @@
   }
 
-  if (argc != 3) {
+  valid  = (argc == 3);
+  valid |= (argc > 4) && !strcmp (argv[3], "where");
+  if (!valid) {
     gprint (GP_ERR, "USAGE: plot <x> <y> [style]\n");
+    gprint (GP_ERR, "   OR: plot <x> <y> [style] where (condition)\n");
     return (FALSE);
+  }
+
+  // tvec is used for logical test (truth vector)
+  Vector *tvec = NULL;
+  char *mask = NULL;
+  if (argc > 4) {
+    out = dvomath (argc - 4, &argv[4], &size, 1);
+    if (out == NULL) {
+      print_error ();
+      return FALSE;
+    }
+    if ((tvec = SelectVector (out, OLDVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, " invalid logic result\n");
+      DeleteNamedVector (out);
+      free (out);
+      return (FALSE);
+    }
   }
 
@@ -53,4 +74,8 @@
     return (FALSE);
   }
+  if (tvec && tvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "logic test vector not the same length as data vectors\n");
+    return (FALSE);
+  }
   if (dypvec && (dypvec->Nelements != xvec->Nelements)) goto mismatch;
   if (dymvec && (dymvec->Nelements != xvec->Nelements)) goto mismatch;
@@ -59,17 +84,39 @@
 
   Npts = xvec[0].Nelements;
-  if (Npts == 0) return (TRUE);
+  if (Npts == 0) {
+    if (tvec) DeleteVector (tvec);
+    return (TRUE);
+  }
+
+  if (tvec) {
+    Npts = 0;
+    ALLOCATE (mask, char, tvec->Nelements);
+    for (i = 0; i < tvec->Nelements; i++) {
+      mask[i] = (tvec->type == OPIHI_FLT) ? (tvec->elements.Flt[i] == 0.0) : (tvec->elements.Int[i] == 0.0);
+      if (!mask[i]) Npts ++;
+    }
+    if (Npts == 0) {
+      DeleteVector (tvec);
+      free (mask);
+      return TRUE;
+    }
+  }
 
   if (!KapaPrepPlot (kapa, Npts, &graphmode)) return (FALSE);
   
-  PlotVectorSingle (kapa, xvec, "x");
-  PlotVectorSingle (kapa, yvec, "y");
+  PlotVectorSingle (kapa, xvec, mask, "x");
+  PlotVectorSingle (kapa, yvec, mask, "y");
   if (graphmode.etype & 0x01) {
-    PlotVectorSingle (kapa, dymvec, "dym");
-    PlotVectorSingle (kapa, dypvec, "dyp");
+    PlotVectorSingle (kapa, dymvec, mask, "dym");
+    PlotVectorSingle (kapa, dypvec, mask, "dyp");
   }
   if (graphmode.etype & 0x02) {
-    PlotVectorSingle (kapa, dxmvec, "dxm");
-    PlotVectorSingle (kapa, dxpvec, "dxp");
+    PlotVectorSingle (kapa, dxmvec, mask, "dxm");
+    PlotVectorSingle (kapa, dxpvec, mask, "dxp");
+  }
+
+  if (tvec) {
+    free (mask);
+    DeleteVector (tvec);
   }
   return (TRUE);
Index: trunk/Ohana/src/opihi/cmd.data/spline.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/spline.c	(revision 34584)
+++ trunk/Ohana/src/opihi/cmd.data/spline.c	(revision 34584)
@@ -0,0 +1,54 @@
+# include "data.h"
+
+int spline_list (int argc, char **argv);
+int spline_create (int argc, char **argv);
+int spline_apply (int argc, char **argv);
+int spline_load (int argc, char **argv);
+int spline_save (int argc, char **argv);
+int spline_delete (int argc, char **argv);
+int spline_getspline (int argc, char **argv);
+
+static Command spline_commands[] = {
+  {1, "list",       spline_list,       "list splines"},
+  {1, "create",     spline_create,     "create a spline"},
+  {1, "apply",      spline_apply,      "apply a spline"},
+  {1, "load",       spline_load,       "write a spline to a FITS file"},
+  {1, "save",       spline_save,       "read a spline from a FITS file"},
+  {1, "delete",     spline_delete,     "delete a spline"},
+};
+
+int spline_command (int argc, char **argv) {
+
+  int i, N, status;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: spline (command)\n");
+    gprint (GP_ERR, "    spline list                                    : list splines\n");
+    gprint (GP_ERR, "    spline create   (spline)                       : create a spline\n");
+    gprint (GP_ERR, "    spline delete   (spline)                       : delete a spline\n");
+    return (FALSE);
+  }
+
+  N = sizeof (spline_commands) / sizeof (Command);
+
+  /* find the spline sub-command which matches */
+  for (i = 0; i < N; i++) {
+    if (!strcmp (spline_commands[i].name, argv[1])) {
+      status = (*spline_commands[i].func) (argc - 1, argv + 1);
+      return (status);
+    }
+  }
+
+  gprint (GP_ERR, "unknown spline command %s\n", argv[1]);
+  return (FALSE);
+}
+
+/* spline is called with the command "spline".  
+   the command line word "spline" is meant to be followed the one of several 
+   possible options:
+   
+   spline create
+   spline delete
+   spline list
+
+*/
Index: trunk/Ohana/src/opihi/cmd.data/spline_apply.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/spline_apply.c	(revision 34461)
+++ 	(revision )
@@ -1,98 +1,0 @@
-# include "data.h"
-
-// need to rename this as an image function
-int spline_apply_cmd (int argc, char **argv) {
-  
-  int i, j, I, J;
-  int nx, ny, Nx, Ny;
-  float rx, ry, x, y;
-  float *Tx1, *Tx2, *Txc, *Ty1, *Ty2, *Tyc, *V, *V1, *V2;
-  Buffer *out, *y1, *y2;
-
-  if (argc != 7) {
-    gprint (GP_ERR, "USAGE: spline_apply <Y> <Y2> <out> (x/y) Nx Ny\n");
-    return (FALSE);
-  }
-
-  if ((y1  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
-  if ((y2  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
-  if ((out = SelectBuffer (argv[3], ANYBUFFER, TRUE)) == NULL) return (FALSE);
-
-  // xdir = FALSE;
-  // if (!strcmp (argv[4], "x")) xdir = TRUE; 
-
-  nx = atoi (argv[5]);
-  ny = atoi (argv[6]);
-
-  Nx = y1[0].matrix.Naxis[0];
-  Ny = y1[0].matrix.Naxis[1];
-
-  rx = Nx / (float) nx;
-  ry = Ny / (float) ny;
-
-  /* create an output matrix buffer with desired nx, ny */
-  gfits_free_matrix (&out[0].matrix);
-  gfits_free_header (&out[0].header);
-
-  out[0].bitpix = y1[0].bitpix;
-  out[0].unsign = y1[0].unsign;
-  out[0].bscale = y1[0].bscale;
-  out[0].bzero  = y1[0].bzero;
-  gfits_copy_header (&y1[0].header, &out[0].header);
-  gfits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
-  gfits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
-
-  out[0].header.Naxis[0] = nx;
-  out[0].header.Naxis[1] = ny;
-  gfits_create_matrix (&out[0].header, &out[0].matrix);
-  if ((y1[0].file[0] != '*') && (y1[0].file[0] != '(')) {
-    sprintf (out[0].file, "*%s", y1[0].file);
-  } else {
-    sprintf (out[0].file, "%s", y1[0].file);
-  }
-
-  ALLOCATE (Ty2, float, Ny);
-  ALLOCATE (Ty1, float, Ny);
-  ALLOCATE (Tyc, float, Ny);
-  for (i = 0; i < Ny; i++) { Tyc[i] = i; }
-
-  ALLOCATE (Tx1, float, Nx);
-  ALLOCATE (Tx2, float, Nx);
-  ALLOCATE (Txc, float, Nx);
-  for (i = 0; i < Nx; i++) { Txc[i] = i; }
-
-  V = (float *)(out[0].matrix.buffer);
-
-  for (J = 0; J < ny; J++) {
-    y = J * ry;
-
-    /* construct spline for each element in this row */
-    for (i = 0; i < Nx; i++) {
-      V1 = (float *)(y1[0].matrix.buffer) + i;
-      V2 = (float *)(y2[0].matrix.buffer) + i;
-      for (j = 0; j < Ny; j++, V1+=Nx, V2+=Nx) {
-	Ty1[j] = *V1;
-	Ty2[j] = *V2;
-      }
-      Tx1[i] = spline_apply (Tyc, Ty1, Ty2, Ny, y);
-    }
-    spline_construct (Txc, Tx1, Nx, Tx2);
-
-    /* apply x-dir spline to new image */
-    for (I = 0; I < nx; I++, V++) {
-      x = I * rx;
-      *V = spline_apply (Txc, Tx1, Tx2, Nx, x);
-    }
-  }
-
-  free (Ty1);
-  free (Ty2);
-  free (Tyc);
-  
-  free (Tx1);
-  free (Tx2);
-  free (Txc);
-  
-  return (TRUE);
-
-}
Index: trunk/Ohana/src/opihi/cmd.data/spline_commands.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/spline_commands.c	(revision 34584)
+++ trunk/Ohana/src/opihi/cmd.data/spline_commands.c	(revision 34584)
@@ -0,0 +1,148 @@
+# include "data.h"
+
+int spline_list (int argc, char **argv) {
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: spline list\n");
+    return FALSE;
+  }
+
+  ListSplines();
+  return TRUE;
+}
+
+int spline_create (int argc, char **argv) {
+
+  int i;
+  Vector *xvec, *yvec;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: spline create (name) (Xknots) (Yknots)\n");
+    return FALSE;
+  }
+
+  if ((xvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec->Nelements != yvec->Nelements) {
+    gprint (GP_ERR, "x and y vectors must be the same length\n");
+    return FALSE;
+  }
+
+  Spline *myspline = CreateSpline (argv[1], xvec->Nelements);
+
+  for (i = 0; i < xvec->Nelements; i++) {
+    myspline->xk[i] = xvec->elements.Flt[i];
+    myspline->yk[i] = yvec->elements.Flt[i];
+  }    
+
+  spline_construct_dbl (myspline->xk, myspline->yk, myspline->Nknots, myspline->y2);
+  return TRUE;
+}
+
+int spline_apply (int argc, char **argv) {
+
+  int i;
+  Vector *xvec, *yvec;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: spline apply (name) (Xpoints) (Ypoints)\n");
+    return FALSE;
+  }
+
+  Spline *myspline = FindSpline (argv[1]);
+  if (!myspline) {
+    gprint (GP_ERR, "spline %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  ResetVector (yvec, OPIHI_FLT, xvec->Nelements);
+
+  for (i = 0; i < xvec->Nelements; i++) {
+    opihi_flt value = spline_apply_dbl (myspline->xk, myspline->yk, myspline->y2, myspline->Nknots, xvec->elements.Flt[i]);
+    yvec->elements.Flt[i] = value;
+  }    
+
+  return TRUE;
+}
+
+int spline_save (int argc, char **argv) {
+
+  int N;
+
+  int APPEND = FALSE;
+  if ((N = get_argument (argc, argv, "-append"))) {
+    APPEND = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: spline save (name) (filename) [-append]\n");
+    return FALSE;
+  }
+
+  if (!SaveSpline(argv[2], argv[1], APPEND)) {
+    gprint (GP_ERR, "failed to save spline %s\n", argv[1]);
+    return (FALSE);
+  }
+  return TRUE;
+}
+
+int spline_load (int argc, char **argv) {
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: spline load (name) (filename)\n");
+    return FALSE;
+  }
+
+  if (!LoadSpline(argv[2], argv[1])) {
+    gprint (GP_ERR, "failed to load spline %s\n", argv[1]);
+    return (FALSE);
+  }
+  return TRUE;
+}
+
+int spline_delete (int argc, char **argv) {
+
+  int status;
+  Spline *spline;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: spline delete (spline)\n");
+    return FALSE;
+  }
+
+  spline = FindSpline (argv[1]);
+  if (spline == NULL) {
+    gprint (GP_ERR, "spline %s not found\n", argv[1]);
+    return FALSE;
+  }
+
+  status = DeleteSpline (spline);
+  if (!status) abort ();
+  return TRUE;
+}
+
+/* 
+int spline_listspline (int argc, char **argv) {
+
+  Spline *spline;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: spline listspline (spline)\n");
+    return FALSE;
+  }
+
+  spline = FindSpline (argv[1]);
+  if (spline == NULL) {
+    gprint (GP_ERR, "spline %s not found\n", argv[1]);
+    return FALSE;
+  }
+
+  ListPages (spline);
+  return TRUE;
+}
+*/
+
Index: trunk/Ohana/src/opihi/cmd.data/spline_construct.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/spline_construct.c	(revision 34461)
+++ 	(revision )
@@ -1,72 +1,0 @@
-# include "data.h"
-
-// need to rename this as an image function
-int spline_construct_cmd (int argc, char **argv) {
-  
-  int i, j, Nx, Ny;
-  float *Tx, *Ty, *Ty2, *V;
-  Buffer *in, *out;
-
-  if (argc != 4) {
-    gprint (GP_ERR, "USAGE: spline_construct <in> <out> (x/y)\n");
-    return (FALSE);
-  }
-
-  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
-  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
-
-  // XXX move this to gfits_create_matrix
-  free (out[0].matrix.buffer);
-  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
-    sprintf (out[0].file, "*%s", in[0].file);
-  } else {
-    sprintf (out[0].file, "%s", in[0].file);
-  }
-  out[0].bitpix = in[0].bitpix;
-  out[0].unsign = in[0].unsign;
-  out[0].bscale = in[0].bscale;
-  out[0].bzero  = in[0].bzero;
-  gfits_copy_matrix_info (&in[0].matrix, &out[0].matrix);
-  gfits_copy_header (&in[0].header, &out[0].header);
-  gfits_create_matrix (&out[0].header, &out[0].matrix);
-
-  // int xdir = FALSE;
-  // if (!strcmp (argv[3], "x")) xdir = TRUE; 
-  /* ideally, the resulting image should carry this info (in header?) */
-
-  Nx = in[0].matrix.Naxis[0];
-  Ny = in[0].matrix.Naxis[1];
-
-  ALLOCATE (Ty2, float, Ny);
-  ALLOCATE (Ty, float, Ny);
-  ALLOCATE (Tx, float, Ny);
-
-  /** for now only perform the operation for the ydir splines */
-
-  /* construct coordinate vector */
-  for (j = 0; j < Ny; j++) { Tx[j] = j; }
-  
-  for (i = 0; i < Nx; i++) {
-    
-    /* construct temp vector with values to spline */
-    V = (float *)(in[0].matrix.buffer) + i;
-    for (j = 0; j < Ny; j++, V+=Nx) {
-      Ty[j] = *V;
-    }
-  
-    spline_construct (Tx, Ty, Ny, Ty2);
-  
-    /* copy derivatives to output buffer */
-    V = (float *)(out[0].matrix.buffer) + i;
-    for (j = 0; j < Ny; j++, V+=Nx) {
-      *V = Ty2[j];
-    }
-  }
-
-  free (Tx);
-  free (Ty);
-  free (Ty2);
-  
-  return (TRUE);
-
-}
Index: trunk/Ohana/src/opihi/cmd.data/write_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 34584)
@@ -99,5 +99,5 @@
   }
 
-  /* open file for outuput */
+  /* open file for output */
   if (append) {
     f = fopen (argv[1], "a");
Index: trunk/Ohana/src/opihi/cmd.data/zplot.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/zplot.c	(revision 34461)
+++ trunk/Ohana/src/opihi/cmd.data/zplot.c	(revision 34584)
@@ -3,5 +3,6 @@
 int zplot (int argc, char **argv) {
   
-  int i, kapa;
+  char *outname;
+  int i, kapa, valid, size;
   opihi_flt *out;
   double min, range;
@@ -11,6 +12,9 @@
   if (!style_args (&graphmode, &argc, argv, &kapa)) return (FALSE);
 
-  if (argc != 6) {
+  valid  = (argc == 6);
+  valid |= (argc > 7) && !strcmp (argv[6], "where");
+  if (!valid) {
     gprint (GP_ERR, "USAGE: zplot <x> <y> <z> min max\n");
+    gprint (GP_ERR, "   OR: zplot <x> <y> <z> min max where (condition)\n");
     return (FALSE);
   }
@@ -18,4 +22,21 @@
   min = atof(argv[4]);
   range = atof(argv[5]) - min;
+
+  // tvec is used for logical test (truth vector)
+  Vector *tvec = NULL;
+  char *mask = NULL;
+  if (argc > 7) {
+    outname = dvomath (argc - 7, &argv[7], &size, 1);
+    if (outname == NULL) {
+      print_error ();
+      return FALSE;
+    }
+    if ((tvec = SelectVector (outname, OLDVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, " invalid logic result\n");
+      DeleteNamedVector (outname);
+      free (outname);
+      return (FALSE);
+    }
+  }
 
   /* find vectors */
@@ -29,4 +50,8 @@
   if (xvec[0].Nelements != zvec[0].Nelements) {
     gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[3]);
+    return (FALSE);
+  }
+  if (tvec && tvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "logic test vector not the same length as data vectors\n");
     return (FALSE);
   }
@@ -46,11 +71,20 @@
   }
 
+  if (tvec) {
+    ALLOCATE (mask, char, tvec->Nelements);
+    for (i = 0; i < tvec->Nelements; i++) {
+      mask[i] = (tvec->type == OPIHI_FLT) ? (tvec->elements.Flt[i] == 0.0) : (tvec->elements.Int[i] == 0.0);
+    }
+  }
+
   /* point size determined by Zvec */
   graphmode.style = 2; /* plot points */
   graphmode.size = -1; /* point size determined by Zvec */
   graphmode.etype = 0; /* no errorbars */
-  PlotVectorTriplet (kapa, xvec, yvec, &Zvec, &graphmode);
+  PlotVectorTriplet (kapa, xvec, yvec, &Zvec, mask, &graphmode);
 
   free (Zvec.elements.Ptr);
+  if (mask) free (mask);
+  DeleteNamedVector (outname);
 
   return (TRUE);
@@ -60,5 +94,6 @@
 int zcplot (int argc, char **argv) {
   
-  int i, kapa;
+  char *outname;
+  int i, kapa, valid, size;
   opihi_flt *out;
   double min, range;
@@ -68,6 +103,9 @@
   if (!style_args (&graphmode, &argc, argv, &kapa)) return (FALSE);
 
-  if (argc != 6) {
-    gprint (GP_ERR, "USAGE: zplot <x> <y> <z> min max\n");
+  valid  = (argc == 6);
+  valid |= (argc > 7) && !strcmp (argv[6], "where");
+  if (!valid) {
+    gprint (GP_ERR, "USAGE: zcplot <x> <y> <z> min max\n");
+    gprint (GP_ERR, "   OR: zcplot <x> <y> <z> min max where (condition)\n");
     return (FALSE);
   }
@@ -75,4 +113,21 @@
   min = atof(argv[4]);
   range = atof(argv[5]) - min;
+
+  // tvec is used for logical test (truth vector)
+  Vector *tvec = NULL;
+  char *mask = NULL;
+  if (argc > 7) {
+    outname = dvomath (argc - 7, &argv[7], &size, 1);
+    if (outname == NULL) {
+      print_error ();
+      return FALSE;
+    }
+    if ((tvec = SelectVector (outname, OLDVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, " invalid logic result\n");
+      DeleteNamedVector (outname);
+      free (outname);
+      return (FALSE);
+    }
+  }
 
   /* find vectors */
@@ -86,4 +141,8 @@
   if (xvec[0].Nelements != zvec[0].Nelements) {
     gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[3]);
+    return (FALSE);
+  }
+  if (tvec && tvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "logic test vector not the same length as data vectors\n");
     return (FALSE);
   }
@@ -103,11 +162,20 @@
   }
 
+  if (tvec) {
+    ALLOCATE (mask, char, tvec->Nelements);
+    for (i = 0; i < tvec->Nelements; i++) {
+      mask[i] = (tvec->type == OPIHI_FLT) ? (tvec->elements.Flt[i] == 0.0) : (tvec->elements.Int[i] == 0.0);
+    }
+  }
+
   /* point size determined by Zvec */
   graphmode.style = 2; /* plot points */
   graphmode.color = -1; /* point color determined by Zvec */
   graphmode.etype = 0; /* no errorbars */
-  PlotVectorTriplet (kapa, xvec, yvec, &Zvec, &graphmode);
+  PlotVectorTriplet (kapa, xvec, yvec, &Zvec, mask, &graphmode);
 
   free (Zvec.elements.Ptr);
+  if (mask) free (mask);
+  DeleteNamedVector (outname);
 
   return (TRUE);
