Index: /trunk/psModules/src/astrom/Makefile.am
===================================================================
--- /trunk/psModules/src/astrom/Makefile.am	(revision 20800)
+++ /trunk/psModules/src/astrom/Makefile.am	(revision 20801)
@@ -10,5 +10,6 @@
 	pmAstrometryModel.c \
 	pmAstrometryRefstars.c \
-	pmAstrometryWCS.c
+	pmAstrometryWCS.c \
+	pmAstrometryVisual.c 
 
 pkginclude_HEADERS = \
@@ -19,5 +20,6 @@
 	pmAstrometryModel.h \
 	pmAstrometryRefstars.h \
-	pmAstrometryWCS.h
+	pmAstrometryWCS.h \
+	pmAstrometryVisual.h
 
 CLEANFILES = *~
Index: /trunk/psModules/src/astrom/pmAstrometryObjects.c
===================================================================
--- /trunk/psModules/src/astrom/pmAstrometryObjects.c	(revision 20800)
+++ /trunk/psModules/src/astrom/pmAstrometryObjects.c	(revision 20801)
@@ -8,6 +8,6 @@
 *  @author EAM, IfA
 *
-*  @version $Revision: 1.41 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2008-10-10 02:33:35 $
+*  @version $Revision: 1.42 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2008-11-20 01:26:07 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -29,5 +29,4 @@
 #include <unistd.h>   // for unlink
 #include <pslib.h>
-#include <kapa.h> // cnb: do I need an IFDEF?
 
 #include "pmHDU.h"
@@ -35,4 +34,5 @@
 #include "pmAstrometryObjects.h"
 #include "pmKapaPlots.h"
+#include "pmAstrometryVisual.h"
 
 #define PM_ASTROMETRYOBJECTS_DEBUG 1
@@ -120,5 +120,4 @@
         i++;
     }
-
     return (matches);
 }
@@ -564,10 +563,4 @@
     psF32 **D2 = gridD2->data.F32;
 
-#ifdef PLOTS
-    // vectors to hold dX and dY
-    int nplot = raw->n * ref->n;
-    float dXplot[nplot];
-    float dYplot[nplot];
-#endif
 
     // accumulate grids for focal plane (L,M) matches
@@ -579,9 +572,4 @@
             dY = ob1->FP->y - ob2->FP->y;
 
-#ifdef PLOTS
-            dXplot[(i * ref->n) + j] = dX;
-            dYplot[(i * ref->n) + j] = dY;
-            // fprintf (f, "dX,dY: %8.2f %8.2f : %8.2f %8.2f : %8.2f %8.2f\n", dX, dY, ob1->FP->x, ob2->FP->x, ob1->FP->y, ob2->FP->y);
-#endif
             // find bin coordinates for this delta-delta
             if (!AstromGridBin (&iX, &iY, dX, dY)) {
@@ -618,5 +606,5 @@
         }
 
-        # if 0
+# if 0
         char line[16];
         psFits *fits = psFitsOpen ("grid.image.fits", "w");
@@ -625,5 +613,5 @@
         fprintf (stderr, "wrote grid image, press return to continue\n");
         fgets (line, 15, stdin);
-        # endif
+# endif
 
         // only check bins with at least 1/2 of max bin
@@ -670,4 +658,7 @@
         }
 
+        pmAstromVisualPlotGridMatch(raw, ref, gridNP, stats->offset.x, stats->offset.y,
+                                    maxOffpix, Scale, Offset);
+
         psFree (imStats);
         // XXX EAM : This routine, and pmAstromGridMatch, need to handle failure cases better
@@ -689,59 +680,4 @@
     // fprintf (stderr, "sigma: nMatch: %d, nTest: %d, nTen: %d\n", stats->nMatch, stats->nTest, sort->data.U32[sort->n - 10]);
 
