22 """Support utilities for Measuring sources""" 25 __all__ = [
"DipoleTestImage"]
36 import lsst.meas.algorithms
as measAlg
38 from .dipoleFitTask
import DipoleFitAlgorithm
39 from .
import diffimLib
40 from .
import diffimTools
42 afwDisplay.setDefaultMaskTransparency(75)
46 def showSourceSet(sSet, xy0=(0, 0), frame=0, ctype=afwDisplay.GREEN, symb=
"+", size=2):
47 """Draw the (XAstrom, YAstrom) positions of a set of Sources. 49 Image has the given XY0. 51 disp = afwDisplay.afwDisplay(frame=frame)
52 with disp.Buffering():
54 xc, yc = s.getXAstrom() - xy0[0], s.getYAstrom() - xy0[1]
57 disp.dot(str(s.getId()), xc, yc, ctype=ctype, size=size)
59 disp.dot(symb, xc, yc, ctype=ctype, size=size)
67 ctype=None, ctypeUnused=None, ctypeBad=None, size=3,
68 frame=None, title="Spatial Cells"):
69 """Show the SpatialCells. 71 If symb is something that display.dot understands (e.g. "o"), the top 72 nMaxPerCell candidates will be indicated with that symbol, using ctype 75 disp = afwDisplay.Display(frame=frame)
76 disp.mtv(maskedIm, title=title)
77 with disp.Buffering():
78 origin = [-maskedIm.getX0(), -maskedIm.getY0()]
79 for cell
in kernelCellSet.getCellList():
80 afwDisplay.utils.drawBBox(cell.getBBox(), origin=origin, display=disp)
82 goodies = ctypeBad
is None 83 for cand
in cell.begin(goodies):
84 xc, yc = cand.getXCenter() + origin[0], cand.getYCenter() + origin[1]
85 if cand.getStatus() == afwMath.SpatialCellCandidate.BAD:
87 elif cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
89 elif cand.getStatus() == afwMath.SpatialCellCandidate.UNKNOWN:
95 disp.dot(symb, xc, yc, ctype=color, size=size)
98 rchi2 = cand.getChi2()
101 disp.dot(
"%d %.1f" % (cand.getId(), rchi2),
102 xc - size, yc - size - 4, ctype=color, size=size)
106 """Display Dia Sources. 112 disp = afwDisplay.Display(frame=frame)
113 for plane
in (
"BAD",
"CR",
"EDGE",
"INTERPOlATED",
"INTRP",
"SAT",
"SATURATED"):
114 disp.setMaskPlaneColor(plane, color=
"ignore")
116 mos = afwDisplay.utils.Mosaic()
117 for i
in range(len(sources)):
119 badFlag = isFlagged[i]
120 dipoleFlag = isDipole[i]
121 bbox = source.getFootprint().getBBox()
122 stamp = exposure.Factory(exposure, bbox,
True)
123 im = afwDisplay.utils.Mosaic(gutter=1, background=0, mode=
"x")
124 im.append(stamp.getMaskedImage())
125 lab =
"%.1f,%.1f:" % (source.getX(), source.getY())
127 ctype = afwDisplay.RED
130 ctype = afwDisplay.YELLOW
132 if not badFlag
and not dipoleFlag:
133 ctype = afwDisplay.GREEN
135 mos.append(im.makeMosaic(), lab, ctype)
136 title =
"Dia Sources" 137 mosaicImage = mos.makeMosaic(frame=frame, title=title)
142 resids=False, kernels=False):
143 """Display the Kernel candidates. 145 If kernel is provided include spatial model and residuals; 146 If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi. 152 mos = afwDisplay.utils.Mosaic(gutter=5, background=0)
154 mos = afwDisplay.utils.Mosaic(gutter=5, background=-1)
156 candidateCenters = []
157 candidateCentersBad = []
159 for cell
in kernelCellSet.getCellList():
160 for cand
in cell.begin(
False):
163 resid = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
167 rchi2 = cand.getChi2()
171 if not showBadCandidates
and cand.isBad():
174 im_resid = afwDisplay.utils.Mosaic(gutter=1, background=-0.5, mode=
"x")
177 im = cand.getScienceMaskedImage()
178 im = im.Factory(im,
True)
179 im.setXY0(cand.getScienceMaskedImage().getXY0())
182 if (
not resids
and not kernels):
183 im_resid.append(im.Factory(im,
True))
185 im = cand.getTemplateMaskedImage()
186 im = im.Factory(im,
True)
187 im.setXY0(cand.getTemplateMaskedImage().getXY0())
190 if (
not resids
and not kernels):
191 im_resid.append(im.Factory(im,
True))
195 var = resid.getVariance()
196 var = var.Factory(var,
True)
197 np.sqrt(var.getArray(), var.getArray())
198 resid = resid.getImage()
200 bbox = kernel.shrinkBBox(resid.getBBox())
201 resid = resid.Factory(resid, bbox, deep=
True)
203 kim = cand.getKernelImage(diffimLib.KernelCandidateF.ORIG).convertF()
204 resid = kim.Factory(kim,
True)
205 im_resid.append(resid)
208 ski = afwImage.ImageD(kernel.getDimensions())
209 kernel.computeImage(ski,
False, int(cand.getXCenter()), int(cand.getYCenter()))
213 sbg = background(int(cand.getXCenter()), int(cand.getYCenter()))
214 sresid = cand.getDifferenceImage(sk, sbg)
217 resid = sresid.getImage()
219 bbox = kernel.shrinkBBox(resid.getBBox())
220 resid = resid.Factory(resid, bbox, deep=
True)
223 resid = kim.Factory(kim,
True)
224 im_resid.append(resid)
226 im = im_resid.makeMosaic()
228 lab =
"%d chi^2 %.1f" % (cand.getId(), rchi2)
229 ctype = afwDisplay.RED
if cand.isBad()
else afwDisplay.GREEN
231 mos.append(im, lab, ctype)
233 if False and np.isnan(rchi2):
234 disp = afwDisplay.Display(frame=1)
235 disp.mtv(cand.getScienceMaskedImage.getImage(), title=
"candidate")
236 print(
"rating", cand.getCandidateRating())
238 im = cand.getScienceMaskedImage()
239 center = (candidateIndex, cand.getXCenter() - im.getX0(), cand.getYCenter() - im.getY0())
242 candidateCentersBad.append(center)
244 candidateCenters.append(center)
251 title =
"Candidates & residuals" 252 mosaicImage = mos.makeMosaic(frame=frame, title=title)
258 """Display a Kernel's basis images. 260 mos = afwDisplay.utils.Mosaic()
262 for k
in kernel.getKernelList():
263 im = afwImage.ImageD(k.getDimensions())
264 k.computeImage(im,
False)
266 mos.makeMosaic(frame=frame, title=
"Kernel Basis Images")
274 numSample=128, keepPlots=True, maxCoeff=10):
275 """Plot the Kernel spatial model. 278 import matplotlib.pyplot
as plt
279 import matplotlib.colors
280 except ImportError
as e:
281 print(
"Unable to import numpy and matplotlib: %s" % e)
284 x0 = kernelCellSet.getBBox().getBeginX()
285 y0 = kernelCellSet.getBBox().getBeginY()
293 for cell
in kernelCellSet.getCellList():
294 for cand
in cell.begin(
False):
295 if not showBadCandidates
and cand.isBad():
297 candCenter = afwGeom.PointD(cand.getXCenter(), cand.getYCenter())
299 im = cand.getTemplateMaskedImage()
303 targetFits = badFits
if cand.isBad()
else candFits
304 targetPos = badPos
if cand.isBad()
else candPos
305 targetAmps = badAmps
if cand.isBad()
else candAmps
308 kp0 = np.array(cand.getKernel(diffimLib.KernelCandidateF.ORIG).getKernelParameters())
309 amp = cand.getCandidateRating()
311 targetFits = badFits
if cand.isBad()
else candFits
312 targetPos = badPos
if cand.isBad()
else candPos
313 targetAmps = badAmps
if cand.isBad()
else candAmps
315 targetFits.append(kp0)
316 targetPos.append(candCenter)
317 targetAmps.append(amp)
319 xGood = np.array([pos.getX()
for pos
in candPos]) - x0
320 yGood = np.array([pos.getY()
for pos
in candPos]) - y0
321 zGood = np.array(candFits)
323 xBad = np.array([pos.getX()
for pos
in badPos]) - x0
324 yBad = np.array([pos.getY()
for pos
in badPos]) - y0
325 zBad = np.array(badFits)
328 xRange = np.linspace(0, kernelCellSet.getBBox().getWidth(), num=numSample)
329 yRange = np.linspace(0, kernelCellSet.getBBox().getHeight(), num=numSample)
332 maxCoeff = min(maxCoeff, kernel.getNKernelParameters())
334 maxCoeff = kernel.getNKernelParameters()
336 for k
in range(maxCoeff):
337 func = kernel.getSpatialFunction(k)
338 dfGood = zGood[:, k] - np.array([func(pos.getX(), pos.getY())
for pos
in candPos])
342 dfBad = zBad[:, k] - np.array([func(pos.getX(), pos.getY())
for pos
in badPos])
344 yMin = min([yMin, dfBad.min()])
345 yMax = max([yMax, dfBad.max()])
346 yMin -= 0.05*(yMax - yMin)
347 yMax += 0.05*(yMax - yMin)
349 fRange = np.ndarray((len(xRange), len(yRange)))
350 for j, yVal
in enumerate(yRange):
351 for i, xVal
in enumerate(xRange):
352 fRange[j][i] = func(xVal, yVal)
358 fig.canvas._tkcanvas._root().lift()
362 fig.suptitle(
'Kernel component %d' % k)
365 ax = fig.add_axes((0.1, 0.05, 0.35, 0.35))
368 norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
369 im = ax.imshow(fRange, aspect=
'auto', norm=norm,
370 extent=[0, kernelCellSet.getBBox().getWidth() - 1,
371 0, kernelCellSet.getBBox().getHeight() - 1])
372 ax.set_title(
'Spatial polynomial')
373 plt.colorbar(im, orientation=
'horizontal', ticks=[vmin, vmax])
376 ax = fig.add_axes((0.1, 0.55, 0.35, 0.35))
377 ax.plot(-2.5*np.log10(candAmps), zGood[:, k],
'b+')
379 ax.plot(-2.5*np.log10(badAmps), zBad[:, k],
'r+')
380 ax.set_title(
"Basis Coefficients")
381 ax.set_xlabel(
"Instr mag")
382 ax.set_ylabel(
"Coeff")
385 ax = fig.add_axes((0.55, 0.05, 0.35, 0.35))
386 ax.set_autoscale_on(
False)
387 ax.set_xbound(lower=0, upper=kernelCellSet.getBBox().getHeight())
388 ax.set_ybound(lower=yMin, upper=yMax)
389 ax.plot(yGood, dfGood,
'b+')
391 ax.plot(yBad, dfBad,
'r+')
393 ax.set_title(
'dCoeff (indiv-spatial) vs. y')
396 ax = fig.add_axes((0.55, 0.55, 0.35, 0.35))
397 ax.set_autoscale_on(
False)
398 ax.set_xbound(lower=0, upper=kernelCellSet.getBBox().getWidth())
399 ax.set_ybound(lower=yMin, upper=yMax)
400 ax.plot(xGood, dfGood,
'b+')
402 ax.plot(xBad, dfBad,
'r+')
404 ax.set_title(
'dCoeff (indiv-spatial) vs. x')
409 if keepPlots
and not keptPlots:
412 print(
"%s: Please close plots when done." % __name__)
417 print(
"Plots closed, exiting...")
419 atexit.register(show)
424 """Plot the individual kernel candidate and the spatial kernel solution coefficients. 429 spatialKernel : `lsst.afw.math.LinearCombinationKernel` 430 The spatial spatialKernel solution model which is a spatially varying linear combination 431 of the spatialKernel basis functions. 432 Typically returned by `lsst.ip.diffim.SpatialKernelSolution.getSolutionPair()`. 434 kernelCellSet : `lsst.afw.math.SpatialCellSet` 435 The spatial cells that was used for solution for the spatialKernel. They contain the 436 local solutions of the AL kernel for the selected sources. 438 showBadCandidates : `bool`, optional 439 If True, plot the coefficient values for kernel candidates where the solution was marked 440 bad by the numerical algorithm. Defaults to False. 442 keepPlots: `bool`, optional 443 If True, sets ``plt.show()`` to be called before the task terminates, so that the plots 444 can be explored interactively. Defaults to True. 448 This function produces 3 figures per image subtraction operation. 449 * A grid plot of the local solutions. Each grid cell corresponds to a proportional area in 450 the image. In each cell, local kernel solution coefficients are plotted of kernel candidates (color) 451 that fall into this area as a function of the kernel basis function number. 452 * A grid plot of the spatial solution. Each grid cell corresponds to a proportional area in 453 the image. In each cell, the spatial solution coefficients are evaluated for the center of the cell. 454 * Histogram of the local solution coefficients. Red line marks the spatial solution value at 457 This function is called if ``lsst.ip.diffim.psfMatch.plotKernelCoefficients==True`` in lsstDebug. This 458 function was implemented as part of DM-17825. 461 import matplotlib.pyplot
as plt
462 except ImportError
as e:
463 print(
"Unable to import matplotlib: %s" % e)
467 imgBBox = kernelCellSet.getBBox()
468 x0 = imgBBox.getBeginX()
469 y0 = imgBBox.getBeginY()
470 wImage = imgBBox.getWidth()
471 hImage = imgBBox.getHeight()
472 imgCenterX = imgBBox.getCenterX()
473 imgCenterY = imgBBox.getCenterY()
485 fig.suptitle(
"Kernel candidate parameters on an image grid")
486 arrAx = fig.subplots(nrows=nY, ncols=nX, sharex=
True, sharey=
True, gridspec_kw=dict(
490 arrAx = arrAx[::-1, :]
493 for cell
in kernelCellSet.getCellList():
494 cellBBox = afwGeom.Box2D(cell.getBBox())
496 iX = int((cellBBox.getCenterX() - x0)//wCell)
497 iY = int((cellBBox.getCenterY() - y0)//hCell)
499 for cand
in cell.begin(
False):
501 kernel = cand.getKernel(cand.ORIG)
505 if not showBadCandidates
and cand.isBad():
508 nKernelParams = kernel.getNKernelParameters()
509 kernelParams = np.array(kernel.getKernelParameters())
510 allParams.append(kernelParams)
516 arrAx[iY, iX].plot(np.arange(nKernelParams), kernelParams,
'.-',
517 color=color, drawstyle=
'steps-mid', linewidth=0.1)
518 for ax
in arrAx.ravel():
519 ax.grid(
True, axis=
'y')
524 spatialFuncs = spatialKernel.getSpatialFunctionList()
525 nKernelParams = spatialKernel.getNKernelParameters()
528 fig.suptitle(
"Hist. of parameters marked with spatial solution at img center")
529 arrAx = fig.subplots(nrows=int(nKernelParams//nX)+1, ncols=nX)
530 arrAx = arrAx[::-1, :]
531 allParams = np.array(allParams)
532 for k
in range(nKernelParams):
533 ax = arrAx.ravel()[k]
534 ax.hist(allParams[:, k], bins=20, edgecolor=
'black')
535 ax.set_xlabel(
'P{}'.format(k))
536 valueParam = spatialFuncs[k](imgCenterX, imgCenterY)
537 ax.axvline(x=valueParam, color=
'red')
538 ax.text(0.1, 0.9,
'{:.1f}'.format(valueParam),
539 transform=ax.transAxes, backgroundcolor=
'lightsteelblue')
552 fig.suptitle(
"Spatial solution of kernel parameters on an image grid")
553 arrAx = fig.subplots(nrows=nY, ncols=nX, sharex=
True, sharey=
True, gridspec_kw=dict(
555 arrAx = arrAx[::-1, :]
556 kernelParams = np.zeros(nKernelParams, dtype=float)
563 kernelParams = [f(x, y)
for f
in spatialFuncs]
564 arrAx[iY, iX].plot(np.arange(nKernelParams), kernelParams,
'.-', drawstyle=
'steps-mid')
565 arrAx[iY, iX].grid(
True, axis=
'y')
568 if keepPlots
and not keptPlots:
571 print(
"%s: Please close plots when done." % __name__)
576 print(
"Plots closed, exiting...")
578 atexit.register(show)
583 showCenter=True, showEllipticity=True):
584 """Show a mosaic of Kernel images. 586 mos = afwDisplay.utils.Mosaic()
588 x0 = bbox.getBeginX()
589 y0 = bbox.getBeginY()
590 width = bbox.getWidth()
591 height = bbox.getHeight()
594 ny = int(nx*float(height)/width + 0.5)
598 schema = afwTable.SourceTable.makeMinimalSchema()
599 centroidName =
"base_SdssCentroid" 600 shapeName =
"base_SdssShape" 601 control = measBase.SdssCentroidControl()
602 schema.getAliasMap().set(
"slot_Centroid", centroidName)
603 schema.getAliasMap().set(
"slot_Centroid_flag", centroidName +
"_flag")
604 centroider = measBase.SdssCentroidAlgorithm(control, centroidName, schema)
605 sdssShape = measBase.SdssShapeControl()
606 shaper = measBase.SdssShapeAlgorithm(sdssShape, shapeName, schema)
607 table = afwTable.SourceTable.make(schema)
608 table.defineCentroid(centroidName)
609 table.defineShape(shapeName)
615 x = int(ix*(width - 1)/(nx - 1)) + x0
616 y = int(iy*(height - 1)/(ny - 1)) + y0
618 im = afwImage.ImageD(kernel.getDimensions())
619 ksum = kernel.computeImage(im,
False, x, y)
620 lab =
"Kernel(%d,%d)=%.2f" % (x, y, ksum)
if False else "" 626 w, h = im.getWidth(), im.getHeight()
627 centerX = im.getX0() + w//2
628 centerY = im.getY0() + h//2
629 src = table.makeRecord()
632 foot.addPeak(centerX, centerY, 1)
633 src.setFootprint(foot)
636 centroider.measure(src, exp)
637 centers.append((src.getX(), src.getY()))
639 shaper.measure(src, exp)
640 shapes.append((src.getIxx(), src.getIxy(), src.getIyy()))
644 mos.makeMosaic(frame=frame, title=title
if title
else "Model Kernel", mode=nx)
646 if centers
and frame
is not None:
647 disp = afwDisplay.Display(frame=frame)
649 with disp.Buffering():
650 for cen, shape
in zip(centers, shapes):
651 bbox = mos.getBBox(i)
653 xc, yc = cen[0] + bbox.getMinX(), cen[1] + bbox.getMinY()
655 disp.dot(
"+", xc, yc, ctype=afwDisplay.BLUE)
658 ixx, ixy, iyy = shape
659 disp.dot(
"@:%g,%g,%g" % (ixx, ixy, iyy), xc, yc, ctype=afwDisplay.RED)
665 kernel, background, testSources, config,
666 origVariance=False, nptsFull=1e6, keepPlots=True, titleFs=14):
667 """Plot diffim residuals for LOCAL and SPATIAL models. 673 for cell
in kernelCellSet.getCellList():
674 for cand
in cell.begin(
True):
676 if not (cand.getStatus() == afwMath.SpatialCellCandidate.GOOD):
679 diffim = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
680 orig = cand.getScienceMaskedImage()
682 ski = afwImage.ImageD(kernel.getDimensions())
683 kernel.computeImage(ski,
False, int(cand.getXCenter()), int(cand.getYCenter()))
685 sbg = background(int(cand.getXCenter()), int(cand.getYCenter()))
686 sdiffim = cand.getDifferenceImage(sk, sbg)
689 bbox = kernel.shrinkBBox(diffim.getBBox())
690 tdiffim = diffim.Factory(diffim, bbox)
691 torig = orig.Factory(orig, bbox)
692 tsdiffim = sdiffim.Factory(sdiffim, bbox)
695 candidateResids.append(np.ravel(tdiffim.getImage().getArray() /
696 np.sqrt(torig.getVariance().getArray())))
697 spatialResids.append(np.ravel(tsdiffim.getImage().getArray() /
698 np.sqrt(torig.getVariance().getArray())))
700 candidateResids.append(np.ravel(tdiffim.getImage().getArray() /
701 np.sqrt(tdiffim.getVariance().getArray())))
702 spatialResids.append(np.ravel(tsdiffim.getImage().getArray() /
703 np.sqrt(tsdiffim.getVariance().getArray())))
705 fullIm = diffExposure.getMaskedImage().getImage().getArray()
706 fullMask = diffExposure.getMaskedImage().getMask().getArray()
708 fullVar = exposure.getMaskedImage().getVariance().getArray()
710 fullVar = diffExposure.getMaskedImage().getVariance().getArray()
713 bitmaskBad |= afwImage.Mask.getPlaneBitMask(
'NO_DATA')
714 bitmaskBad |= afwImage.Mask.getPlaneBitMask(
'SAT')
715 idx = np.where((fullMask & bitmaskBad) == 0)
716 stride = int(len(idx[0])//nptsFull)
717 sidx = idx[0][::stride], idx[1][::stride]
718 allResids = fullIm[sidx]/np.sqrt(fullVar[sidx])
720 testFootprints = diffimTools.sourceToFootprintList(testSources, warpedTemplateExposure,
721 exposure, config, Log.getDefaultLogger())
722 for fp
in testFootprints:
723 subexp = diffExposure.Factory(diffExposure, fp[
"footprint"].getBBox())
724 subim = subexp.getMaskedImage().getImage()
726 subvar = afwImage.ExposureF(exposure, fp[
"footprint"].getBBox()).getMaskedImage().getVariance()
728 subvar = subexp.getMaskedImage().getVariance()
729 nonfitResids.append(np.ravel(subim.getArray()/np.sqrt(subvar.getArray())))
731 candidateResids = np.ravel(np.array(candidateResids))
732 spatialResids = np.ravel(np.array(spatialResids))
733 nonfitResids = np.ravel(np.array(nonfitResids))
737 from matplotlib.font_manager
import FontProperties
738 except ImportError
as e:
739 print(
"Unable to import pylab: %s" % e)
745 fig.canvas._tkcanvas._root().lift()
749 fig.suptitle(
"Diffim residuals: Normalized by sqrt(input variance)", fontsize=titleFs)
751 fig.suptitle(
"Diffim residuals: Normalized by sqrt(diffim variance)", fontsize=titleFs)
753 sp1 = pylab.subplot(221)
754 sp2 = pylab.subplot(222, sharex=sp1, sharey=sp1)
755 sp3 = pylab.subplot(223, sharex=sp1, sharey=sp1)
756 sp4 = pylab.subplot(224, sharex=sp1, sharey=sp1)
757 xs = np.arange(-5, 5.05, 0.1)
758 ys = 1./np.sqrt(2*np.pi)*np.exp(-0.5*xs**2)
760 sp1.hist(candidateResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 761 % (np.mean(candidateResids), np.var(candidateResids)))
762 sp1.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
763 sp1.set_title(
"Candidates: basis fit", fontsize=titleFs - 2)
764 sp1.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
766 sp2.hist(spatialResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 767 % (np.mean(spatialResids), np.var(spatialResids)))
768 sp2.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
769 sp2.set_title(
"Candidates: spatial fit", fontsize=titleFs - 2)
770 sp2.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
772 sp3.hist(nonfitResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 773 % (np.mean(nonfitResids), np.var(nonfitResids)))
774 sp3.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
775 sp3.set_title(
"Control sample: spatial fit", fontsize=titleFs - 2)
776 sp3.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
778 sp4.hist(allResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 779 % (np.mean(allResids), np.var(allResids)))
780 sp4.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
781 sp4.set_title(
"Full image (subsampled)", fontsize=titleFs - 2)
782 sp4.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
784 pylab.setp(sp1.get_xticklabels() + sp1.get_yticklabels(), fontsize=titleFs - 4)
785 pylab.setp(sp2.get_xticklabels() + sp2.get_yticklabels(), fontsize=titleFs - 4)
786 pylab.setp(sp3.get_xticklabels() + sp3.get_yticklabels(), fontsize=titleFs - 4)
787 pylab.setp(sp4.get_xticklabels() + sp4.get_yticklabels(), fontsize=titleFs - 4)
794 if keepPlots
and not keptPlots:
797 print(
"%s: Please close plots when done." % __name__)
802 print(
"Plots closed, exiting...")
804 atexit.register(show)
809 """Calculate first moment of a (kernel) image. 813 xarr = np.asarray([[el
for el
in range(x)]
for el2
in range(y)])
814 yarr = np.asarray([[el2
for el
in range(x)]
for el2
in range(y)])
817 centx = narr.sum()/sarrSum
819 centy = narr.sum()/sarrSum
824 """Calculate second moment of a (kernel) image. 829 xarr = np.asarray([[el
for el
in range(x)]
for el2
in range(y)])
830 yarr = np.asarray([[el2
for el
in range(x)]
for el2
in range(y)])
831 narr = sarr*np.power((xarr - centx), 2.)
833 xstd = np.sqrt(narr.sum()/sarrSum)
834 narr = sarr*np.power((yarr - centy), 2.)
835 ystd = np.sqrt(narr.sum()/sarrSum)
840 """Print differences in sky coordinates. 842 The difference is that between the source Position and its Centroid mapped 846 sCentroid = s.getCentroid()
847 sPosition = s.getCoord().getPosition(afwGeom.degrees)
848 dra = 3600*(sPosition.getX() - wcs.pixelToSky(sCentroid).getPosition(afwGeom.degrees).getX())/0.2
849 ddec = 3600*(sPosition.getY() - wcs.pixelToSky(sCentroid).getPosition(afwGeom.degrees).getY())/0.2
850 if np.isfinite(dra)
and np.isfinite(ddec):
855 """Create regions file for display from input source list. 857 fh = open(outfilename,
"w")
858 fh.write(
"global color=red font=\"helvetica 10 normal\" " 859 "select=1 highlite=1 edit=1 move=1 delete=1 include=1 fixed=0 source\nfk5\n")
862 (ra, dec) = wcs.pixelToSky(s.getCentroid()).getPosition(afwGeom.degrees)
864 (ra, dec) = s.getCoord().getPosition(afwGeom.degrees)
865 if np.isfinite(ra)
and np.isfinite(dec):
866 fh.write(
"circle(%f,%f,2\")\n"%(ra, dec))
872 """Draw the (RA, Dec) positions of a set of Sources. Image has the XY0. 874 disp = afwDisplay.Display(frame=frame)
875 with disp.Buffering():
877 (xc, yc) = wcs.skyToPixel(s.getCoord().getRa(), s.getCoord().getDec())
880 disp.dot(symb, xc, yc, ctype=ctype, size=size)
884 """Plot whisker diagram of astromeric offsets between results.matches. 886 refCoordKey = results.matches[0].first.getTable().getCoordKey()
887 inCentroidKey = results.matches[0].second.getTable().getCentroidKey()
888 positions = [m.first.get(refCoordKey)
for m
in results.matches]
889 residuals = [m.first.get(refCoordKey).getOffsetFrom(
890 newWcs.pixelToSky(m.second.get(inCentroidKey)))
for 891 m
in results.matches]
892 import matplotlib.pyplot
as plt
894 sp = fig.add_subplot(1, 1, 0)
895 xpos = [x[0].asDegrees()
for x
in positions]
896 ypos = [x[1].asDegrees()
for x
in positions]
897 xpos.append(0.02*(max(xpos) - min(xpos)) + min(xpos))
898 ypos.append(0.98*(max(ypos) - min(ypos)) + min(ypos))
899 xidxs = np.isfinite(xpos)
900 yidxs = np.isfinite(ypos)
901 X = np.asarray(xpos)[xidxs]
902 Y = np.asarray(ypos)[yidxs]
903 distance = [x[1].asArcseconds()
for x
in residuals]
905 distance = np.asarray(distance)[xidxs]
908 bearing = [x[0].asRadians()
for x
in residuals]
910 bearing = np.asarray(bearing)[xidxs]
911 U = (distance*np.cos(bearing))
912 V = (distance*np.sin(bearing))
913 sp.quiver(X, Y, U, V)
914 sp.set_title(
"WCS Residual")
919 """Utility class for dipole measurement testing. 921 Generate an image with simulated dipoles and noise; store the original 922 "pre-subtraction" images and catalogs as well. 923 Used to generate test data for DMTN-007 (http://dmtn-007.lsst.io). 926 def __init__(self, w=101, h=101, xcenPos=[27.], ycenPos=[25.], xcenNeg=[23.], ycenNeg=[25.],
927 psfSigma=2., flux=[30000.], fluxNeg=None, noise=10., gradientParams=None):
943 def _makeDipoleImage(self):
944 """Generate an exposure and catalog with the given dipole source(s). 953 dipole = posImage.clone()
954 di = dipole.getMaskedImage()
955 di -= negImage.getMaskedImage()
959 posDetectedBits = posImage.getMaskedImage().getMask().getArray() == dm.getPlaneBitMask(
"DETECTED")
960 negDetectedBits = negImage.getMaskedImage().getMask().getArray() == dm.getPlaneBitMask(
"DETECTED")
961 pos_det = dm.addMaskPlane(
"DETECTED_POS")
962 neg_det = dm.addMaskPlane(
"DETECTED_NEG")
965 dma[:, :] = posDetectedBits*pos_det + negDetectedBits*neg_det
966 self.diffim, self.posImage, self.posCatalog, self.negImage, self.negCatalog \
967 = dipole, posImage, posCatalog, negImage, negCatalog
969 def _makeStarImage(self, xc=[15.3], yc=[18.6], flux=[2500], schema=None, randomSeed=None):
970 """Generate an exposure and catalog with the given stellar source(s). 973 bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(self.
w - 1, self.
h - 1))
974 dataset = TestDataset(bbox, psfSigma=self.
psfSigma, threshold=1.)
976 for i
in range(len(xc)):
977 dataset.addSource(instFlux=flux[i], centroid=afwGeom.Point2D(xc[i], yc[i]))
980 schema = TestDataset.makeMinimalSchema()
981 exposure, catalog = dataset.realize(noise=self.
noise, schema=schema, randomSeed=randomSeed)
984 y, x = np.mgrid[:self.
w, :self.
h]
986 gradient = gp[0] + gp[1]*x + gp[2]*y
988 gradient += gp[3]*x*y + gp[4]*x*x + gp[5]*y*y
989 imgArr = exposure.getMaskedImage().getArrays()[0]
992 return exposure, catalog
996 fitResult = alg.fitDipole(source, **kwds)
1000 """Utility function for detecting dipoles. 1002 Detect pos/neg sources in the diffim, then merge them. A 1003 bigger "grow" parameter leads to a larger footprint which 1004 helps with dipole measurement for faint dipoles. 1009 Whether to merge the positive and negagive detections into a single 1011 diffim : `lsst.afw.image.exposure.exposure.ExposureF` 1012 Difference image on which to perform detection. 1013 detectSigma : `float` 1014 Threshold for object detection. 1016 Number of pixels to grow the footprints before merging. 1018 Minimum bin size for the background (re)estimation (only applies if 1019 the default leads to min(nBinX, nBinY) < fit order so the default 1020 config parameter needs to be decreased, but not to a value smaller 1021 than ``minBinSize``, in which case the fitting algorithm will take 1022 over and decrease the fit order appropriately.) 1026 sources : `lsst.afw.table.SourceCatalog` 1027 If doMerge=True, the merged source catalog is returned OR 1028 detectTask : `lsst.meas.algorithms.SourceDetectionTask` 1029 schema : `lsst.afw.table.Schema` 1030 If doMerge=False, the source detection task and its schema are 1034 diffim = self.diffim
1037 schema = afwTable.SourceTable.makeMinimalSchema()
1040 detectConfig = measAlg.SourceDetectionConfig()
1041 detectConfig.returnOriginalFootprints =
False 1043 psfSigma = diffim.getPsf().computeShape().getDeterminantRadius()
1046 detectConfig.thresholdPolarity =
"both" 1047 detectConfig.thresholdValue = detectSigma
1049 detectConfig.reEstimateBackground =
True 1050 detectConfig.thresholdType =
"pixel_stdev" 1052 while ((min(diffim.getWidth(), diffim.getHeight()))//detectConfig.background.binSize <
1053 detectConfig.background.approxOrderX
and detectConfig.background.binSize > minBinSize):
1054 detectConfig.background.binSize = max(minBinSize, detectConfig.background.binSize//2)
1057 detectTask = measAlg.SourceDetectionTask(schema, config=detectConfig)
1059 table = afwTable.SourceTable.make(schema)
1060 catalog = detectTask.makeSourceCatalog(table, diffim, sigma=psfSigma)
1064 fpSet = catalog.fpSets.positive
1065 fpSet.merge(catalog.fpSets.negative, grow, grow,
False)
1066 sources = afwTable.SourceCatalog(table)
1067 fpSet.makeSources(sources)
1072 return detectTask, schema
def _makeDipoleImage(self)
def showDiaSources(sources, exposure, isFlagged, isDipole, frame=None)
def plotKernelCoefficients(spatialKernel, kernelCellSet, showBadCandidates=False, keepPlots=True)
def makeRegions(sources, outfilename, wcs=None)
def __init__(self, w=101, h=101, xcenPos=[27.], ycenPos=[25.], xcenNeg=[23.], ycenNeg=[25.], psfSigma=2., flux=[30000.], fluxNeg=None, noise=10., gradientParams=None)
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename std::shared_ptr< Image< ImagePixelT >> image, typename std::shared_ptr< Mask< MaskPixelT >> mask=Mask< MaskPixelT >(), typename std::shared_ptr< Image< VariancePixelT >> variance=Image< VariancePixelT >())
def showKernelSpatialCells(maskedIm, kernelCellSet, showChi2=False, symb="o", ctype=None, ctypeUnused=None, ctypeBad=None, size=3, frame=None, title="Spatial Cells")
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
def _makeStarImage(self, xc=[15.3], yc=[18.6], flux=[2500], schema=None, randomSeed=None)
def plotKernelSpatialModel(kernel, kernelCellSet, showBadCandidates=True, numSample=128, keepPlots=True, maxCoeff=10)
def plotPixelResiduals(exposure, warpedTemplateExposure, diffExposure, kernelCellSet, kernel, background, testSources, config, origVariance=False, nptsFull=1e6, keepPlots=True, titleFs=14)
def printSkyDiffs(sources, wcs)
def showKernelCandidates(kernelCellSet, kernel, background, frame=None, showBadCandidates=True, resids=False, kernels=False)
def detectDipoleSources(self, doMerge=True, diffim=None, detectSigma=5.5, grow=3, minBinSize=32)
def calcWidth(arr, centx, centy)
def showSourceSet(sSet, xy0=(0, 0), frame=0, ctype=afwDisplay.GREEN, symb="+", size=2)
def plotWhisker(results, newWcs)
def showKernelMosaic(bbox, kernel, nx=7, ny=None, frame=None, title=None, showCenter=True, showEllipticity=True)
def showKernelBasis(kernel, frame=None)
def fitDipoleSource(self, source, kwds)
def showSourceSetSky(sSet, wcs, xy0, frame=0, ctype=afwDisplay.GREEN, symb="+", size=2)