22 """Support utilities for Measuring sources""" 25 __all__ = [
"DipoleTestImage"]
37 import lsst.meas.algorithms
as measAlg
39 from .dipoleFitTask
import DipoleFitAlgorithm
40 from .
import diffimLib
41 from .
import diffimTools
43 afwDisplay.setDefaultMaskTransparency(75)
47 def showSourceSet(sSet, xy0=(0, 0), frame=0, ctype=afwDisplay.GREEN, symb=
"+", size=2):
48 """Draw the (XAstrom, YAstrom) positions of a set of Sources. 50 Image has the given XY0. 52 disp = afwDisplay.afwDisplay(frame=frame)
53 with disp.Buffering():
55 xc, yc = s.getXAstrom() - xy0[0], s.getYAstrom() - xy0[1]
58 disp.dot(str(s.getId()), xc, yc, ctype=ctype, size=size)
60 disp.dot(symb, xc, yc, ctype=ctype, size=size)
68 ctype=None, ctypeUnused=None, ctypeBad=None, size=3,
69 frame=None, title="Spatial Cells"):
70 """Show the SpatialCells. 72 If symb is something that display.dot understands (e.g. "o"), the top 73 nMaxPerCell candidates will be indicated with that symbol, using ctype 76 disp = afwDisplay.Display(frame=frame)
77 disp.mtv(maskedIm, title=title)
78 with disp.Buffering():
79 origin = [-maskedIm.getX0(), -maskedIm.getY0()]
80 for cell
in kernelCellSet.getCellList():
81 afwDisplay.utils.drawBBox(cell.getBBox(), origin=origin, display=disp)
83 goodies = ctypeBad
is None 84 for cand
in cell.begin(goodies):
85 xc, yc = cand.getXCenter() + origin[0], cand.getYCenter() + origin[1]
86 if cand.getStatus() == afwMath.SpatialCellCandidate.BAD:
88 elif cand.getStatus() == afwMath.SpatialCellCandidate.GOOD:
90 elif cand.getStatus() == afwMath.SpatialCellCandidate.UNKNOWN:
96 disp.dot(symb, xc, yc, ctype=color, size=size)
99 rchi2 = cand.getChi2()
102 disp.dot(
"%d %.1f" % (cand.getId(), rchi2),
103 xc - size, yc - size - 4, ctype=color, size=size)
107 """Display Dia Sources. 113 disp = afwDisplay.Display(frame=frame)
114 for plane
in (
"BAD",
"CR",
"EDGE",
"INTERPOlATED",
"INTRP",
"SAT",
"SATURATED"):
115 disp.setMaskPlaneColor(plane, color=
"ignore")
117 mos = afwDisplay.utils.Mosaic()
118 for i
in range(len(sources)):
120 badFlag = isFlagged[i]
121 dipoleFlag = isDipole[i]
122 bbox = source.getFootprint().getBBox()
123 stamp = exposure.Factory(exposure, bbox,
True)
124 im = afwDisplay.utils.Mosaic(gutter=1, background=0, mode=
"x")
125 im.append(stamp.getMaskedImage())
126 lab =
"%.1f,%.1f:" % (source.getX(), source.getY())
128 ctype = afwDisplay.RED
131 ctype = afwDisplay.YELLOW
133 if not badFlag
and not dipoleFlag:
134 ctype = afwDisplay.GREEN
136 mos.append(im.makeMosaic(), lab, ctype)
137 title =
"Dia Sources" 138 mosaicImage = mos.makeMosaic(frame=frame, title=title)
143 resids=False, kernels=False):
144 """Display the Kernel candidates. 146 If kernel is provided include spatial model and residuals; 147 If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi. 153 mos = afwDisplay.utils.Mosaic(gutter=5, background=0)
155 mos = afwDisplay.utils.Mosaic(gutter=5, background=-1)
157 candidateCenters = []
158 candidateCentersBad = []
160 for cell
in kernelCellSet.getCellList():
161 for cand
in cell.begin(
False):
164 resid = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
168 rchi2 = cand.getChi2()
172 if not showBadCandidates
and cand.isBad():
175 im_resid = afwDisplay.utils.Mosaic(gutter=1, background=-0.5, mode=
"x")
178 im = cand.getScienceMaskedImage()
179 im = im.Factory(im,
True)
180 im.setXY0(cand.getScienceMaskedImage().getXY0())
183 if (
not resids
and not kernels):
184 im_resid.append(im.Factory(im,
True))
186 im = cand.getTemplateMaskedImage()
187 im = im.Factory(im,
True)
188 im.setXY0(cand.getTemplateMaskedImage().getXY0())
191 if (
not resids
and not kernels):
192 im_resid.append(im.Factory(im,
True))
196 var = resid.getVariance()
197 var = var.Factory(var,
True)
198 np.sqrt(var.getArray(), var.getArray())
199 resid = resid.getImage()
201 bbox = kernel.shrinkBBox(resid.getBBox())
202 resid = resid.Factory(resid, bbox, deep=
True)
204 kim = cand.getKernelImage(diffimLib.KernelCandidateF.ORIG).convertF()
205 resid = kim.Factory(kim,
True)
206 im_resid.append(resid)
209 ski = afwImage.ImageD(kernel.getDimensions())
210 kernel.computeImage(ski,
False, int(cand.getXCenter()), int(cand.getYCenter()))
214 sbg = background(int(cand.getXCenter()), int(cand.getYCenter()))
215 sresid = cand.getDifferenceImage(sk, sbg)
218 resid = sresid.getImage()
220 bbox = kernel.shrinkBBox(resid.getBBox())
221 resid = resid.Factory(resid, bbox, deep=
True)
224 resid = kim.Factory(kim,
True)
225 im_resid.append(resid)
227 im = im_resid.makeMosaic()
229 lab =
"%d chi^2 %.1f" % (cand.getId(), rchi2)
230 ctype = afwDisplay.RED
if cand.isBad()
else afwDisplay.GREEN
232 mos.append(im, lab, ctype)
234 if False and np.isnan(rchi2):
235 disp = afwDisplay.Display(frame=1)
236 disp.mtv(cand.getScienceMaskedImage.getImage(), title=
"candidate")
237 print(
"rating", cand.getCandidateRating())
239 im = cand.getScienceMaskedImage()
240 center = (candidateIndex, cand.getXCenter() - im.getX0(), cand.getYCenter() - im.getY0())
243 candidateCentersBad.append(center)
245 candidateCenters.append(center)
252 title =
"Candidates & residuals" 253 mosaicImage = mos.makeMosaic(frame=frame, title=title)
259 """Display a Kernel's basis images. 261 mos = afwDisplay.utils.Mosaic()
263 for k
in kernel.getKernelList():
264 im = afwImage.ImageD(k.getDimensions())
265 k.computeImage(im,
False)
267 mos.makeMosaic(frame=frame, title=
"Kernel Basis Images")
275 numSample=128, keepPlots=True, maxCoeff=10):
276 """Plot the Kernel spatial model. 279 import matplotlib.pyplot
as plt
280 import matplotlib.colors
281 except ImportError
as e:
282 print(
"Unable to import numpy and matplotlib: %s" % e)
285 x0 = kernelCellSet.getBBox().getBeginX()
286 y0 = kernelCellSet.getBBox().getBeginY()
294 for cell
in kernelCellSet.getCellList():
295 for cand
in cell.begin(
False):
296 if not showBadCandidates
and cand.isBad():
298 candCenter =
geom.PointD(cand.getXCenter(), cand.getYCenter())
300 im = cand.getTemplateMaskedImage()
304 targetFits = badFits
if cand.isBad()
else candFits
305 targetPos = badPos
if cand.isBad()
else candPos
306 targetAmps = badAmps
if cand.isBad()
else candAmps
309 kp0 = np.array(cand.getKernel(diffimLib.KernelCandidateF.ORIG).getKernelParameters())
310 amp = cand.getCandidateRating()
312 targetFits = badFits
if cand.isBad()
else candFits
313 targetPos = badPos
if cand.isBad()
else candPos
314 targetAmps = badAmps
if cand.isBad()
else candAmps
316 targetFits.append(kp0)
317 targetPos.append(candCenter)
318 targetAmps.append(amp)
320 xGood = np.array([pos.getX()
for pos
in candPos]) - x0
321 yGood = np.array([pos.getY()
for pos
in candPos]) - y0
322 zGood = np.array(candFits)
324 xBad = np.array([pos.getX()
for pos
in badPos]) - x0
325 yBad = np.array([pos.getY()
for pos
in badPos]) - y0
326 zBad = np.array(badFits)
329 xRange = np.linspace(0, kernelCellSet.getBBox().getWidth(), num=numSample)
330 yRange = np.linspace(0, kernelCellSet.getBBox().getHeight(), num=numSample)
333 maxCoeff = min(maxCoeff, kernel.getNKernelParameters())
335 maxCoeff = kernel.getNKernelParameters()
337 for k
in range(maxCoeff):
338 func = kernel.getSpatialFunction(k)
339 dfGood = zGood[:, k] - np.array([func(pos.getX(), pos.getY())
for pos
in candPos])
343 dfBad = zBad[:, k] - np.array([func(pos.getX(), pos.getY())
for pos
in badPos])
345 yMin = min([yMin, dfBad.min()])
346 yMax = max([yMax, dfBad.max()])
347 yMin -= 0.05*(yMax - yMin)
348 yMax += 0.05*(yMax - yMin)
350 fRange = np.ndarray((len(xRange), len(yRange)))
351 for j, yVal
in enumerate(yRange):
352 for i, xVal
in enumerate(xRange):
353 fRange[j][i] = func(xVal, yVal)
359 fig.canvas._tkcanvas._root().lift()
363 fig.suptitle(
'Kernel component %d' % k)
366 ax = fig.add_axes((0.1, 0.05, 0.35, 0.35))
369 norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
370 im = ax.imshow(fRange, aspect=
'auto', norm=norm,
371 extent=[0, kernelCellSet.getBBox().getWidth() - 1,
372 0, kernelCellSet.getBBox().getHeight() - 1])
373 ax.set_title(
'Spatial polynomial')
374 plt.colorbar(im, orientation=
'horizontal', ticks=[vmin, vmax])
377 ax = fig.add_axes((0.1, 0.55, 0.35, 0.35))
378 ax.plot(-2.5*np.log10(candAmps), zGood[:, k],
'b+')
380 ax.plot(-2.5*np.log10(badAmps), zBad[:, k],
'r+')
381 ax.set_title(
"Basis Coefficients")
382 ax.set_xlabel(
"Instr mag")
383 ax.set_ylabel(
"Coeff")
386 ax = fig.add_axes((0.55, 0.05, 0.35, 0.35))
387 ax.set_autoscale_on(
False)
388 ax.set_xbound(lower=0, upper=kernelCellSet.getBBox().getHeight())
389 ax.set_ybound(lower=yMin, upper=yMax)
390 ax.plot(yGood, dfGood,
'b+')
392 ax.plot(yBad, dfBad,
'r+')
394 ax.set_title(
'dCoeff (indiv-spatial) vs. y')
397 ax = fig.add_axes((0.55, 0.55, 0.35, 0.35))
398 ax.set_autoscale_on(
False)
399 ax.set_xbound(lower=0, upper=kernelCellSet.getBBox().getWidth())
400 ax.set_ybound(lower=yMin, upper=yMax)
401 ax.plot(xGood, dfGood,
'b+')
403 ax.plot(xBad, dfBad,
'r+')
405 ax.set_title(
'dCoeff (indiv-spatial) vs. x')
410 if keepPlots
and not keptPlots:
413 print(
"%s: Please close plots when done." % __name__)
418 print(
"Plots closed, exiting...")
420 atexit.register(show)
425 """Plot the individual kernel candidate and the spatial kernel solution coefficients. 430 spatialKernel : `lsst.afw.math.LinearCombinationKernel` 431 The spatial spatialKernel solution model which is a spatially varying linear combination 432 of the spatialKernel basis functions. 433 Typically returned by `lsst.ip.diffim.SpatialKernelSolution.getSolutionPair()`. 435 kernelCellSet : `lsst.afw.math.SpatialCellSet` 436 The spatial cells that was used for solution for the spatialKernel. They contain the 437 local solutions of the AL kernel for the selected sources. 439 showBadCandidates : `bool`, optional 440 If True, plot the coefficient values for kernel candidates where the solution was marked 441 bad by the numerical algorithm. Defaults to False. 443 keepPlots: `bool`, optional 444 If True, sets ``plt.show()`` to be called before the task terminates, so that the plots 445 can be explored interactively. Defaults to True. 449 This function produces 3 figures per image subtraction operation. 450 * A grid plot of the local solutions. Each grid cell corresponds to a proportional area in 451 the image. In each cell, local kernel solution coefficients are plotted of kernel candidates (color) 452 that fall into this area as a function of the kernel basis function number. 453 * A grid plot of the spatial solution. Each grid cell corresponds to a proportional area in 454 the image. In each cell, the spatial solution coefficients are evaluated for the center of the cell. 455 * Histogram of the local solution coefficients. Red line marks the spatial solution value at 458 This function is called if ``lsst.ip.diffim.psfMatch.plotKernelCoefficients==True`` in lsstDebug. This 459 function was implemented as part of DM-17825. 462 import matplotlib.pyplot
as plt
463 except ImportError
as e:
464 print(
"Unable to import matplotlib: %s" % e)
468 imgBBox = kernelCellSet.getBBox()
469 x0 = imgBBox.getBeginX()
470 y0 = imgBBox.getBeginY()
471 wImage = imgBBox.getWidth()
472 hImage = imgBBox.getHeight()
473 imgCenterX = imgBBox.getCenterX()
474 imgCenterY = imgBBox.getCenterY()
486 fig.suptitle(
"Kernel candidate parameters on an image grid")
487 arrAx = fig.subplots(nrows=nY, ncols=nX, sharex=
True, sharey=
True, gridspec_kw=dict(
491 arrAx = arrAx[::-1, :]
494 for cell
in kernelCellSet.getCellList():
495 cellBBox = afwGeom.Box2D(cell.getBBox())
497 iX = int((cellBBox.getCenterX() - x0)//wCell)
498 iY = int((cellBBox.getCenterY() - y0)//hCell)
500 for cand
in cell.begin(
False):
502 kernel = cand.getKernel(cand.ORIG)
506 if not showBadCandidates
and cand.isBad():
509 nKernelParams = kernel.getNKernelParameters()
510 kernelParams = np.array(kernel.getKernelParameters())
511 allParams.append(kernelParams)
517 arrAx[iY, iX].plot(np.arange(nKernelParams), kernelParams,
'.-',
518 color=color, drawstyle=
'steps-mid', linewidth=0.1)
519 for ax
in arrAx.ravel():
520 ax.grid(
True, axis=
'y')
525 spatialFuncs = spatialKernel.getSpatialFunctionList()
526 nKernelParams = spatialKernel.getNKernelParameters()
529 fig.suptitle(
"Hist. of parameters marked with spatial solution at img center")
530 arrAx = fig.subplots(nrows=int(nKernelParams//nX)+1, ncols=nX)
531 arrAx = arrAx[::-1, :]
532 allParams = np.array(allParams)
533 for k
in range(nKernelParams):
534 ax = arrAx.ravel()[k]
535 ax.hist(allParams[:, k], bins=20, edgecolor=
'black')
536 ax.set_xlabel(
'P{}'.format(k))
537 valueParam = spatialFuncs[k](imgCenterX, imgCenterY)
538 ax.axvline(x=valueParam, color=
'red')
539 ax.text(0.1, 0.9,
'{:.1f}'.format(valueParam),
540 transform=ax.transAxes, backgroundcolor=
'lightsteelblue')
553 fig.suptitle(
"Spatial solution of kernel parameters on an image grid")
554 arrAx = fig.subplots(nrows=nY, ncols=nX, sharex=
True, sharey=
True, gridspec_kw=dict(
556 arrAx = arrAx[::-1, :]
557 kernelParams = np.zeros(nKernelParams, dtype=float)
564 kernelParams = [f(x, y)
for f
in spatialFuncs]
565 arrAx[iY, iX].plot(np.arange(nKernelParams), kernelParams,
'.-', drawstyle=
'steps-mid')
566 arrAx[iY, iX].grid(
True, axis=
'y')
569 if keepPlots
and not keptPlots:
572 print(
"%s: Please close plots when done." % __name__)
577 print(
"Plots closed, exiting...")
579 atexit.register(show)
584 showCenter=True, showEllipticity=True):
585 """Show a mosaic of Kernel images. 587 mos = afwDisplay.utils.Mosaic()
589 x0 = bbox.getBeginX()
590 y0 = bbox.getBeginY()
591 width = bbox.getWidth()
592 height = bbox.getHeight()
595 ny = int(nx*float(height)/width + 0.5)
599 schema = afwTable.SourceTable.makeMinimalSchema()
600 centroidName =
"base_SdssCentroid" 601 shapeName =
"base_SdssShape" 602 control = measBase.SdssCentroidControl()
603 schema.getAliasMap().set(
"slot_Centroid", centroidName)
604 schema.getAliasMap().set(
"slot_Centroid_flag", centroidName +
"_flag")
605 centroider = measBase.SdssCentroidAlgorithm(control, centroidName, schema)
606 sdssShape = measBase.SdssShapeControl()
607 shaper = measBase.SdssShapeAlgorithm(sdssShape, shapeName, schema)
608 table = afwTable.SourceTable.make(schema)
609 table.defineCentroid(centroidName)
610 table.defineShape(shapeName)
616 x = int(ix*(width - 1)/(nx - 1)) + x0
617 y = int(iy*(height - 1)/(ny - 1)) + y0
619 im = afwImage.ImageD(kernel.getDimensions())
620 ksum = kernel.computeImage(im,
False, x, y)
621 lab =
"Kernel(%d,%d)=%.2f" % (x, y, ksum)
if False else "" 627 w, h = im.getWidth(), im.getHeight()
628 centerX = im.getX0() + w//2
629 centerY = im.getY0() + h//2
630 src = table.makeRecord()
633 foot.addPeak(centerX, centerY, 1)
634 src.setFootprint(foot)
637 centroider.measure(src, exp)
638 centers.append((src.getX(), src.getY()))
640 shaper.measure(src, exp)
641 shapes.append((src.getIxx(), src.getIxy(), src.getIyy()))
645 mos.makeMosaic(frame=frame, title=title
if title
else "Model Kernel", mode=nx)
647 if centers
and frame
is not None:
648 disp = afwDisplay.Display(frame=frame)
650 with disp.Buffering():
651 for cen, shape
in zip(centers, shapes):
652 bbox = mos.getBBox(i)
654 xc, yc = cen[0] + bbox.getMinX(), cen[1] + bbox.getMinY()
656 disp.dot(
"+", xc, yc, ctype=afwDisplay.BLUE)
659 ixx, ixy, iyy = shape
660 disp.dot(
"@:%g,%g,%g" % (ixx, ixy, iyy), xc, yc, ctype=afwDisplay.RED)
666 kernel, background, testSources, config,
667 origVariance=False, nptsFull=1e6, keepPlots=True, titleFs=14):
668 """Plot diffim residuals for LOCAL and SPATIAL models. 674 for cell
in kernelCellSet.getCellList():
675 for cand
in cell.begin(
True):
677 if not (cand.getStatus() == afwMath.SpatialCellCandidate.GOOD):
680 diffim = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG)
681 orig = cand.getScienceMaskedImage()
683 ski = afwImage.ImageD(kernel.getDimensions())
684 kernel.computeImage(ski,
False, int(cand.getXCenter()), int(cand.getYCenter()))
686 sbg = background(int(cand.getXCenter()), int(cand.getYCenter()))
687 sdiffim = cand.getDifferenceImage(sk, sbg)
690 bbox = kernel.shrinkBBox(diffim.getBBox())
691 tdiffim = diffim.Factory(diffim, bbox)
692 torig = orig.Factory(orig, bbox)
693 tsdiffim = sdiffim.Factory(sdiffim, bbox)
696 candidateResids.append(np.ravel(tdiffim.getImage().getArray() /
697 np.sqrt(torig.getVariance().getArray())))
698 spatialResids.append(np.ravel(tsdiffim.getImage().getArray() /
699 np.sqrt(torig.getVariance().getArray())))
701 candidateResids.append(np.ravel(tdiffim.getImage().getArray() /
702 np.sqrt(tdiffim.getVariance().getArray())))
703 spatialResids.append(np.ravel(tsdiffim.getImage().getArray() /
704 np.sqrt(tsdiffim.getVariance().getArray())))
706 fullIm = diffExposure.getMaskedImage().getImage().getArray()
707 fullMask = diffExposure.getMaskedImage().getMask().getArray()
709 fullVar = exposure.getMaskedImage().getVariance().getArray()
711 fullVar = diffExposure.getMaskedImage().getVariance().getArray()
714 bitmaskBad |= afwImage.Mask.getPlaneBitMask(
'NO_DATA')
715 bitmaskBad |= afwImage.Mask.getPlaneBitMask(
'SAT')
716 idx = np.where((fullMask & bitmaskBad) == 0)
717 stride = int(len(idx[0])//nptsFull)
718 sidx = idx[0][::stride], idx[1][::stride]
719 allResids = fullIm[sidx]/np.sqrt(fullVar[sidx])
721 testFootprints = diffimTools.sourceToFootprintList(testSources, warpedTemplateExposure,
722 exposure, config, Log.getDefaultLogger())
723 for fp
in testFootprints:
724 subexp = diffExposure.Factory(diffExposure, fp[
"footprint"].getBBox())
725 subim = subexp.getMaskedImage().getImage()
727 subvar = afwImage.ExposureF(exposure, fp[
"footprint"].getBBox()).getMaskedImage().getVariance()
729 subvar = subexp.getMaskedImage().getVariance()
730 nonfitResids.append(np.ravel(subim.getArray()/np.sqrt(subvar.getArray())))
732 candidateResids = np.ravel(np.array(candidateResids))
733 spatialResids = np.ravel(np.array(spatialResids))
734 nonfitResids = np.ravel(np.array(nonfitResids))
738 from matplotlib.font_manager
import FontProperties
739 except ImportError
as e:
740 print(
"Unable to import pylab: %s" % e)
746 fig.canvas._tkcanvas._root().lift()
750 fig.suptitle(
"Diffim residuals: Normalized by sqrt(input variance)", fontsize=titleFs)
752 fig.suptitle(
"Diffim residuals: Normalized by sqrt(diffim variance)", fontsize=titleFs)
754 sp1 = pylab.subplot(221)
755 sp2 = pylab.subplot(222, sharex=sp1, sharey=sp1)
756 sp3 = pylab.subplot(223, sharex=sp1, sharey=sp1)
757 sp4 = pylab.subplot(224, sharex=sp1, sharey=sp1)
758 xs = np.arange(-5, 5.05, 0.1)
759 ys = 1./np.sqrt(2*np.pi)*np.exp(-0.5*xs**2)
761 sp1.hist(candidateResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 762 % (np.mean(candidateResids), np.var(candidateResids)))
763 sp1.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
764 sp1.set_title(
"Candidates: basis fit", fontsize=titleFs - 2)
765 sp1.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
767 sp2.hist(spatialResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 768 % (np.mean(spatialResids), np.var(spatialResids)))
769 sp2.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
770 sp2.set_title(
"Candidates: spatial fit", fontsize=titleFs - 2)
771 sp2.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
773 sp3.hist(nonfitResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 774 % (np.mean(nonfitResids), np.var(nonfitResids)))
775 sp3.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
776 sp3.set_title(
"Control sample: spatial fit", fontsize=titleFs - 2)
777 sp3.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
779 sp4.hist(allResids, bins=xs, normed=
True, alpha=0.5, label=
"N(%.2f, %.2f)" 780 % (np.mean(allResids), np.var(allResids)))
781 sp4.plot(xs, ys,
"r-", lw=2, label=
"N(0,1)")
782 sp4.set_title(
"Full image (subsampled)", fontsize=titleFs - 2)
783 sp4.legend(loc=1, fancybox=
True, shadow=
True, prop=FontProperties(size=titleFs - 6))
785 pylab.setp(sp1.get_xticklabels() + sp1.get_yticklabels(), fontsize=titleFs - 4)
786 pylab.setp(sp2.get_xticklabels() + sp2.get_yticklabels(), fontsize=titleFs - 4)
787 pylab.setp(sp3.get_xticklabels() + sp3.get_yticklabels(), fontsize=titleFs - 4)
788 pylab.setp(sp4.get_xticklabels() + sp4.get_yticklabels(), fontsize=titleFs - 4)
795 if keepPlots
and not keptPlots:
798 print(
"%s: Please close plots when done." % __name__)
803 print(
"Plots closed, exiting...")
805 atexit.register(show)
810 """Calculate first moment of a (kernel) image. 814 xarr = np.asarray([[el
for el
in range(x)]
for el2
in range(y)])
815 yarr = np.asarray([[el2
for el
in range(x)]
for el2
in range(y)])
818 centx = narr.sum()/sarrSum
820 centy = narr.sum()/sarrSum
825 """Calculate second moment of a (kernel) image. 830 xarr = np.asarray([[el
for el
in range(x)]
for el2
in range(y)])
831 yarr = np.asarray([[el2
for el
in range(x)]
for el2
in range(y)])
832 narr = sarr*np.power((xarr - centx), 2.)
834 xstd = np.sqrt(narr.sum()/sarrSum)
835 narr = sarr*np.power((yarr - centy), 2.)
836 ystd = np.sqrt(narr.sum()/sarrSum)
841 """Print differences in sky coordinates. 843 The difference is that between the source Position and its Centroid mapped 847 sCentroid = s.getCentroid()
848 sPosition = s.getCoord().getPosition(geom.degrees)
849 dra = 3600*(sPosition.getX() - wcs.pixelToSky(sCentroid).getPosition(geom.degrees).getX())/0.2
850 ddec = 3600*(sPosition.getY() - wcs.pixelToSky(sCentroid).getPosition(geom.degrees).getY())/0.2
851 if np.isfinite(dra)
and np.isfinite(ddec):
856 """Create regions file for display from input source list. 858 fh = open(outfilename,
"w")
859 fh.write(
"global color=red font=\"helvetica 10 normal\" " 860 "select=1 highlite=1 edit=1 move=1 delete=1 include=1 fixed=0 source\nfk5\n")
863 (ra, dec) = wcs.pixelToSky(s.getCentroid()).getPosition(geom.degrees)
865 (ra, dec) = s.getCoord().getPosition(geom.degrees)
866 if np.isfinite(ra)
and np.isfinite(dec):
867 fh.write(
"circle(%f,%f,2\")\n"%(ra, dec))
873 """Draw the (RA, Dec) positions of a set of Sources. Image has the XY0. 875 disp = afwDisplay.Display(frame=frame)
876 with disp.Buffering():
878 (xc, yc) = wcs.skyToPixel(s.getCoord().getRa(), s.getCoord().getDec())
881 disp.dot(symb, xc, yc, ctype=ctype, size=size)
885 """Plot whisker diagram of astromeric offsets between results.matches. 887 refCoordKey = results.matches[0].first.getTable().getCoordKey()
888 inCentroidKey = results.matches[0].second.getTable().getCentroidKey()
889 positions = [m.first.get(refCoordKey)
for m
in results.matches]
890 residuals = [m.first.get(refCoordKey).getOffsetFrom(
891 newWcs.pixelToSky(m.second.get(inCentroidKey)))
for 892 m
in results.matches]
893 import matplotlib.pyplot
as plt
895 sp = fig.add_subplot(1, 1, 0)
896 xpos = [x[0].asDegrees()
for x
in positions]
897 ypos = [x[1].asDegrees()
for x
in positions]
898 xpos.append(0.02*(max(xpos) - min(xpos)) + min(xpos))
899 ypos.append(0.98*(max(ypos) - min(ypos)) + min(ypos))
900 xidxs = np.isfinite(xpos)
901 yidxs = np.isfinite(ypos)
902 X = np.asarray(xpos)[xidxs]
903 Y = np.asarray(ypos)[yidxs]
904 distance = [x[1].asArcseconds()
for x
in residuals]
906 distance = np.asarray(distance)[xidxs]
909 bearing = [x[0].asRadians()
for x
in residuals]
911 bearing = np.asarray(bearing)[xidxs]
912 U = (distance*np.cos(bearing))
913 V = (distance*np.sin(bearing))
914 sp.quiver(X, Y, U, V)
915 sp.set_title(
"WCS Residual")
920 """Utility class for dipole measurement testing. 922 Generate an image with simulated dipoles and noise; store the original 923 "pre-subtraction" images and catalogs as well. 924 Used to generate test data for DMTN-007 (http://dmtn-007.lsst.io). 927 def __init__(self, w=101, h=101, xcenPos=[27.], ycenPos=[25.], xcenNeg=[23.], ycenNeg=[25.],
928 psfSigma=2., flux=[30000.], fluxNeg=None, noise=10., gradientParams=None):
944 def _makeDipoleImage(self):
945 """Generate an exposure and catalog with the given dipole source(s). 954 dipole = posImage.clone()
955 di = dipole.getMaskedImage()
956 di -= negImage.getMaskedImage()
960 posDetectedBits = posImage.getMaskedImage().getMask().getArray() == dm.getPlaneBitMask(
"DETECTED")
961 negDetectedBits = negImage.getMaskedImage().getMask().getArray() == dm.getPlaneBitMask(
"DETECTED")
962 pos_det = dm.addMaskPlane(
"DETECTED_POS")
963 neg_det = dm.addMaskPlane(
"DETECTED_NEG")
966 dma[:, :] = posDetectedBits*pos_det + negDetectedBits*neg_det
967 self.diffim, self.posImage, self.posCatalog, self.negImage, self.negCatalog \
968 = dipole, posImage, posCatalog, negImage, negCatalog
970 def _makeStarImage(self, xc=[15.3], yc=[18.6], flux=[2500], schema=None, randomSeed=None):
971 """Generate an exposure and catalog with the given stellar source(s). 975 dataset = TestDataset(bbox, psfSigma=self.
psfSigma, threshold=1.)
977 for i
in range(len(xc)):
978 dataset.addSource(instFlux=flux[i], centroid=
geom.Point2D(xc[i], yc[i]))
981 schema = TestDataset.makeMinimalSchema()
982 exposure, catalog = dataset.realize(noise=self.
noise, schema=schema, randomSeed=randomSeed)
985 y, x = np.mgrid[:self.
w, :self.
h]
987 gradient = gp[0] + gp[1]*x + gp[2]*y
989 gradient += gp[3]*x*y + gp[4]*x*x + gp[5]*y*y
990 imgArr = exposure.getMaskedImage().getArrays()[0]
993 return exposure, catalog
997 fitResult = alg.fitDipole(source, **kwds)
1001 """Utility function for detecting dipoles. 1003 Detect pos/neg sources in the diffim, then merge them. A 1004 bigger "grow" parameter leads to a larger footprint which 1005 helps with dipole measurement for faint dipoles. 1010 Whether to merge the positive and negagive detections into a single 1012 diffim : `lsst.afw.image.exposure.exposure.ExposureF` 1013 Difference image on which to perform detection. 1014 detectSigma : `float` 1015 Threshold for object detection. 1017 Number of pixels to grow the footprints before merging. 1019 Minimum bin size for the background (re)estimation (only applies if 1020 the default leads to min(nBinX, nBinY) < fit order so the default 1021 config parameter needs to be decreased, but not to a value smaller 1022 than ``minBinSize``, in which case the fitting algorithm will take 1023 over and decrease the fit order appropriately.) 1027 sources : `lsst.afw.table.SourceCatalog` 1028 If doMerge=True, the merged source catalog is returned OR 1029 detectTask : `lsst.meas.algorithms.SourceDetectionTask` 1030 schema : `lsst.afw.table.Schema` 1031 If doMerge=False, the source detection task and its schema are 1035 diffim = self.diffim
1038 schema = afwTable.SourceTable.makeMinimalSchema()
1041 detectConfig = measAlg.SourceDetectionConfig()
1042 detectConfig.returnOriginalFootprints =
False 1044 psfSigma = diffim.getPsf().computeShape().getDeterminantRadius()
1047 detectConfig.thresholdPolarity =
"both" 1048 detectConfig.thresholdValue = detectSigma
1050 detectConfig.reEstimateBackground =
True 1051 detectConfig.thresholdType =
"pixel_stdev" 1053 while ((min(diffim.getWidth(), diffim.getHeight()))//detectConfig.background.binSize <
1054 detectConfig.background.approxOrderX
and detectConfig.background.binSize > minBinSize):
1055 detectConfig.background.binSize = max(minBinSize, detectConfig.background.binSize//2)
1058 detectTask = measAlg.SourceDetectionTask(schema, config=detectConfig)
1060 table = afwTable.SourceTable.make(schema)
1061 catalog = detectTask.makeSourceCatalog(table, diffim, sigma=psfSigma)
1065 fpSet = catalog.fpSets.positive
1066 fpSet.merge(catalog.fpSets.negative, grow, grow,
False)
1067 sources = afwTable.SourceCatalog(table)
1068 fpSet.makeSources(sources)
1073 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)