-#ifdef PLOTS
-    /*** plot DXs and DYs ***/
-    KapaSection section = {"s1", 0.00, 0.00, 1.0, 1.0};
-    //KapaSection left = {"s2", 0.05, 0.05, 0.35, 0.8};
-    //KapaSection right = {"s3", 0.55, 0.05, 0.35, 0.8};
-    //KapaSection yprof = {"s4", 0.45, 0.05, 0.10, 0.9};
-    //KapaSection xprof = {"s5", .05, .90, .35, .1};
-
-    Graphdata graphdata;
-    int kapa = pmKapaOpen(true);
-    KapaClearPlots(kapa);
-    KapaInitGraph(&graphdata);
-    KapaSetSection(kapa, &section);
-    graphdata.xmin = stats->offset.x - 1.5 * maxOffpix;
-    graphdata.xmax = stats->offset.x + 1.5 * maxOffpix;
-    graphdata.ymin = stats->offset.y - 1.5 * maxOffpix;
-    graphdata.ymax = stats->offset.y + 1.5 * maxOffpix;
-
-    KapaSetLimits(kapa, &graphdata);
-    KapaSetFont(kapa, "helvetica", 14);
-    KapaBox(kapa, &graphdata);
-    KapaSendLabel (kapa, "X offset", KAPA_LABEL_XM);
-    KapaSendLabel (kapa, "Y offset", KAPA_LABEL_YM);
-    KapaSendLabel (kapa, "pmAstromGridAngle residuals. Big Box: Serach Region. Small Box: Correlation Peak.",
-                   KAPA_LABEL_XP);
-    graphdata.style = 2;
-    graphdata.ptype = 0;
-    graphdata.size = 0.4;
-    graphdata.color = KapaColorByName ("black");
-    KapaPrepPlot(kapa, nplot, &graphdata);
-    KapaPlotVector (kapa, nplot, dXplot, "x");
-    KapaPlotVector (kapa, nplot, dYplot, "y");
-
-    //Overplot bounding box, peak of distribution
-    float xbound[5] = { -maxOffpix, maxOffpix, maxOffpix, -maxOffpix, -maxOffpix};
-    float ybound[5] = { -maxOffpix, -maxOffpix, maxOffpix, maxOffpix, -maxOffpix};
-    float xbin[5] = {stats->offset.x - 0.5 * Scale, stats->offset.x + 0.5 * Scale, stats->offset.x + 0.5 * Scale,
-                     stats->offset.x - 0.5 * Scale, stats->offset.x - 0.5 * Scale};
-    float ybin[5] = {stats->offset.y - 0.5 * Scale, stats->offset.y - 0.5 * Scale, stats->offset.y + 0.5 * Scale,
-                     stats->offset.y + 0.5 * Scale, stats->offset.y - 0.5 * Scale};
-    graphdata.color = KapaColorByName("red");
-    graphdata.style = 0;
-    graphdata.size = 1.0;
-    KapaPrepPlot(kapa, 5, &graphdata);
-    KapaPlotVector (kapa, 5, xbound, "x");
-    KapaPlotVector (kapa, 5, ybound, "y");
-    KapaPrepPlot(kapa, 5, &graphdata);
-    KapaPlotVector (kapa, 5, xbin, "x");
-    KapaPlotVector (kapa, 5, ybin, "y");
-
-    KapaPNG(kapa, "dXdY.png");
-    char c;
-    fscanf(stdin, "%c", &c);
-    /*** end ***/
-#endif
 
   psFree (sort);
@@ -767,5 +703,4 @@
     PS_ASSERT_PTR_NON_NULL(ref, NULL);
     PS_ASSERT_PTR_NON_NULL(config, NULL);
-
     bool status;
     double xMin, xMax, yMin, yMax;
@@ -911,8 +846,4 @@
     psVector *xHistNew = psVectorSmooth(NULL, xHist, tweakSmooth, tweakNsigma);
     psVector *yHistNew = psVectorSmooth(NULL, yHist, tweakSmooth, tweakNsigma);
