Example #1
0
    def __init__(self, schema, refObjLoader=None, **kwds):
        r"""!Create the astrometric calibration task.  Most arguments are simply passed onto pipe.base.Task.

        \param schema An lsst::afw::table::Schema used to create the output lsst.afw.table.SourceCatalog
        \param refObjLoader The AstrometryTask constructor requires a refObjLoader.  In order to make this
        task retargettable for AstrometryTask it needs to take the same arguments.  This argument will be
        ignored since it uses its own internal loader.
        \param **kwds keyword arguments to be passed to the lsst.pipe.base.task.Task constructor

        A centroid field "centroid.distorted" (used internally during the Task's operation)
        will be added to the schema.
        """
        pipeBase.Task.__init__(self, **kwds)
        self.distortedName = "astrom_distorted"
        self.centroidXKey = schema.addField(self.distortedName + "_x", type="D",
                                            doc="centroid distorted for astrometry solver")
        self.centroidYKey = schema.addField(self.distortedName + "_y", type="D",
                                            doc="centroid distorted for astrometry solver")
        self.centroidXErrKey = schema.addField(self.distortedName + "_xErr", type="F",
                                               doc="centroid distorted err for astrometry solver")
        self.centroidYErrKey = schema.addField(self.distortedName + "_yErr", type="F",
                                               doc="centroid distorted err for astrometry solver")
        self.centroidFlagKey = schema.addField(self.distortedName + "_flag", type="Flag",
                                               doc="centroid distorted flag astrometry solver")
        self.centroidKey = Point2DKey(self.centroidXKey, self.centroidYKey)
        self.centroidErrKey = CovarianceMatrix2fKey((self.centroidXErrKey, self.centroidYErrKey))
        # postpone making the solver subtask because it may not be needed and is expensive to create
        self.solver = None
Example #2
0
    def plotStars(self, refCat, bbox=None):
        """Plot the centroids of reference objects, and the bounding box (if specified)
        """
        import matplotlib.pyplot as plt
        if bbox is not None:
            cornerList = list(afwGeom.Box2D(bbox).getCorners())
            cornerList.append(cornerList[0])  # show 4 sides of the box by going back to the beginning
            xc, yc = list(zip(*cornerList))
            plt.plot(xc, yc, '-')

        centroidKey = Point2DKey(refCat.schema["centroid"])
        centroidList = [rec.get(centroidKey) for rec in refCat]
        xp, yp = list(zip(*centroidList))
        plt.plot(xp, yp, '.')
        plt.show()
Example #3
0
    def assertObjInBBox(self, refCat, bbox, wcs):
        """Assert that all reference objects are inside the specified pixel bounding box plus a margin

        @param[in] refCat  reference object catalog, an lsst.afw.table.SimpleCatalog or compatible;
            the only fields read are "centroid_x/y" and "coord_ra/dec"
        @param[in] bbox  pixel bounding box coordinates, an lsst.afw.geom.Box2I or Box2D;
            the supplied box is grown by self.config.pixelMargin before testing the stars
        @param[in] wcs  WCS, an lsst.afw.image.Wcs
        """
        bbox = afwGeom.Box2D(bbox)
        bbox.grow(self.config.pixelMargin)
        centroidKey = Point2DKey(refCat.schema["centroid"])
        coordKey = CoordKey(refCat.schema["coord"])
        for refObj in refCat:
            point = refObj.get(centroidKey)
            if not bbox.contains(point):
                coord = refObj.get(coordKey)
                self.fail("refObj at RA, Dec %0.3f, %0.3f point %s is not in bbox %s" %
                          (coord[0].asDegrees(), coord[1].asDegrees(), point, bbox))
