1 from __future__
import absolute_import, division, print_function
2 from builtins
import zip
3 from builtins
import input
4 from builtins
import object
31 import matplotlib.pyplot
as plt
41 from .
import psfexLib
42 from .psfex
import compute_fwhmrange
44 __all__ = [
"PsfexStarSelectorConfig",
"PsfexStarSelectorTask"]
48 fluxName = pexConfig.Field(
50 doc=
"Name of photometric flux key ",
51 default=
"base_PsfFlux",
53 fluxErrName = pexConfig.Field(
55 doc=
"Name of phot. flux err. key",
58 minFwhm = pexConfig.Field(
60 doc=
"Maximum allowed FWHM ",
63 maxFwhm = pexConfig.Field(
65 doc=
"Minimum allowed FWHM ",
68 maxFwhmVariability = pexConfig.Field(
70 doc=
"Allowed FWHM variability (1.0 = 100%)",
73 maxbad = pexConfig.Field(
75 doc=
"Max number of bad pixels ",
77 check=
lambda x: x >= 0,
79 maxbadflag = pexConfig.Field(
81 doc=
"Filter bad pixels? ",
84 maxellip = pexConfig.Field(
86 doc=
"Maximum (A-B)/(A+B) ",
88 check=
lambda x: x >= 0.0,
90 minsn = pexConfig.Field(
92 doc=
"Minimum S/N for candidates",
94 check=
lambda x: x >= 0.0,
98 pexConfig.Config.validate(self)
103 raise pexConfig.FieldValidationError(
"fluxErrName (%s) doesn't correspond to fluxName (%s)" 107 raise pexConfig.FieldValidationError(
"minFwhm (%f) > maxFwhm (%f)" % (self.
minFwhm, self.
maxFwhm))
111 "base_PixelFlags_flag_edge",
112 "base_PixelFlags_flag_saturatedCenter",
113 "base_PixelFlags_flag_crCenter",
114 "base_PixelFlags_flag_bad",
115 "base_PixelFlags_flag_suspectCenter",
122 """A class to handle key strokes with matplotlib displays""" 124 def __init__(self, axes, xs, ys, x, y, frames=[0]):
132 self.
cid = self.
axes.figure.canvas.mpl_connect(
'key_press_event', self)
135 if ev.inaxes != self.
axes:
138 if ev.key
and ev.key
in (
"p"):
139 dist = np.hypot(self.
xs - ev.xdata, self.
ys - ev.ydata)
140 dist[np.where(np.isnan(dist))] = 1e30
142 which = np.where(dist == min(dist))
147 ds9.pan(x, y, frame=frame)
148 ds9.cmdBuffer.flush()
155 def plot(mag, width, centers, clusterId, marker="o", markersize=2, markeredgewidth=0, ltype='-',
167 axes = fig.add_axes((0.1, 0.1, 0.85, 0.80))
169 xmin = sorted(mag)[int(0.05*len(mag))]
170 xmax = sorted(mag)[int(0.95*len(mag))]
172 axes.set_xlim(-17.5, -13)
173 axes.set_xlim(xmin - 0.1*(xmax - xmin), xmax + 0.1*(xmax - xmin))
176 colors = [
"r", "g", "b", "c", "m", "k", ]
177 for k, mean
in enumerate(centers):
179 axes.plot(axes.get_xlim(), (mean, mean,),
"k%s" % ltype)
182 axes.plot(mag[l], width[l], marker, markersize=markersize, markeredgewidth=markeredgewidth,
183 color=colors[k%len(colors)])
185 l = (clusterId == -1)
186 axes.plot(mag[l], width[l], marker, markersize=markersize, markeredgewidth=markeredgewidth,
190 axes.set_xlabel(
"model")
191 axes.set_ylabel(
r"$\sqrt{I_{xx} + I_{yy}}$")
204 """!A star selector whose algorithm is not yet documented 206 @anchor PsfexStarSelectorTask_ 208 @section meas_extensions_psfex_psfexStarSelectorStarSelector_Contents Contents 210 - @ref meas_extensions_psfex_psfexStarSelectorStarSelector_Purpose 211 - @ref meas_extensions_psfex_psfexStarSelectorStarSelector_Initialize 212 - @ref meas_extensions_psfex_psfexStarSelectorStarSelector_IO 213 - @ref meas_extensions_psfex_psfexStarSelectorStarSelector_Config 214 - @ref meas_extensions_psfex_psfexStarSelectorStarSelector_Debug 216 @section meas_extensions_psfex_psfexStarSelectorStarSelector_Purpose Description 218 A star selector whose algorithm is not yet documented 220 @section meas_extensions_psfex_psfexStarSelectorStarSelector_Initialize Task initialisation 222 @copydoc \_\_init\_\_ 224 @section meas_extensions_psfex_psfexStarSelectorStarSelector_IO Invoking the Task 226 Like all star selectors, the main method is `run`. 228 @section meas_extensions_psfex_psfexStarSelectorStarSelector_Config Configuration parameters 230 See @ref PsfexStarSelectorConfig 232 @section meas_extensions_psfex_psfexStarSelectorStarSelector_Debug Debug variables 234 PsfexStarSelectorTask has a debug dictionary with the following keys: 237 <dd>bool; if True display debug information 239 <dd>bool; if True display the exposure and spatial cells 240 <dt>plotFwhmHistogram 241 <dd>bool; if True plot histogram of FWHM 243 <dd>bool: if True plot the sources coloured by their flags 245 <dd>bool; if True plot why sources are rejected 248 For example, put something like: 252 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively 253 if name.endswith("objectSizeStarSelector"): 255 di.displayExposure = True 256 di.plotFwhmHistogram = True 260 lsstDebug.Info = DebugInfo 262 into your `debug.py` file and run your task with the `--debug` flag. 264 ConfigClass = PsfexStarSelectorConfig
268 """!Select stars from source catalog 270 @param[in] exposure the exposure containing the sources 271 @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) 272 @param[in] matches astrometric matches; ignored by this star selector 274 @return a Struct containing: 275 - starCat a subset of sourceCat containing the selected stars 280 displayExposure = display
and \
282 plotFwhmHistogram = display
and plt
and \
284 plotFlags = display
and plt
and \
286 plotRejection = display
and plt
and \
291 fluxName = self.config.fluxName
292 fluxErrName = self.config.fluxErrName
293 minFwhm = self.config.minFwhm
294 maxFwhm = self.config.maxFwhm
295 maxFwhmVariability = self.config.maxFwhmVariability
296 maxbad = self.config.maxbad
297 maxbadflag = self.config.maxbadflag
298 maxellip = self.config.maxellip
299 minsn = self.config.minsn
301 maxelong = (maxellip + 1.0)/(1.0 - maxellip)
if maxellip < 1.0
else 100
304 shape = sourceCat.getShapeDefinition()
305 ixx = sourceCat.get(
"%s.xx" % shape)
306 iyy = sourceCat.get(
"%s.yy" % shape)
308 fwhm = 2*np.sqrt(2*np.log(2))*np.sqrt(0.5*(ixx + iyy))
309 elong = 0.5*(ixx - iyy)/(ixx + iyy)
311 flux = sourceCat.get(fluxName)
312 fluxErr = sourceCat.get(fluxErrName)
313 sn = flux/np.where(fluxErr > 0, fluxErr, 1)
314 sn[fluxErr <= 0] = -psfexLib.BIG
317 for i, f
in enumerate(self.config.badFlags):
318 flags = np.bitwise_or(flags, np.where(sourceCat.get(f), 1 << i, 0))
322 good = np.logical_and(sn > minsn, np.logical_not(flags))
323 good = np.logical_and(good, elong < maxelong)
324 good = np.logical_and(good, fwhm >= minFwhm)
325 good = np.logical_and(good, fwhm < maxFwhm)
327 fwhmMode, fwhmMin, fwhmMax =
compute_fwhmrange(fwhm[good], maxFwhmVariability, minFwhm, maxFwhm,
328 plot=dict(fwhmHistogram=plotFwhmHistogram))
340 selectionVectors = []
341 selectionVectors.append((bad,
"flags %d" % sum(bad)))
345 bad = np.logical_or(bad, dbad)
347 selectionVectors.append((dbad,
"S/N %d" % sum(dbad)))
349 dbad = fwhm < fwhmMin
351 bad = np.logical_or(bad, dbad)
353 selectionVectors.append((dbad,
"fwhmMin %d" % sum(dbad)))
355 dbad = fwhm > fwhmMax
357 bad = np.logical_or(bad, dbad)
359 selectionVectors.append((dbad,
"fwhmMax %d" % sum(dbad)))
361 dbad = elong > maxelong
363 bad = np.logical_or(bad, dbad)
365 selectionVectors.append((dbad,
"elong %d" % sum(dbad)))
369 nbad = np.array([(v <= -psfexLib.BIG).sum()
for v
in vignet])
372 bad = np.logical_or(bad, dbad)
374 selectionVectors.append((dbad,
"badpix %d" % sum(dbad)))
376 good = np.logical_not(bad)
382 mi = exposure.getMaskedImage()
384 ds9.mtv(mi, frame=frame, title=
"PSF candidates")
386 with ds9.Buffering():
387 for i, source
in enumerate(sourceCat):
393 ds9.dot(
"+", source.getX() - mi.getX0(), source.getY() - mi.getY0(),
394 frame=frame, ctype=ctype)
396 if plotFlags
or plotRejection:
397 imag = -2.5*np.log10(flux)
402 isSet = np.where(flags == 0x0)[0]
403 plt.plot(imag[isSet], fwhm[isSet],
'o', alpha=alpha, label=
"good")
405 for i, f
in enumerate(self.config.badFlags):
407 isSet = np.where(np.bitwise_and(flags, mask))[0]
409 if np.isfinite(imag[isSet] + fwhm[isSet]).any():
410 label = re.sub(
r"\_flag",
"",
411 re.sub(
r"^base\_",
"",
412 re.sub(
r"^.*base\_PixelFlags\_flag\_",
"", f)))
413 plt.plot(imag[isSet], fwhm[isSet],
'o', alpha=alpha, label=label)
415 for bad, label
in selectionVectors:
416 plt.plot(imag[bad], fwhm[bad],
'o', alpha=alpha, label=label)
418 plt.plot(imag[good], fwhm[good],
'o', color=
"black", label=
"selected")
419 [plt.axhline(_, color=
'red')
for _
in [fwhmMin, fwhmMax]]
420 plt.xlim(np.median(imag[good]) + 5*np.array([-1, 1]))
421 plt.ylim(fwhm[np.where(np.isfinite(fwhm + imag))].min(), 2*fwhmMax)
423 plt.xlabel(
"Instrumental %s Magnitude" % fluxName.split(
".")[-1].title())
425 title =
"PSFEX Star Selection" 426 plt.title(
"%s %d selected" % (title, sum(good)))
430 eventHandler =
EventHandler(plt.axes(), imag, fwhm, sourceCat.getX(), sourceCat.getY(),
433 if plotFlags
or plotRejection:
436 reply = input(
"continue? [y[es] h(elp) p(db) q(uit)] ").strip()
445 At this prompt, you can continue with almost any key; 'p' enters pdb, 446 'q' returns to the shell, and 452 If you put the cursor on a point in the matplotlib scatter plot and hit 'p' you'll see it in ds9.""")
453 elif reply[0] ==
"p":
456 elif reply[0] ==
'q':
461 starCat = SourceCatalog(sourceCat.schema)
462 for source, isGood
in zip(sourceCat, good):
464 starCat.append(source)
470 starSelectorRegistry.register(
"psfex", PsfexStarSelectorTask)
def selectStars(self, exposure, sourceCat, matches=None)
Select stars from source catalog.
def compute_fwhmrange(fwhm, maxvar, minin, maxin, plot=dict(fwhmHistogram=False))
def __init__(self, axes, xs, ys, x, y, frames=[0])
A star selector whose algorithm is not yet documented.
def plot(mag, width, centers, clusterId, marker="o", markersize=2, markeredgewidth=0, ltype='-', clear=True)