Index: trunk/Ohana/src/opihi/cmd.data/box.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/box.c	(revision 38553)
+++ trunk/Ohana/src/opihi/cmd.data/box.c	(revision 38986)
@@ -48,5 +48,5 @@
     if (strlen (graphmode.ticks) != 4) { goto usage; }
     for (i = 0; i < strlen (graphmode.ticks); i++) {
-      if ((graphmode.ticks[i] != '0') && (graphmode.ticks[i] != '1') && (graphmode.ticks[i] != '2')) { goto usage; }
+      if ((graphmode.ticks[i] != '0') && (graphmode.ticks[i] != '1') && (graphmode.ticks[i] != '2') && (graphmode.ticks[i] != '3')) { goto usage; }
     }
   }
@@ -139,4 +139,62 @@
     remove_argument (N, &argc, argv);
     graphmode.padYp = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-fminor"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fMinorXm = atof(argv[N]);
+    graphmode.fMinorXp = atof(argv[N]);
+    graphmode.fMinorYm = atof(argv[N]);
+    graphmode.fMinorYp = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-xfminor"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fMinorXm = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+xfminor"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fMinorXp = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-yfminor"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fMinorYm = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+yfminor"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fMinorYp = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-flabel"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fLabelRangeXm = atof(argv[N]);
+    graphmode.fLabelRangeXp = atof(argv[N]);
+    graphmode.fLabelRangeYm = atof(argv[N]);
+    graphmode.fLabelRangeYp = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-xflabel"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fLabelRangeXm = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+xflabel"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fLabelRangeXp = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-yflabel"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fLabelRangeYm = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+yflabel"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.fLabelRangeYp = atof(argv[N]);
     remove_argument (N, &argc, argv);
   }
@@ -174,4 +232,12 @@
   gprint (GP_ERR, "         alternatively, set each axis independently with:\n");
   gprint (GP_ERR, "        -xpad, -ypad, +xpad, +ypad\n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  -fminor : set the number of minor ticks per major (all axes)\n");
+  gprint (GP_ERR, "         alternatively, set each axis independently with:\n");
+  gprint (GP_ERR, "        -xfminor, -yfminor, +xfminor, +yfminor\n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  -flabel : set the fraction of axis over which major ticks have labels (all axes)\n");
+  gprint (GP_ERR, "         alternatively, set each axis independently with:\n");
+  gprint (GP_ERR, "        -xflabel, -yflabel, +xflabel, +yflabel\n");
 
   return (FALSE);
Index: trunk/Ohana/src/opihi/cmd.data/device.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/device.c	(revision 38553)
+++ trunk/Ohana/src/opihi/cmd.data/device.c	(revision 38986)
@@ -6,4 +6,10 @@
   char *name;;
   /* set / get current graphics device */
+
+  int QUIET = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    remove_argument (N, &argc, argv);
+    QUIET = TRUE;
+  }
 
   name = NULL;
@@ -23,5 +29,5 @@
     if (!GetGraph (NULL, &kapa, name)) return (FALSE);
   }
-  gprint (GP_ERR, "kapa %s\n", name); 
+  if (!QUIET) gprint (GP_ERR, "kapa %s\n", name); 
 
   return (TRUE);
Index: trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 38553)
+++ trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 38986)
@@ -511,5 +511,6 @@
     if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension %d\n", Nextend);
   } else {
-    if (!gfits_fread_ftable_range (f, padIfShort, &table, start, Nrows)) ESCAPE ("error reading table for extension %d\n", Nextend);
+    // arg3 (FALSE) : seek to this segment start
+    if (!gfits_fread_ftable_range (f, padIfShort, FALSE, &table, start, Nrows)) ESCAPE ("error reading table for extension %d\n", Nextend);
   }
 
Index: trunk/Ohana/src/opihi/cmd.data/uniq.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/uniq.c	(revision 38553)
+++ trunk/Ohana/src/opihi/cmd.data/uniq.c	(revision 38986)
@@ -1,11 +1,24 @@
 # include "data.h"