Example #4
0
def displayAstrometry(refCat=None,
                      sourceCat=None,
                      distortedCentroidKey=None,
                      bbox=None,
                      exposure=None,
                      matches=None,
                      frame=1,
                      title="",
                      pause=True):
    """Show an astrometry debug image.

    Parameters
    ----------
    refCat : `lsst.afw.table.SimpleCatalog`
        reference object catalog; must have fields "centroid_x" an
        "centroid_y"
    sourceCat : `lsst.afw.table.SourceCatalg`
        source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
    distortedCentroidKey : `lsst.afw.table.Key`
        key for sourceCat with field to use for distorted positions
    exposure : `lsst.afw.image.Exposure`
        exposure to display
    bbox : `lsst.geom.Box2I`
        bounding box of exposure; Used if the exposure is `None`
    matches : `list` of `lsst.afw.table.ReferenceMatch`
        List of matched objects
    frame : `int`
        frame number for display
    title : `str`
        title for display
    pause : `bool`
        pause for inspection of display? This is done by dropping into pdb.

    Notes
    -----

    - reference objects in refCat are shown as red X
    - sources in sourceCat are shown as green +
    - distorted sources in sourceCat (position given by distortedCentroidKey)
      are shown as green o
    - matches are shown as a yellow circle around the source and a yellow line
      connecting the reference object and source
    - if both exposure and bbox are `None`, no image is displayed

    """
    disp = afwDisplay.getDisplay(frame=frame)

    if exposure is not None:
        disp.mtv(exposure, title=title)
    elif bbox is not None:
        disp.mtv(exposure=ExposureF(bbox), title=title)

    with disp.Buffering():
        if refCat is not None:
            refCentroidKey = Point2DKey(refCat.schema["centroid"])
            for refObj in refCat:
                rx, ry = refObj.get(refCentroidKey)
                disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED)

        if sourceCat is not None:
            sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
            for source in sourceCat:
                sx, sy = source.get(sourceCentroidKey)
                disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN)
                if distortedCentroidKey is not None:
                    dx, dy = source.get(distortedCentroidKey)
                    disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN)
                    disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN)

        if matches is not None:
            refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
            sourceCentroidKey = Point2DKey(
                matches[0].second.schema["slot_Centroid"])
            radArr = np.ndarray(len(matches))

            for i, m in enumerate(matches):
                refCentroid = m.first.get(refCentroidKey)
                sourceCentroid = m.second.get(sourceCentroidKey)
                radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
                sx, sy = sourceCentroid
                disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW)
                disp.line([refCentroid, sourceCentroid],
                          ctype=afwDisplay.YELLOW)

            print("<match radius> = %.4g +- %.4g [%d matches]" %
                  (radArr.mean(), radArr.std(), len(matches)))

    if pause:
        print(
            "Dropping into debugger to allow inspection of display. Type 'continue' when done."
        )
        import pdb
        pdb.set_trace()
Example #5
0
def plotAstrometry(matches,
                   refCat=None,
                   sourceCat=None,
                   refMarker="x",
                   refColor="r",
                   sourceMarker="+",
                   sourceColor="g",
                   matchColor="y"):
    """Plot reference objects, sources and matches

    Parameters
    ----------
    matches : `list` of `lsst.afw.table.ReferenceMatch`
        list of matches
    refCat : `lsst.afw.table.SimpleCatalog`
        reference object catalog, or None to not plot reference objects
    sourceCat : `lsst.afw.table.SourceCatalog`
        source catalog, or None to not plot sources
    refMarker : `str`
        pyplot marker for reference objects
    refColor : `str`
        pyplot color for reference objects
    sourceMarker : `str`
        pyplot marker for sources
    sourceColor : `str`
        pyplot color for sources
    matchColor : `str`
        color for matches; can be a constant
        or a function taking one match and returning a string

    Notes
    -----
    By default:

    - reference objects in refCat are shown as red X
    - sources in sourceCat are shown as green +
    - matches are shown as a yellow circle around the source and a line
      connecting the reference object to the source
    """
    # delay importing plt to give users a chance to set the backend before calling this function
    import matplotlib.pyplot as plt
    refSchema = matches[0][0].schema
    refCentroidKey = Point2DKey(refSchema["centroid"])
    srcSchema = matches[0][1].schema
    srcCentroidKey = Point2DKey(srcSchema["slot_Centroid"])

    if refCat is not None:
        refXArr, refYArr = list(
            zip(*[ref.get(refCentroidKey) for ref in refCat]))
        plt.plot(refXArr,
                 refYArr,
                 marker=refMarker,
                 color=refColor,
                 linestyle="")

    if sourceCat is not None:
        srcXArr, srcYArr = list(
            zip(*[src.get(srcCentroidKey) for src in sourceCat]))
        plt.plot(srcXArr,
                 srcYArr,
                 marker=sourceMarker,
                 color=sourceColor,
                 linestyle="")

    def makeLineSegmentData(refXYArr, srcXYArr, colorArr):
        """Make a list of line segement data

        This is used to draw line segements between ref and src positions in the specified color

        Notes
        -----
        The returned data has the format:
         [(refX0, srcX0), (refY0, srcY0), color0, (refX1, srcX1), (refY1, srcY1), color1,...]
        """
        if len(refXYArr) != len(srcXYArr):
            raise RuntimeError("len(refXYArr) = %d != %d = len(srcXYArr)" %
                               (len(refXYArr), len(srcXYArr)))
        if len(refXYArr) != len(colorArr):
            raise RuntimeError("len(refXYArr) = %d != %d = len(colorArr)" %
                               (len(refXYArr), len(colorArr)))

        refXArr, refYArr = list(zip(*refXYArr))
        srcXArr, srcYArr = list(zip(*srcXYArr))
        refSrcXArr = list(zip(refXArr, srcXArr))
        refSrcYArr = list(zip(refYArr, srcYArr))
        dataList = []
        for xycolor in zip(refSrcXArr, refSrcYArr, colorArr):
            for val in xycolor:
                dataList.append(val)
        return dataList

    refXYArr, srcXYArr = \
        list(zip(*[(match[0].get(refCentroidKey), match[1].get(srcCentroidKey)) for match in matches]))

    def plotSourceCircles(matches, color):
        srcXYArr = [match[1].get(srcCentroidKey) for match in matches]
        srcXArr, srcYArr = list(zip(*srcXYArr))
        plt.plot(
            srcXArr,
            srcYArr,
            "o",
            mec=color,
            mfc="none",
            ms=10,
        )

    if callable(matchColor):
        # different matches have different colors
        matchColorArr = [matchColor(match) for match in matches]

        # plot circles for each color separately
        matchColorSet = set(matchColorArr)
        for color in matchColorSet:
            subMatches = [
                match for match in matches if matchColor(match) == color
            ]
            plotSourceCircles(subMatches, color=color)
    else:
        matchColorArr = [matchColor] * len(refXYArr)
        plotSourceCircles(matches, color=matchColor)

    lineSegData = makeLineSegmentData(refXYArr, srcXYArr, matchColorArr)
    plt.plot(*lineSegData)

    plt.show()
