Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 31635)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 31667)
@@ -137,4 +137,5 @@
 int zap              PROTO((int, char **));
 int zplot            PROTO((int, char **));
+int zcplot            PROTO((int, char **));
 
 static Command cmds[] = {  
@@ -284,4 +285,5 @@
   {1, "zap",          zap,              "assign values to pixel regions"},
   {1, "zplot",        zplot,            "plot x y with size scaled by z"},
+  {1, "zcplot",       zcplot,           "plot x y with color scaled by z"},
 }; 
 
Index: trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 31635)
+++ trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 31667)
@@ -2,5 +2,5 @@
 
 FILE *f = (FILE *) NULL;
-char filename[256];
+char filename[2048];
 
 int datafile (int argc, char **argv) {
@@ -23,5 +23,5 @@
 int read_vectors (int argc, char **argv) {
   
-  int i, j, Nskip, Nvec, *col, done, status;
+  int i, j, Nskip, Nvec, *col, done, status, IsCSV;
   int Nbytes, nbytes, Nstart, NELEM, N, nread;
   char *colstr, *c0, *c1, *buffer, *extname;
@@ -47,4 +47,10 @@
   }
 
+  IsCSV = FALSE;
+  if ((N = get_argument (argc, argv, "-csv"))) {
+    remove_argument (N, &argc, argv);
+    IsCSV = TRUE;
+  }
+
   if ((argc < 3) || !(argc % 2)) {
     gprint (GP_ERR, "USAGE: read name N name N ...\n");
@@ -58,4 +64,9 @@
   }
   fseeko (f, 0LL, SEEK_SET);
+
+//  if (IsCSV) {
+//    status = read_vectors_csv (argc, argv, Nskip, f);
+//    return status;
+//  }
 
   Nvec = (argc - 1) / 2;
@@ -73,12 +84,28 @@
     colstr = argv[2*i+2];
     for (j = 0; j < strlen (colstr); j++) {
-      if (!isdigit(colstr[j])) {
-	gprint (GP_ERR, "USAGE: read name N name N ...\n");
-	free (vec);
-	free (col);
-	return (FALSE);    
-      }
-    }
-    col[i] = atof (colstr);
+      if (isdigit(colstr[j])) {
+	col[i] = atof (colstr);
+	continue;
+      }
+      // allow 'excel' columns names of the form A-Z, AA-AZ, BA-BZ, .. ZA-ZZ
+      if (strlen(colstr) >= 3) goto bad_colname;
+      if (colstr[0] < 'A') goto bad_colname;
+      if (colstr[0] > 'Z') goto bad_colname;
+      if (colstr[1] && colstr[1] < 'A') goto bad_colname;
+      if (colstr[1] && colstr[1] > 'Z') goto bad_colname;
+
+      col[i] = colstr[0] - 'A' + 1;
+      if (colstr[1]) {
+	col[i] *= 26;
+	col[i] += colstr[1] - 'A' + 1;
+      }
+      continue;
+
+    bad_colname:
+      gprint (GP_ERR, "USAGE: read name N name N ...\n");
+      free (vec);
+      free (col);
+      return (FALSE);    
+    }
   }
 
@@ -94,4 +121,7 @@
     scan_line (f, buffer);
   }
+
+  int Nfield = 0;
+  int Nline = 0;
 
   Nstart = 0;
@@ -122,10 +152,22 @@
       if ((*c0 != '#') && (*c0 != '!')) {
 	for (i = 0; (i < Nvec) && status; i++) {
-	  status = dparse (&value, col[i], c0);
+	  if (IsCSV) {
+	    status = dparse_csv (&value, col[i], c0);
+	  } else {
+	    status = dparse (&value, col[i], c0);
+	  }
 	  vec[i][0].elements.Flt[N] = value;
+	  if (status) {
+	      Nfield ++;
+	  }
 	  if (!status) vec[i][0].elements.Flt[N] = NAN;
 	}
 	if (status) N++;
       }
+      Nline ++;
+      if (c1) {
+	  // fprintf (stderr, "line %d, chars %ld, fields %d\n", Nline, (c1 - c0), Nfield);
+      }
+      Nfield = 0;
       c0 = c1 + 1;
       if (N == NELEM) {
@@ -341,2 +383,104 @@
   return (TRUE);
 }