+// NOTE: if there are only a few uniq values, the old algorithm is not bad.  
+// for 10000 uniq values, 30M points take ~20sec in the new algorithm, 
+// 3M points takess 45 sec in the old method.
 
 int uniq (int argc, char **argv) {
   
-  int Nnew, i, j, found;
+  int Nnew, i, N;
   Vector *ivec, *ovec;
 
+  Vector *cvec = NULL;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    if ((cvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, "invalid vector %s\n", argv[N]);
+      return FALSE;
+    }
+    remove_argument (N, &argc, argv);
+  }
+
   if (argc != 3) {
-    gprint (GP_ERR, "USAGE: uniq (in) (out)\n");
+    gprint (GP_ERR, "USAGE: uniq (in) (out) -c count\n");
     return (FALSE);
   }
@@ -16,37 +29,69 @@
   /* allocate the maximum possible needed */
   ResetVector (ovec, ivec->type, ivec->Nelements);
+  if (cvec) {
+    ResetVector (cvec, OPIHI_INT, ivec->Nelements);
+  }
 
   Nnew = 0;
 
   if (ivec->type == OPIHI_FLT) {
-    opihi_flt *v1 = ivec[0].elements.Flt;
-    for (i = 0; i < ivec[0].Nelements; i++, v1++) {
-      opihi_flt *v2 = ovec[0].elements.Flt;
-      found = FALSE;
-      for (j = 0; !found && (j < Nnew); j++, v2++) {
-	if (*v1 == *v2) found = TRUE;
+    // copy the input data to a temporary array to avoid damaging it with sort
+    opihi_flt *indata = NULL;
+    ALLOCATE (indata, opihi_flt, ivec[0].Nelements);
+    memcpy (indata, ivec->elements.Flt, ivec[0].Nelements*sizeof(opihi_flt));
+
+    dsort (indata, ivec->Nelements);
+
+    Nnew = 0;
+    opihi_flt *vtgt = ovec[0].elements.Flt;
+
+    opihi_flt *vsrc = indata;
+
+    for (i = 0; i < ivec->Nelements; Nnew++) {
+      vtgt[Nnew] = *vsrc;
+      int Ndup = 0;
+      opihi_flt lastValue = *vsrc;
+      while ((i < ivec->Nelements) && (*vsrc == lastValue)) {
+	i++;
+	vsrc ++;
+	Ndup ++;
       }
-      if (!found) {
-	ovec[0].elements.Flt[Nnew] = *v1;
-	Nnew ++;
+      if (cvec) {
+	cvec->elements.Int[Nnew] = Ndup;
       }
     }
+    free (indata);
   } else {
-    opihi_int *v1 = ivec[0].elements.Int;
-    for (i = 0; i < ivec[0].Nelements; i++, v1++) {
-      opihi_int *v2 = ovec[0].elements.Int;
-      found = FALSE;
-      for (j = 0; !found && (j < Nnew); j++, v2++) {
-	if (*v1 == *v2) found = TRUE;
+    // copy the input data to a temporary array to avoid damaging it with sort
+    opihi_int *indata = NULL;
+    ALLOCATE (indata, opihi_int, ivec[0].Nelements);
+    memcpy (indata, ivec->elements.Int, ivec[0].Nelements*sizeof(opihi_int));
+
+    isort (indata, ivec->Nelements);
+
+    Nnew = 0;
+    opihi_int *vtgt = ovec[0].elements.Int;
+
+    opihi_int *vsrc = indata;
+
+    for (i = 0; i < ivec->Nelements; Nnew++) {
+      vtgt[Nnew] = *vsrc;
+      int Ndup = 0;
+      opihi_int lastValue = *vsrc;
+      while ((i < ivec->Nelements) && (*vsrc == lastValue)) {
+	i++;
+	vsrc ++;
+	Ndup ++;
       }
-      if (!found) {
-	ovec[0].elements.Int[Nnew] = *v1;
-	Nnew ++;
+      if (cvec) {
+	cvec->elements.Int[Nnew] = Ndup;
       }
     }
+    free (indata);
   }
 
   // free up extra memory
   ResetVector (ovec, ivec->type, Nnew);
+  if (cvec) ResetVector (cvec, OPIHI_INT, Nnew);
 
   return (TRUE);