Example #6
0
def displayAstrometry(refCat=None,
                      sourceCat=None,
                      distortedCentroidKey=None,
                      bbox=None,
                      exposure=None,
                      matches=None,
                      frame=1,
                      title="",
                      pause=True):
    """Show an astrometry debug image

    - reference objects in refCat are shown as red X
    - sources in sourceCat are shown as green +
    - distorted sources in sourceCat (position given by distortedCentroidKey) are shown as green o
    - matches are shown as a yellow circle around the source and a yellow line
        connecting the reference object and source
    - if both exposure and bbox are None, no image is displayed

    @param[in] refCat  reference object catalog; must have fields "centroid_x" and "centroid_y"
    @param[in] sourceCat  source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
    @param[in] distortedCentroidKey  key for sourceCat with field to use for distorted positions, or None
    @param[in] exposure  exposure to display, or None for a blank exposure
    @param[in] bbox  bounding box of exposure; used if exposure is None for a blank image
    @param[in] matches  a list of lsst.afw.table.ReferenceMatch, or None
    @param[in] frame  frame number for ds9 display
    @param[in] title  title for ds9 display
    @param[in] pause  pause for inspection of display? This is done by dropping into pdb.
    """
    disp = afwDisplay.getDisplay(frame)

    if exposure is not None:
        disp.mtv(exposure, title=title)
    elif bbox is not None:
        disp.mtv(exposure=ExposureF(bbox), title=title)

    with disp.Buffering():
        if refCat is not None:
            refCentroidKey = Point2DKey(refCat.schema["centroid"])
            for refObj in refCat:
                rx, ry = refObj.get(refCentroidKey)
                disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED)

        if sourceCat is not None:
            sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
            for source in sourceCat:
                sx, sy = source.get(sourceCentroidKey)
                disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN)
                if distortedCentroidKey is not None:
                    dx, dy = source.get(distortedCentroidKey)
                    disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN)
                    disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN)

        if matches is not None:
            refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
            sourceCentroidKey = Point2DKey(
                matches[0].second.schema["slot_Centroid"])
            radArr = np.ndarray(len(matches))

            for i, m in enumerate(matches):
                refCentroid = m.first.get(refCentroidKey)
                sourceCentroid = m.second.get(sourceCentroidKey)
                radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
                sx, sy = sourceCentroid
                disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW)
                disp.line([refCentroid, sourceCentroid],
                          ctype=afwDisplay.YELLOW)

            print("<match radius> = %.4g +- %.4g [%d matches]" %
                  (radArr.mean(), radArr.std(), len(matches)))

    if pause:
        print(
            "Dropping into debugger to allow inspection of display. Type 'continue' when done."
        )
        import pdb
        pdb.set_trace()