-    psFree(xHist);
-    psFree(yHist);
-    xHist = xHistNew;
-    yHist = yHistNew;
 
     // select peak in x and in y
@@ -921,11 +852,11 @@
     double yMax = 0;
     for (int i = 0; i < nBin; i++) {
-        if (xHist->data.F32[i] > xMax) {
+        if (xHistNew->data.F32[i] > xMax) {
             xBin = i;
-            xMax = xHist->data.F32[i];
-        }
-        if (yHist->data.F32[i] > yMax) {
+            xMax = xHistNew->data.F32[i];
+        }
+        if (yHistNew->data.F32[i] > yMax) {
             yBin = i;
-            yMax = yHist->data.F32[i];
+            yMax = yHistNew->data.F32[i];
         }
     }
@@ -940,7 +871,11 @@
     tweak->offset.y += yPeak;
 
+    pmAstromVisualPlotTweak (xHistNew, yHistNew, xBin, yBin);
+
     psFree (rot);
     psFree (xHist);
     psFree (yHist);
+    psFree (xHistNew);
+    psFree (yHistNew);
 
     return tweak;
Index: /trunk/psModules/src/astrom/pmAstrometryObjects.h
===================================================================
--- /trunk/psModules/src/astrom/pmAstrometryObjects.h	(revision 20800)
+++ /trunk/psModules/src/astrom/pmAstrometryObjects.h	(revision 20801)
@@ -4,6 +4,6 @@
  * @author EAM, IfA
  *
- * @version $Revision: 1.17 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-11-21 07:02:55 $
+ * @version $Revision: 1.18 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-11-20 01:26:07 $
  * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
  */
@@ -238,11 +238,9 @@
  *
  */
-bool pmAstromFitFPA(
-    pmFPA *fpa,
-    psArray *st1,
-    psArray *st2,
-    psArray *match,
-    psMetadata *config
-);
+bool pmAstromFitFPA(pmFPA *fpa,
+                    psArray *st1,
+                    psArray *st2,
+                    psArray *match,
+                    psMetadata *config);
 
 
@@ -269,6 +267,5 @@
     psArray *st2,
     psArray *match,
-    psMetadata *config
-);
+    psMetadata *config);
 
 
Index: /trunk/psModules/src/astrom/pmAstrometryVisual.c
===================================================================
--- /trunk/psModules/src/astrom/pmAstrometryVisual.c	(revision 20801)
+++ /trunk/psModules/src/astrom/pmAstrometryVisual.c	(revision 20801)
@@ -0,0 +1,448 @@
+/** Diagnostic plots called from within pmAstrometry routines.
+ * @author      Chris Beaumont
+ * @date        October 2008
+ */
+
+/* Include Files   */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <pslib.h>
+
+#include "pmKapaPlots.h"
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmAstrometryObjects.h"
+
+# if (HAVE_KAPA)
+# include <kapa.h>
+
+# define KAPAX 700
+# define KAPAY 700
+
+
+//variables to determine when things are plotted
+static bool isVisual             = false;
+static bool plotGridMatch        = true;
+static bool plotTweak            = true;
+
+// variables to store plotting window indices
+static int kapa = -1;
+
+
+/* Utility Routine Prototypes */
+bool pmAstromVisualScaleGraphdata(Graphdata *graphdata, psVector *xVec, psVector *yVec, bool clip);
+
+
+/* Initialization Routines  */
+
+
+/** start or stop plotting */
+bool pmAstromSetVisual (bool mode) {
+    isVisual = mode;
+    return true;
+}
+
+
+/** open name, and resize a window if necessary */
+bool pmAstromVisualInitWindow (int *kapid, char *name) {
+    if (*kapid == -1) {
+        *kapid = KapaOpenNamedSocket("kapa", name);
+        if (*kapid == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled for pmAstrom\n");
+            isVisual = false;
+            return false;
+        }
+        KapaResize (*kapid, KAPAX, KAPAY);
+    }
+    return true;
+}
+
+
+/** ask the user how to proceed */
+bool pmAstromVisualAskUser(bool *plotflag)
+{
+    char key[10];
+    fprintf (stdout, "[c]ontinue? [s]kip the rest of these plots? [a]bort all visual plots?");
+    if (!fgets(key, 8, stdin)) {
+        psWarning("Unable to read option");
+    }
+    if (key[0] == 's') {
+        *plotflag = false;
+    }
+    if (key[0] == 'a') {
+        pmAstromSetVisual(false);
+    }
+    return true;
+}
+
+
+/** destroy windows at the end of a run*/
+bool pmAstromVisualClose()
+{
+    if(kapa != -1)
+        KiiClose(kapa);
+    return true;
+}
+
+
+/* plotting routines */
+
+/**
+ * Plot the offset between every pair of reference and raw source locations. The peak of this
+ * distribution nominally gives the offset, scale difference, and rotation of the two catalogs.
+ * Overplots the location of this peak as determined by pmAstromGridAngle, as well as some profiles
+ * along horizontal and vertical cuts through this peak.
+ */
+bool pmAstromVisualPlotGridMatch (const psArray *raw, ///< raw stars
+                                  const psArray *ref, ///< reference stars
+                                  psImage *gridNP,    ///< a 2D histogram of raw-ref star distances
+                                  double offsetX,     ///< The X location (FP coordinates) of the peak of gridNP
+                                  double offsetY,     ///< the Y location (FP coordinates) of the peak of gridNP
+                                  double maxOffpix,   ///< The half-width of gridNP in FP coordinates
+                                  double Scale,       ///< The pixel size of gridNP in histogram-bin-coordinates
+                                  double Offset       ///< The (x,y) location (histogram-bin coordinates) of the FP point (0,0) in gridNP
+                                  )
+{
+    //make sure we want to plot this
+    if (!isVisual || !plotGridMatch) return true;
+    if (!pmAstromVisualInitWindow(&kapa, "pmAstrom:plots"))
+        return false;
+
+    KapaSection section = {"s1", 0.05, 0.05, .75, .75};
+    KapaSection sectionY = {"s2", 0.8, 0.05, .15, .75};
+    KapaSection sectionX = {"s3", .05, .8, .75, .15};
+
+    Graphdata graphdata;
+    int nplot = raw->n * ref->n;                      // number of points to plot
+    float dXplot[nplot];                              // x data points
+    float dYplot[nplot];                              // y data points
+    pmAstromObj *ob1; pmAstromObj *ob2;               // shortcuts to the data in raw and ref
+    psU32 **NP = gridNP->data.U32;                    // shortcut to the gridNP data
+    float vertHistSlice[gridNP->numRows];             // vertical histogram slice through peak
+    float horizHistSlice[gridNP->numCols];            // horizontal histogram slice through peak
+    float horizontalIndices[gridNP->numCols];         // the horizontal offset corresponding to each bin of horizHistSlice
+    float verticalIndices[gridNP->numRows];           // the vertical offset corresponding to each bin of vertHistSlice
+    int maxHorizontalSlice = 0;                       // peak value of horizHistSlice
+    int maxVerticalSlice = 0;                         // peak value of vertHistSlice
+    int peakXbin = (int) (offsetX / Scale + Offset);  // X bin index of peak
+    int peakYbin = (int) (offsetY / Scale + Offset);  // Y bin index of peak
+
+
+    // set up plot information
+    KapaClearPlots(kapa);
+    KapaInitGraph(&graphdata);
+    KapaSetSection(kapa, &section);
+
+    graphdata.xmin = -1.0 * maxOffpix;
+    graphdata.xmax =  1.0 * maxOffpix;
+    graphdata.ymin = -1.0 * maxOffpix;
+    graphdata.ymax =  1.0 * maxOffpix;
+    KapaSetLimits(kapa, &graphdata);
+
+    KapaSetFont(kapa, "helvetica", 14);
+    KapaBox(kapa, &graphdata);
+    KapaSendLabel (kapa, "X offset (FP)", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "Y offset (FP)", KAPA_LABEL_YM);
+    KapaSendLabel (kapa, "pmAstromGridAngle residuals. Box: Correlation Peak.",
+                   KAPA_LABEL_XP);
+    graphdata.style = 2;
+    graphdata.ptype = 0;
+    graphdata.size = 0.4;
+    graphdata.color = KapaColorByName ("black");
+
+    // calculate the plot points
+    float dX, dY;
+    for (int i = 0; i < raw->n; i++) {
+        ob1 = (pmAstromObj *)raw->data[i];
+        for (int j = 0; j < ref->n; j++) {
+            ob2 = (pmAstromObj *)ref->data[j];
+            dX = ob1->FP->x - ob2->FP->x;
+            dY = ob1->FP->y - ob2->FP->y;
+            dXplot[(i * ref->n) + j] = dX;
+            dYplot[(i * ref->n) + j] = dY;
+        }
+    }
+
+    // calculate the points for the profiles
+    for (int i = 0; i < gridNP->numRows; i++) {
+        vertHistSlice[i] = NP[i][peakXbin];
+        verticalIndices[i] = (i - Offset) * Scale;
+        if (vertHistSlice[i] > maxVerticalSlice) {
+            maxVerticalSlice = vertHistSlice[i];
+        }
+    }
+    for (int i = 0; i < gridNP->numCols; i++) {
+        horizHistSlice[i] = NP[peakYbin][i];
+        horizontalIndices[i] = (i - Offset) * Scale;
+        if (horizHistSlice[i] > maxHorizontalSlice) {
+            maxHorizontalSlice = horizHistSlice[i];
+        }
+    }
+
+    //Plot the offsets
+    KapaPrepPlot(kapa, nplot, &graphdata);
+    KapaPlotVector (kapa, nplot, dXplot, "x");
+    KapaPlotVector (kapa, nplot, dYplot, "y");
+
+    //Overplot bounding box, peak of distribution
+    float xbound[5] = { -maxOffpix, maxOffpix, maxOffpix, -maxOffpix, -maxOffpix};
+    float ybound[5] = { -maxOffpix, -maxOffpix, maxOffpix, maxOffpix, -maxOffpix};
+    float xbin[5] = {offsetX - 0.5 * Scale, offsetX + 0.5 * Scale,
+                     offsetX + 0.5 * Scale, offsetX - 0.5 * Scale,
+                     offsetX - 0.5 * Scale};
+    float ybin[5] = {offsetY - 0.5 * Scale, offsetY - 0.5 * Scale,
+                     offsetY + 0.5 * Scale, offsetY + 0.5 * Scale,
+                     offsetY - 0.5 * Scale};
+    graphdata.color = KapaColorByName("red");
+    graphdata.style = 0;
+    graphdata.size = 1.0;
+    KapaPrepPlot(kapa, 5, &graphdata);
+    KapaPlotVector (kapa, 5, xbound, "x");
+    KapaPlotVector (kapa, 5, ybound, "y");
+    KapaPrepPlot(kapa, 5, &graphdata);
+    KapaPlotVector (kapa, 5, xbin, "x");
+    KapaPlotVector (kapa, 5, ybin, "y");
+
+    //plot X profile
+    KapaSetSection(kapa, &sectionX);
+    graphdata.color = KapaColorByName("black");
+    graphdata.ptype = 1;
+    graphdata.style = 1;
+    graphdata.ymin = 0;
+    graphdata.ymax = maxHorizontalSlice + 0.5;
+    KapaSetLimits(kapa, &graphdata);
+
+    KapaBox(kapa, &graphdata);
+    KapaPrepPlot(kapa, gridNP->numCols, &graphdata);
+    KapaPlotVector (kapa, gridNP->numCols, horizontalIndices, "x");
+    KapaPlotVector (kapa, gridNP->numCols, horizHistSlice, "y");
+    float xslice[2] = {offsetX - Scale / 2., offsetX - Scale / 2.};
+    float yslice[2] = {-5, 100};
+    graphdata.color = KapaColorByName("red");
+    KapaPrepPlot(kapa, 2, &graphdata);
+    KapaPlotVector (kapa, 2, xslice, "x");
+    KapaPlotVector (kapa, 2, yslice, "y");
+
+    //plot Y profile
+    KapaSetSection(kapa, &sectionY);
+    graphdata.color = KapaColorByName("black");
+    graphdata.ptype = 1;
+    graphdata.style = 1;
+    graphdata.ymin = -maxOffpix;
+    graphdata.ymax = maxOffpix;
+    graphdata.xmin = -1.0 ;
+    graphdata.xmax = maxVerticalSlice + 0.5;
+    KapaSetLimits(kapa, &graphdata);
+
+    KapaBox(kapa, &graphdata);
+    KapaPrepPlot(kapa, gridNP->numRows, &graphdata);
+    KapaPlotVector (kapa, gridNP->numRows, vertHistSlice, "x");
+    KapaPlotVector (kapa, gridNP->numRows, verticalIndices, "y");
+    yslice[0] = yslice[1] = offsetY - Scale / 2.;
+    xslice[0] = -5; xslice[1] = 100;
+    graphdata.color = KapaColorByName("red");
+    KapaPrepPlot(kapa, 2, &graphdata);
+    KapaPlotVector (kapa, 2, xslice, "x");
+    KapaPlotVector (kapa, 2, yslice, "y");
+
+    pmAstromVisualAskUser(&plotGridMatch);
+    return true;
+} // end of pmAstromVisualPlotGridMatch
+
+
+/** Plot the refinements made within pmAstromGridTweak.
+ * After pmAstromGridMatch finds the best rotaion/scale/offset between raw and reference stars
+ * within a coarse grid of rotations/scales, pmAstromGridTweak computes a higher precision
+ * estimate of the offset. It computes the 2 point correlation function between raw and ref
+ * stars along horizontal and vertical cuts through the first-guess offset. It finds the peak
+ * of these two profiles and adjusts the offset accordingly. This procedure plots the profiles.
+ */
+bool pmAstromVisualPlotTweak (psVector *xHist, ///< Smoothed Horizontal cut through the histogram
+                              psVector *yHist, ///< Smoothed Vertical cut throug the histogram
+                              int xBin,        ///< X Bin index of the histogram peak
+                              int yBin         ///< Y bin index of the histogram peak
+    )
+{
+    //make sure we want to plot this
+    if (!isVisual || !plotTweak) return true;
+    if (!pmAstromVisualInitWindow(&kapa, "pmAstrom:plots")) {
+        return false;
+    }
+
+    Graphdata graphdata;
+    KapaSection section1 = {"s1", 0.05, 0.05, 0.90, 0.4};
+    KapaSection section2 = {"s2", 0.05, 0.5, 0.90, 0.4};
+
+    psVector *xIndices = psVectorAlloc (xHist->n, PS_TYPE_F32);
+    psVector *yIndices = psVectorAlloc (yHist->n, PS_TYPE_F32);
+
+    //populate the Indices vectors
+    for(int i = 0; i < xHist->n; i++) {
+        xIndices->data.F32[i] = i;
+    }
+    for(int i = 0; i < yHist->n; i++) {
+        yIndices->data.F32[i] = i;
+    }
+
+    // set up plot information
+    KapaClearPlots(kapa);
+    KapaInitGraph(&graphdata);
+
+    // plot the X histogram
+    pmAstromVisualScaleGraphdata(&graphdata, xIndices, xHist, false);
+    KapaSetSection(kapa, &section1);
+    KapaSetLimits (kapa, &graphdata);
+    KapaSetFont(kapa, "helvetica", 14);
+    KapaBox(kapa, &graphdata);
+    KapaSendLabel (kapa, "X offset Bin", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "Number of Sources", KAPA_LABEL_YM);
+    KapaSendLabel (kapa, "Horizontal Profile",
+                   KAPA_LABEL_XP);
+    graphdata.style = 1;
+    graphdata.ptype = 0;
+    graphdata.size = 0.4;
+    graphdata.color = KapaColorByName ("black");
+
+    KapaPrepPlot (kapa, xHist->n, &graphdata);
+    KapaPlotVector (kapa, xHist->n, xIndices->data.F32, "x");
+    KapaPlotVector (kapa, xHist->n, xHist->data.F32, "y");
+
+    //overplot the peak
+    float x[2] = {xBin, xBin};
+    float y[2] = {-500, 500};
+    graphdata.color = KapaColorByName ("red");
+    KapaPrepPlot (kapa, 2, &graphdata);
+    KapaPlotVector (kapa, 2, x, "x");
+    KapaPlotVector (kapa, 2, y, "y");
+
+    //plot the Y histogram
+    pmAstromVisualScaleGraphdata(&graphdata, yIndices, yHist, false);
+    KapaSetSection(kapa, &section2);
+    KapaSetLimits (kapa, &graphdata);
+    KapaSetFont(kapa, "helvetica", 14);
+    graphdata.color = KapaColorByName ("black");
+    KapaBox(kapa, &graphdata);
+    KapaSendLabel (kapa, "Y offset Bin", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "Number of Sources", KAPA_LABEL_YM);
+    KapaSendLabel (kapa, "Vertical Profile",
+                   KAPA_LABEL_XP);
+    graphdata.style = 1;
+    graphdata.ptype = 0;
+    graphdata.size = 0.4;
+
+    KapaPrepPlot (kapa, yHist->n, &graphdata);
+    KapaPlotVector (kapa, yHist->n, yIndices->data.F32, "x");
+    KapaPlotVector (kapa, yHist->n, yHist->data.F32, "y");
+
+    //overplot the peak
+    x[0] = x[1] = yBin;
+    graphdata.color = KapaColorByName ("red");
+    KapaPrepPlot (kapa, 2, &graphdata);
+    KapaPlotVector (kapa, 2, x, "x");
+    KapaPlotVector (kapa, 2, y, "y");
+
+    //plot title
+    graphdata.color = KapaColorByName("black");
+    KapaSection section3 = {"s3", 0, 0, 1, 1};
+    KapaSetSection( kapa, &section3);
+    KapaSendLabel (kapa, "Tweaking the Astrometry Grid Solution. Smoothed profiles + peak location",
+                   KAPA_LABEL_XP);
+
+    pmAstromVisualAskUser(&plotTweak);
+
+    psFree(xIndices);
+    psFree(yIndices);
+    return true;
+} //end of pmAstromPlotTweak
+
+
+/** pmAstromScaleGraphdata
+ * Scale the graphdata structure based on x and y coordinates. Use sigma clipping to
+ * prevent outliers from making te plot region too big.
+ */
+bool pmAstromVisualScaleGraphdata(Graphdata *graphdata, psVector *xVec, psVector *yVec, bool clip) {
+
+    graphdata->xmin = +FLT_MAX;
+    graphdata->xmax = -FLT_MAX;
+    graphdata->ymin = +FLT_MAX;
+    graphdata->ymax = -FLT_MAX;
+
+    //determine standard deviation of xVec and yVec
+    psStats *statsX = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
+    psStats *statsY = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
+    psVectorStats (statsX, xVec, NULL, NULL, 0);
+    psVectorStats (statsY, yVec, NULL, NULL, 0);
+
+    float xhi  = statsX->sampleMedian + 3 *statsX->sampleStdev;
+    float xlo = statsX->sampleMedian - 3 *statsX->sampleStdev;
+    float yhi = statsY->sampleMedian + 3 *statsY->sampleStdev;
+    float ylo = statsY->sampleMedian - 3 *statsY->sampleStdev;
+
+    // don't sigma clip
+    if (!clip) {
+        xhi = +FLT_MAX;
+        xlo = -FLT_MAX;
+        yhi = +FLT_MAX;
+        ylo = -FLT_MAX;
+    }
+
+    // abort if there is no good data
+    if (!isfinite(xhi) || !isfinite(xlo) || !isfinite(yhi) || !isfinite(ylo)) {
+        graphdata->xmin = -1;
+        graphdata->ymin  = -1;
+        graphdata->xmax = 1;
+        graphdata->ymax = 1;
+        psFree(statsX);
+        psFree(statsY);
+        return false;
+    }
+
+    for(int i = 0; i < xVec->n; i++) {
+        if (!isfinite(xVec->data.F32[i])) continue;
+        if (xVec->data.F32[i] > xhi || xVec->data.F32[i] < xlo) continue;
+        graphdata->xmin = PS_MIN (graphdata->xmin, xVec->data.F32[i]);
+        graphdata->xmax = PS_MAX (graphdata->xmax, xVec->data.F32[i]);
+    }
+
+    for (int i = 0; i < yVec->n; i++) {
+        if (!isfinite(xVec->data.F32[i])) continue;
+        if (yVec->data.F32[i] > yhi || yVec->data.F32[i] < ylo) continue;
+        graphdata->ymin = PS_MIN (graphdata->ymin, yVec->data.F32[i]);
+        graphdata->ymax = PS_MAX (graphdata->ymax, yVec->data.F32[i]);
+    }
+
+    // add a whitespace border
+    float range = graphdata->xmax - graphdata->xmin;
+    if (range == 0) range = 1;
+    graphdata->xmin -= .05 * range;
+    graphdata->xmax += .05 * range;
+
+    range = graphdata->ymax - graphdata->ymin;
+    if (range == 0) range = 1;
+    graphdata->ymin -= .05 * range;
+    graphdata->ymax += .05 * range;
+
+    psFree (statsX);
+    psFree (statsY);
+    return true;
+}
+
+
+# else
+
+bool pmAstromSetVisual(bool mode) { return true; }
+bool pmAstromVisualInitWindow (int *kapid, char *name) { return true; }
+bool pmAstromVisualAskUser (bool *plotflag) { return true; }
+bool pmAstromVisualClose() { return true; }
+bool pmAstromVisualPlotGridMatch (const psArray *raw, const psArray *ref, psImage *gridNP, double offsetX, double offsetY, double maxOffpix, double Scale, double Offset) { return true; }
+bool pmAstromVisualPlotTweak (psVector *xHist, psVector *yHist, int xBin, int yBin) {return true;}
+
+# endif
Index: /trunk/psModules/src/astrom/pmAstrometryVisual.h
===================================================================
--- /trunk/psModules/src/astrom/pmAstrometryVisual.h	(revision 20801)
+++ /trunk/psModules/src/astrom/pmAstrometryVisual.h	(revision 20801)
@@ -0,0 +1,6 @@
+bool pmAstromSetVisual(bool mode);
+bool pmAstromVisualInitWindow (int *kapid, char *name);
+bool pmAstromVisualAskUser (bool *plotflag);
+bool pmAstromVisualClose();
+bool pmAstromVisualPlotGridMatch (const psArray *raw, const psArray *ref, psImage *gridNP, double offsetX, double offsetY, double maxOffpix, double Scale, double Offset);
+bool pmAstromVisualPlotTweak (psVector *xHist, psVector *yHist, int xBin, int yBin);
Index: /trunk/psModules/src/psmodules.h
===================================================================
--- /trunk/psModules/src/psmodules.h	(revision 20800)
+++ /trunk/psModules/src/psmodules.h	(revision 20801)
@@ -82,4 +82,5 @@
 #include <pmAstrometryRefstars.h>
 #include <pmAstrometryDistortion.h>
+#include <pmAstrometryVisual.h>
 
 // the following headers are from psModule:imcombine