+
+# if (0)
+int read_vectors_csv (int argc, char **argv, int Nskip, FILE *f) {
+  
+  int i, j, Nvec, *col, done, status;
+  int Nbytes, nbytes, Nstart, NELEM, N, nread;
+  char *colstr, *c0, *c1, *buffer, *extname;
+  double value;
+  Vector **vec;
+
+  Nvec = (argc - 1) / 2;
+  ALLOCATE (vec, Vector *, Nvec);
+  ALLOCATE (col, int, Nvec);
+
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[2*i + 1], ANYVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, "USAGE: read name N name N ...\n");
+      free (vec);
+      free (col);
+      return (FALSE);    
+    }
+    // XXX we could allow flags (eg, N.i) to specify INT vs FLT types vectors...
+    colstr = argv[2*i+2];
+    for (j = 0; j < strlen (colstr); j++) {
+      if (!isdigit(colstr[j])) {
+	gprint (GP_ERR, "USAGE: read name N name N ...\n");
+	free (vec);
+	free (col);
+	return (FALSE);    
+      }
+    }
+    col[i] = atof (colstr);
+  }
+
+  // currently, all read vectors are forced to be type FLT
+  NELEM = 1000;
+  for (i = 0; i < Nvec; i++) {
+    ResetVector (vec[i], OPIHI_FLT, NELEM);
+  }
+  
+  ALLOCATE (buffer, char, 0x10001);
+  bzero (buffer, 0x10001);
+  for (i = 0; i < Nskip; i++) {
+    scan_line (f, buffer);
+  }
+
+  Nstart = 0;
+  N = 0;
+  done = FALSE;
+  while (!done) {
+    Nbytes = 0x10000 - Nstart;
+    bzero (&buffer[Nstart], Nbytes);
+    nread = fread (&buffer[Nstart], 1, Nbytes, f);
+    if (ferror (f)) {
+      perror ("error reading data file");
+      break;
+    }
+    if (nread == 0) break;
+    nbytes = nread + Nstart;
+    
+    status = TRUE;
+    c0 = buffer; 
+    while (status) {
+      c1 = strchr (c0, '\n');
+      if (c1 == (char *) NULL) {
+	Nstart = strlen (c0);
+	memmove (buffer, c0, Nstart);
+	status = FALSE;
+      } else {
+	*c1 = 0;
+      }      
+      if ((*c0 != '#') && (*c0 != '!')) {
+	for (i = 0; (i < Nvec) && status; i++) {
+	  status = dparse_csv (&value, col[i], c0);
+	  vec[i][0].elements.Flt[N] = value;
+	  if (!status) vec[i][0].elements.Flt[N] = NAN;
+	}
+	if (status) N++;
+      }
+      c0 = c1 + 1;
+      if (N == NELEM) {
+	NELEM += 1000;
+	for (i = 0; i < Nvec; i++) {
+	  REALLOCATE (vec[i][0].elements.Flt, opihi_flt, NELEM);
+	}
+      }
+	
+    }
+  }
+  for (i = 0; i < Nvec; i++) {
+    REALLOCATE (vec[i][0].elements.Flt, opihi_flt, MAX (N,1));
+    vec[i][0].Nelements = N;
+  }
+  
+  free (vec);
+  free (col);
+  free (buffer);
+  return (TRUE);
+
+}
+
+# endif
Index: trunk/Ohana/src/opihi/cmd.data/test/csv.dat
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/test/csv.dat	(revision 31667)
+++ trunk/Ohana/src/opihi/cmd.data/test/csv.dat	(revision 31667)
@@ -0,0 +1,3 @@
+word,1,5,10
+foo,2,4,8
+sam,3,3,6
Index: trunk/Ohana/src/opihi/cmd.data/test/csv1.dat
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/test/csv1.dat	(revision 31667)
+++ trunk/Ohana/src/opihi/cmd.data/test/csv1.dat	(revision 31667)
@@ -0,0 +1,3 @@
+word,1,5,10
+foo,,4,8
+sam,3,,6
Index: trunk/Ohana/src/opihi/cmd.data/tvcolors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 31635)
+++ trunk/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 31667)
@@ -5,5 +5,5 @@
   int N, kapa;
   char *name;
-  KapaImageData data;
+  // KapaImageData data;
 
   name = NULL;
@@ -13,5 +13,5 @@
     remove_argument (N, &argc, argv);
   }
-  if (!GetImage (&data, &kapa, name)) return (FALSE);
+  if (!GetGraph (NULL, &kapa, name)) return (FALSE);
   FREE (name);
 
Index: trunk/Ohana/src/opihi/cmd.data/zplot.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/zplot.c	(revision 31635)
+++ trunk/Ohana/src/opihi/cmd.data/zplot.c	(revision 31667)
@@ -58,3 +58,60 @@
 }
 
+int zcplot (int argc, char **argv) {
+  
+  int i, kapa;
+  opihi_flt *out;
+  double min, range;
+  Graphdata graphmode;
+  Vector *xvec, *yvec, *zvec, Zvec;
 
+  if (!style_args (&graphmode, &argc, argv, &kapa)) return (FALSE);
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: zplot <x> <y> <z> min max\n");
+    return (FALSE);
+  }
+
+  min = atof(argv[4]);
+  range = atof(argv[5]) - min;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  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);
+  }
+  SetVector (&Zvec, OPIHI_FLT, zvec[0].Nelements);
+  out = Zvec.elements.Flt;
+ 
+  if (zvec[0].type == OPIHI_FLT) {
+    opihi_flt *in = zvec[0].elements.Flt;
+    for (i = 0; i < Zvec.Nelements; i++, in++, out++) {
+      *out = MIN (1.0, MAX (0.01, (*in - min) / range));
+    }
+  } else {
+    opihi_int *in = zvec[0].elements.Int;
+    for (i = 0; i < Zvec.Nelements; i++, in++, out++) {
+      *out = MIN (1.0, MAX (0.01, (*in - min) / range));
+    }
+  }
+
+  /* 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);
+
+  free (Zvec.elements.Ptr);
+
+  return (TRUE);
+
+}
+
+
