Coverage for python/lsst/faro/utils/selectors.py: 15%
191 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-14 02:39 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-14 02:39 -0700
1# Note: analysis_drp is not yet part of the pipelines, so you need to clone it,
2from lsst.pex.config import ListField, Field, ChoiceField
3from lsst.pipe.tasks.dataFrameActions import DataFrameAction
4import numpy as np
6__all__ = ("FlagSelector", "GalaxyIdentifier", "PerBandFlagSelector", "SNRSelector",
7 "StarIdentifier", "UnknownIdentifier", "applySelectors",
8 "brightIsolatedStarSourceTable", "brightIsolatedStarObjectTable")
11class FlagSelector(DataFrameAction):
12 """The base flag selector to use to select valid sources should not have an
13 associated band"""
15 selectWhenFalse = ListField(
16 doc="Names of the flag columns to select on when False",
17 dtype=str,
18 optional=False,
19 default=[]
20 )
22 selectWhenTrue = ListField(
23 doc="Names of the flag columns to select on when True",
24 dtype=str,
25 optional=False,
26 default=[]
27 )
29 selectorBandType = ChoiceField(
30 doc="Type of selection to do options are current band or static selection",
31 dtype=str,
32 allowed={"currentBands": "use the currentBand for selection",
33 "staticBandSet": "use the bands listed in self.staticBandSet"
34 },
35 default="currentBands",
36 )
37 staticBandSet = ListField(
38 doc="""List of bands that selection should be applied over. If changed from
39 the default this overrides the band argument in the columns/call method.""",
40 dtype=str,
41 default=[""]
42 )
44 def columns(self, currentBands=None):
45 allCols = list(self.selectWhenFalse) + list(self.selectWhenTrue)
46 return allCols
48 def __call__(self, df, currentBands=None):
49 """Select on the given flags
50 Parameters
51 ----------
52 df : `pandas.core.frame.DataFrame`
53 Returns
54 -------
55 result : `numpy.ndarray`
56 A mask of the objects that satisfy the given
57 flag cuts.
58 Notes
59 -----
60 Uses the columns in selectWhenFalse and selectWhenTrue to decide which
61 columns to select on in each circumstance.
62 """
63 mask = np.ones(len(df), dtype=bool)
65 for flag in self.selectWhenFalse:
66 mask &= (df[flag].values == 0)
68 for flag in self.selectWhenTrue:
69 mask &= (df[flag].values == 1)
71 return mask
74class GalaxyIdentifier(DataFrameAction):
75 """Identifies galaxies from the dataFrame"""
77 selectorBandType = ChoiceField(
78 doc="Type of selection to do options are current band or static selection",
79 dtype=str,
80 allowed={"currentBands": "use the currentBand for selection",
81 "staticBandSet": "use the bands listed in self.staticBandSet"
82 },
83 default="currentBands",
84 )
85 staticBandSet = ListField(
86 doc="""List of bands that selection should be applied over. If changed from
87 the default this overrides the band argument in the columns/call method.""",
88 dtype=str,
89 default=[""]
90 )
92 def columns(self, currentBands=None):
93 allCols = []
94 if self.selectorBandType == "staticBandSet":
95 bands = self.staticBandSet
96 else:
97 bands = currentBands
99 if bands is not None:
100 for band in bands:
101 allCols += [band+'_'+'extendedness']
102 else:
103 allCols = ['extendedness']
104 return allCols
106 def __call__(self, df, currentBands=None):
107 """Identifies sources classified as galaxies
108 Parameters
109 ----------
110 df : `pandas.core.frame.DataFrame`
111 Returns
112 -------
113 result : `numpy.ndarray`
114 A mask of objects that are classified as galaxies.
115 """
117 mask = np.ones(len(df), dtype=bool)
119 if self.selectorBandType == "staticBandSet":
120 bands = self.staticBandSet
121 elif self.selectorBandType == "currentBands":
122 bands = currentBands
124 if bands is not None:
125 for band in bands:
126 mask &= (df[band+'_'+'extendedness'] == 1.0)
127 else:
128 mask &= (df['extendedness'] == 1.0)
130 return mask
133class PerBandFlagSelector(DataFrameAction):
134 """Flag selector for ObjectTable flags that are defined in each band
135 Parameters
136 ----------
137 df : `pandas.core.frame.DataFrame`
138 Returns
139 -------
140 result : `numpy.ndarray`
141 A mask of the objects that satisfy the given
142 flag cuts.
143 Notes
144 -----
145 """
146 selectWhenFalse = ListField(
147 doc="Names of the flag columns to select on when False",
148 dtype=str,
149 optional=False,
150 default=[]
151 )
153 selectWhenTrue = ListField(
154 doc="Names of the flag columns to select on when True",
155 dtype=str,
156 optional=False,
157 default=[]
158 )
160 selectorBandType = ChoiceField(
161 doc="Type of selection to do options are current band or static selection",
162 dtype=str,
163 allowed={"currentBands": "use the currentBand for selection",
164 "staticBandSet": "use the bands listed in self.staticBandSet"
165 },
166 default="currentBands",
167 )
168 staticBandSet = ListField(
169 doc="""List of bands that selection should be applied over. If changed from
170 the default this overrides the band argument in the columns/call method.""",
171 dtype=str,
172 default=[""]
173 )
175 def columns(self, currentBands=None):
176 filterColumnsTrue = []
177 filterColumnsFalse = []
178 allCols = []
179 if self.selectorBandType == "staticBandSet":
180 bands = self.staticBandSet
181 else:
182 bands = currentBands
183 if bands is not None:
184 filterColumnsTrue += [band+'_'+flag for flag in self.selectWhenTrue for band in bands]
185 filterColumnsFalse += [band+'_'+flag for flag in self.selectWhenFalse for band in bands]
186 else:
187 filterColumnsTrue += [band+flag for flag in self.selectWhenTrue for band in self.bands]
188 filterColumnsFalse += [band+flag for flag in self.selectWhenFalse for band in self.bands]
189 allCols = list(filterColumnsFalse) + list(filterColumnsTrue)
190 return allCols
192 def __call__(self, df, currentBands=None):
193 """The flags to use for selecting sources from objectTables
194 Parameters
195 ----------
196 df : `pandas.core.frame.DataFrame`
197 Returns
198 -------
199 result : `numpy.ndarray`
200 A mask of the objects that satisfy the given
201 flag cuts.
202 Notes
203 -----
204 """
206 filterColumnsTrue = []
207 filterColumnsFalse = []
208 mask = np.ones(len(df), dtype=bool)
210 if self.selectorBandType == "staticBandSet":
211 bands = self.staticBandSet
212 elif self.selectorBandType == "currentBands":
213 bands = currentBands
215 if bands is not None:
216 for band in bands:
217 filterColumnsTrue += [band+'_'+flag for flag in self.selectWhenTrue for band in bands]
218 filterColumnsFalse += [band+'_'+flag for flag in self.selectWhenFalse for band in bands]
219 else:
220 filterColumnsTrue += [flag for flag in self.selectWhenTrue]
221 filterColumnsFalse += [flag for flag in self.selectWhenFalse]
223 for flag in filterColumnsFalse:
224 mask &= (df[flag].values == 0)
225 for flag in filterColumnsTrue:
226 mask &= (df[flag].values == 1)
227 return mask
230class SNRSelector(DataFrameAction):
231 """SNR Selector for sources from a SourceTable or ObjectTable
232 Selects soruces that have snrMin < S/N < snrMax in the given flux type
233 Parameters
234 ----------
235 df : `pandas.core.frame.DataFrame`
236 Returns
237 -------
238 result : `numpy.ndarray`
239 A mask of the objects that satisfy the given
240 flag cuts.
241 Notes
242 -----
243 """
244 fluxType = Field(
245 doc="Flux type to calculate the S/N in.",
246 dtype=str,
247 default="psfFlux"
248 )
249 snrMin = Field(
250 doc="The minimum S/N threshold to remove sources with.",
251 dtype=float,
252 default=50.0
253 )
254 snrMax = Field(
255 doc="The maximum S/N threshold to remove sources with.",
256 dtype=float,
257 default=np.Inf
258 )
259 selectorBandType = ChoiceField(
260 doc="Type of selection to do options are current band or static selection",
261 dtype=str,
262 allowed={"currentBands": "use the currentBand for selection",
263 "staticBandSet": "use the bands listed in self.staticBandSet"
264 },
265 default="currentBands",
266 )
267 staticBandSet = ListField(
268 doc="""List of bands that selection should be applied over. If changed from
269 the default this overrides the band argument in the columns/call method.""",
270 dtype=str,
271 default=[""]
272 )
273 # want to set an error if staticBandSet, and self.staticBandSet=[""]
275 def columns(self, currentBands=None):
276 allCols = []
277 if self.selectorBandType == "staticBandSet":
278 bands = self.staticBandSet
279 else:
280 bands = currentBands
282 if bands is not None:
283 for band in bands:
284 allCols += [band+'_'+self.fluxType, band+'_'+self.fluxType+'Err']
285 else:
286 allCols = [self.fluxType, self.fluxType+'Err']
287 return allCols
289 def __call__(self, df, currentBands=None):
290 """Makes a mask of objects that have S/N between self.snrMin and
291 self.snrMax in self.fluxType
292 Parameters
293 ----------
294 df : `pandas.core.frame.DataFrame`
295 Returns
296 -------
297 result : `numpy.ndarray`
298 A mask of the objects that satisfy the given
299 S/N cut.
300 """
301 mask = np.ones(len(df), dtype=bool)
302 if self.selectorBandType == "staticBandSet":
303 bands = self.staticBandSet
304 elif self.selectorBandType == "currentBands":
305 bands = currentBands
306 if bands is not None:
307 for band in bands:
308 mask &= ((df[band+'_'+self.fluxType] / df[band+'_'+self.fluxType+"Err"]) > self.snrMin)
309 mask &= ((df[band+'_'+self.fluxType] / df[band+'_'+self.fluxType+"Err"]) < self.snrMax)
310 else:
311 mask &= ((df[self.fluxType] / df[self.fluxType+"Err"]) > self.snrMin)
312 mask &= ((df[self.fluxType] / df[self.fluxType+"Err"]) < self.snrMax)
313 return mask
316class StarIdentifier(DataFrameAction):
317 """Identifies stars from the dataFrame"""
319 selectorBandType = ChoiceField(
320 doc="Type of selection to do options are current band or static selection",
321 dtype=str,
322 allowed={"currentBands": "use the currentBand for selection",
323 "staticBandSet": "use the bands listed in self.staticBandSet"
324 },
325 default="currentBands",
326 )
327 staticBandSet = ListField(
328 doc="""List of bands that selection should be applied over. If changed from
329 the default this overrides the band argument in the columns/call method.""",
330 dtype=str,
331 default=[""]
332 )
334 def columns(self, currentBands=None):
335 allCols = []
336 if self.selectorBandType == "staticBandSet":
337 bands = self.staticBandSet
338 else:
339 bands = currentBands
341 if bands is not None:
342 for band in bands:
343 allCols += [band+'_'+'extendedness']
344 else:
345 allCols = ['extendedness']
346 return allCols
348 def __call__(self, df, currentBands=None):
349 """Identifies sources classified as stars
350 Parameters
351 ----------
352 df : `pandas.core.frame.DataFrame`
353 Returns
354 -------
355 result : `numpy.ndarray`
356 A mask of objects that are classified as stars.
357 """
359 mask = np.ones(len(df), dtype=bool)
361 if self.selectorBandType == "staticBandSet":
362 bands = self.staticBandSet
363 elif self.selectorBandType == "currentBands":
364 bands = currentBands
366 if bands is not None:
367 for band in bands:
368 mask &= (df[band+'_'+'extendedness'] == 0.0)
369 else:
370 mask &= (df['extendedness'] == 0.0)
372 return mask
375class UnknownIdentifier(DataFrameAction):
376 """Identifies unclassified objects from the dataFrame"""
378 selectorBandType = ChoiceField(
379 doc="Type of selection to do options are current band or static selection",
380 dtype=str,
381 allowed={"currentBands": "use the currentBand for selection",
382 "staticBandSet": "use the bands listed in self.staticBandSet"
383 },
384 default="currentBands",
385 )
386 staticBandSet = ListField(
387 doc="""List of bands that selection should be applied over. If changed from
388 the default this overrides the band argument in the columns/call method.""",
389 dtype=str,
390 default=[""]
391 )
393 def columns(self, currentBands=None):
394 allCols = []
395 if self.selectorBandType == "staticBandSet":
396 bands = self.staticBandSet
397 else:
398 bands = currentBands
400 if bands is not None:
401 for band in bands:
402 allCols += [band+'_'+'extendedness']
403 else:
404 allCols = ['extendedness']
405 return allCols
407 def __call__(self, df, currentBands=None):
408 """Identifies sources with unknown classification
409 Parameters
410 ----------
411 df : `pandas.core.frame.DataFrame`
412 Returns
413 -------
414 result : `numpy.ndarray`
415 A mask of objects that are unclassified.
416 """
418 mask = np.ones(len(df), dtype=bool)
420 if self.selectorBandType == "staticBandSet":
421 bands = self.staticBandSet
422 elif self.selectorBandType == "currentBands":
423 bands = currentBands
425 if bands is not None:
426 for band in bands:
427 mask &= (df[band+'_'+'extendedness'] == 9.0)
428 else:
429 mask &= (df['extendedness'] == 9.0)
431 return mask
434def applySelectors(catalog, selectorList, currentBands=None, returnMask=False):
435 """ Apply the selectors to narrow down the sources to use
436 Parameters
437 ----------
438 catalog : `pandas.core.frame.DataFrame`
439 selectorList: list of selector DataFrameActions
440 currentBands: the bands associated with the current measurement quanta
441 returnMask: boolean to return the mask without applying it to the catalog
443 Returns
444 -------
445 result : `numpy.ndarray`
446 if returnMask==False a dataframe with only sources that pass the selector
447 actions is returned.
448 otherwise the original dataframe and a boolean mask indicating the sources
449 that pass the selector actions is returned.
450 """
451 mask = np.ones(len(catalog), dtype=bool)
452 for selector in selectorList:
453 mask &= selector(catalog, currentBands=currentBands)
454 if returnMask:
455 return catalog, mask
456 else:
457 return catalog[mask]
460def brightIsolatedStarSourceTable(config):
461 """
462 To be called in a measurement yaml sets up a
463 standard set of selectorActions for a SourceTable metric
465 Parameters
466 ----------
467 measurement config dict
469 Returns
470 -------
471 result :
472 mesurement config dict confugured to create a mask used to select
473 bright isolated stars from a SourceTable catalog
474 """
475 # will want to put more thought into this
476 # setup SNRSelector
477 config.selectorActions.SNRSelector = SNRSelector
478 config.selectorActions.SNRSelector.fluxType = "psfFlux"
479 config.selectorActions.SNRSelector.snrMin = 50
480 config.selectorActions.SNRSelector.selectorBandType = "currentBands"
481 # setup stellarSelector
482 config.selectorActions.StarIdentifier = StarIdentifier
483 config.selectorActions.StarIdentifier.selectorBandType = "currentBands"
484 # setup flag slectors
485 config.selectorActions.FlagSelector = FlagSelector
486 config.selectorActions.FlagSelector.selectWhenTrue = ["detect_isPrimary"]
487 config.selectorActions.FlagSelector.selectWhenFalse = ["pixelFlags_saturated", "pixelFlags_cr",
488 "pixelFlags_bad", "pixelFlags_edge",
489 "deblend_nChild"]
490 config.selectorActions.FlagSelector.selectorBandType = "currentBands"
491 return config
494def brightIsolatedStarObjectTable(config):
495 """
496 To be called in a measurement yaml sets up a
497 standard set of selectorActions for a ObjectTable metric
499 Parameters
500 ----------
501 measurement config dict
503 Returns
504 -------
505 result :
506 mesurement config dict confugured to create a mask used to select
507 bright isolated stars from an ObjectTable catalog
508 """
509 # will want to put more thought into this
510 # setup SNRSelector
511 config.selectorActions.SNRSelector = SNRSelector
512 config.selectorActions.SNRSelector.fluxType = "psfFlux"
513 config.selectorActions.SNRSelector.snrMin = 50
514 config.selectorActions.SNRSelector.selectorBandType = "currentBands"
515 # setup stellarSelector
516 config.selectorActions.StarIdentifier = StarIdentifier
517 config.selectorActions.StarIdentifier.selectorBandType = "currentBands"
518 # setup non band flag slectors
519 config.selectorActions.FlagSelector = FlagSelector
520 config.selectorActions.FlagSelector.selectWhenTrue = ["detect_isPrimary"]
521 config.selectorActions.FlagSelector.selectorBandType = "currentBands"
522 # setup per band flag selectors
523 config.selectorActions.PerBandFlagSelector = PerBandFlagSelector
524 config.selectorActions.PerBandFlagSelector.selectWhenFalse = ["pixelFlags_saturated", "pixelFlags_cr",
525 "pixelFlags_bad", "pixelFlags_edge"]
526 config.selectorActions.PerBandFlagSelector.selectorBandType = "currentBands"
527 return config