Coverage for python/lsst/analysis/drp/dataSelectors.py: 44%
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1__all__ = ("FlagSelector", "PsfFlagSelector", "StarIdentifier", "GalaxyIdentifier", "UnknownIdentifier",
2 "CoaddPlotFlagSelector", "BaseSNRSelector", "SnSelector")
4from abc import abstractmethod
5from lsst.pex.config import ListField, Field
6from lsst.pipe.tasks.dataFrameActions import DataFrameAction
7import numpy as np
10class FlagSelector(DataFrameAction):
11 """The base flag selector to use to select valid sources for QA"""
13 selectWhenFalse = ListField(doc="Names of the flag columns to select on when False",
14 dtype=str,
15 optional=False,
16 default=[])
18 selectWhenTrue = ListField(doc="Names of the flag columns to select on when True",
19 dtype=str,
20 optional=False,
21 default=[])
23 @property
24 def columns(self):
25 allCols = list(self.selectWhenFalse) + list(self.selectWhenTrue)
26 yield from allCols
28 def __call__(self, df, **kwargs):
29 """Select on the given flags
31 Parameters
32 ----------
33 df : `pandas.core.frame.DataFrame`
35 Returns
36 -------
37 result : `numpy.ndarray`
38 A mask of the objects that satisfy the given
39 flag cuts.
41 Notes
42 -----
43 Uses the columns in selectWhenFalse and
44 selectWhenTrue to decide which columns to
45 select on in each circumstance.
46 """
47 result = np.ones(len(df), dtype=bool)
48 for flag in self.selectWhenFalse:
49 result &= (df[flag].values == 0)
50 for flag in self.selectWhenTrue:
51 result &= (df[flag].values == 1)
52 return result
55class PsfFlagSelector(FlagSelector):
56 """Remove sources with bad flags set for PSF measurements """
58 bands = ListField(doc="The bands to apply the flags in",
59 dtype=str,
60 default=["g", "r", "i", "z", "y"])
62 @property
63 def columns(self):
64 filterColumns = ["xy_flag", "detect_isPatchInner", "detect_isDebelendedSource"]
65 flagCols = ["psfFlux_flag", "psfFlux_flag_apCorr", "psfFlux_flag_edge",
66 "psfFlux_flag_noGoodPixels"]
67 filterColumns += [band + "_" + flag if len(band) > 0 else band + flag
68 for flag in flagCols for band in self.bands]
69 yield from filterColumns
71 def __call__(self, df, **kwargs):
72 """Make a mask of objects with bad PSF flags
74 Parameters
75 ----------
76 df : `pandas.core.frame.DataFrame`
78 Returns
79 -------
80 result : `numpy.ndarray`
81 A mask of the objects that satisfy the given
82 flag cuts.
84 Notes
85 -----
86 Uses the PSF flags and some general quality
87 control flags to make a mask of the data that
88 satisfies these criteria.
89 """
91 result = None
92 flagCols = ["psfFlux_flag", "pixelFlags_saturatedCenter", "extendedness_flag"]
93 filterColumns = ["xy_flag"]
94 filterColumns += [band + "_" + flag if len(band) > 0 else band + flag
95 for flag in flagCols for band in self.bands]
96 for flag in filterColumns:
97 selected = (df[flag].values == 0)
98 if result is None:
99 result = selected
100 else:
101 result &= selected
102 result &= (df["detect_isPatchInner"] == 1)
103 result &= (df["detect_isDeblendedSource"] == 1)
104 return result
107class BaseSNRSelector(DataFrameAction):
108 """Selects sources that have a S/N greater than the
109 given threshold"""
111 fluxField = Field(doc="Flux field to use in SNR calculation", dtype=str,
112 default="psfFlux", optional=False)
113 errField = Field(doc="Flux err field to use in SNR calculation", dtype=str,
114 default="psfFluxErr", optional=False)
115 threshold = Field(doc="The signal to noise threshold to select sources",
116 dtype=float,
117 optional=False)
118 band = Field(doc="The band to make the selection in.",
119 default="i",
120 dtype=str)
122 @property
123 def columns(self):
124 if len(self.band) > 0:
125 band = self.band + "_"
126 else:
127 band = self.band
128 return (band + self.fluxField, band + self.errField)
131class SnSelector(DataFrameAction):
132 """Selects points that have S/N > threshold in the given flux type"""
133 fluxType = Field(doc="Flux type to calculate the S/N in.",
134 dtype=str,
135 default="psfFlux")
136 threshold = Field(doc="The S/N threshold to remove sources with.",
137 dtype=float,
138 default=500.0)
139 bands = ListField(doc="The bands to apply the signal to noise cut in.",
140 dtype=str,
141 default=["i"])
143 @property
144 def columns(self):
145 cols = []
146 for band in self.bands:
147 if len(band) > 0:
148 band = band + "_"
149 cols += [band + self.fluxType, band + self.fluxType + "Err"]
151 return cols
153 def __call__(self, df):
154 """Makes a mask of objects that have S/N greater than
155 self.threshold in self.fluxType
157 Parameters
158 ----------
159 df : `pandas.core.frame.DataFrame`
161 Returns
162 -------
163 result : `numpy.ndarray`
164 A mask of the objects that satisfy the given
165 S/N cut.
166 """
168 mask = np.ones(len(df), dtype=bool)
169 for band in self.bands:
170 if len(band) > 0:
171 band = band + "_"
172 mask &= ((df[band + self.fluxType] / df[band + self.fluxType + "Err"]) > self.threshold)
174 return mask
177def format_extendedness(prefix):
178 return "refExtendedness" if prefix == "ref" else (
179 f"{prefix}{'_' if len(prefix) > 0 else ''}extendedness")
182class ExtendedIdentifier(DataFrameAction):
183 band = Field(doc="The band the object is to be classified as a star in.",
184 default="i",
185 dtype=str)
187 @property
188 def columns(self):
189 return [self.extendedness]
191 @property
192 def extendedness(self):
193 return format_extendedness(self.band)
195 # TODO: Add classmethod in py3.9
196 @property
197 @abstractmethod
198 def sourceType(self):
199 raise NotImplementedError("This method should be overloaded in subclasses")
201 @abstractmethod
202 def identified(self, df):
203 raise NotImplementedError("This method should be overloaded in subclasses")
205 def __call__(self, df, **kwargs):
206 """Identifies sources classified as stars
208 Parameters
209 ----------
210 df : `pandas.core.frame.DataFrame`
212 Returns
213 -------
214 result : `numpy.ndarray`
215 An array with the objects that are classified as
216 stars marked with a 1.
217 """
218 sourceType = np.zeros(len(df))
219 sourceType[self.identified(df)] = self.sourceType
220 return sourceType
223class StarIdentifier(ExtendedIdentifier):
224 """Identifies stars from the dataFrame and marks them as a 1
225 in the added sourceType column"""
226 extendedness_maximum = Field(doc="Maximum extendedness to qualify as unresolved, inclusive.",
227 default=0.5,
228 dtype=float)
230 @property
231 @abstractmethod
232 def sourceType(self):
233 return 1
235 @abstractmethod
236 def identified(self, df):
237 extendedness = df[self.extendedness]
238 return (extendedness >= 0) & (extendedness < self.extendedness_maximum)
241class GalaxyIdentifier(ExtendedIdentifier):
242 """Identifies galaxies from the dataFrame and marks them as a 2
243 in the added sourceType column"""
244 extendedness_minimum = Field(doc="Minimum extendedness to qualify as resolved, not inclusive.",
245 default=0.5,
246 dtype=float)
248 @property
249 @abstractmethod
250 def sourceType(self):
251 return 2
253 @abstractmethod
254 def identified(self, df):
255 extendedness = df[self.extendedness]
256 return (extendedness > self.extendedness_minimum) & (extendedness <= 1)
259class UnknownIdentifier(ExtendedIdentifier):
260 """Identifies un classified objects from the dataFrame and marks them as a
261 9 in the added sourceType column"""
263 @property
264 @abstractmethod
265 def sourceType(self):
266 return 9
268 @abstractmethod
269 def identified(self, df):
270 return df[self.extendedness] == 9
273class VisitPlotFlagSelector(DataFrameAction):
275 @property
276 def columns(self):
277 flagCols = ["psfFlux_flag", "pixelFlags_saturatedCenter", "extendedness_flag", "centroid_flag"]
278 yield from flagCols
280 def __call__(self, df, **kwargs):
281 """The flags to use for selecting sources for visit QA
283 Parameters
284 ----------
285 df : `pandas.core.frame.DataFrame`
287 Returns
288 -------
289 result : `numpy.ndarray`
290 A mask of the objects that satisfy the given
291 flag cuts.
293 Notes
294 -----
295 These flags are taken from pipe_analysis and are considered to
296 be the standard flags for general QA plots. Some of the plots
297 will require a different set of flags, or additional ones on
298 top of the ones specified here. These should be specifed in
299 an additional selector rather than adding to this one.
300 """
302 result = None
303 flagCols = ["psfFlux_flag", "pixelFlags_saturatedCenter", "extendedness_flag", "centroid_flag"]
304 for flag in flagCols:
305 selected = (df[flag].values == 0)
306 if result is None:
307 result = selected
308 else:
309 result &= selected
310 return result
313class CoaddPlotFlagSelector(DataFrameAction):
314 """The flags to use for selecting sources for coadd QA
316 Parameters
317 ----------
318 df : `pandas.core.frame.DataFrame`
320 Returns
321 -------
322 result : `numpy.ndarray`
323 A mask of the objects that satisfy the given
324 flag cuts.
326 Notes
327 -----
328 These flags are taken from pipe_analysis and are considered to
329 be the standard flags for general QA plots. Some of the plots
330 will require a different set of flags, or additional ones on
331 top of the ones specified here. These should be specifed in
332 an additional selector rather than adding to this one.
333 """
335 bands = ListField(doc="The bands to apply the flags in",
336 dtype=str,
337 default=["g", "r", "i", "z", "y"])
339 @property
340 def columns(self):
341 flagCols = ["psfFlux_flag", "pixelFlags_saturatedCenter", "extendedness_flag"]
342 filterColumns = ["xy_flag", "detect_isPatchInner", "detect_isDeblendedSource"]
343 filterColumns += [band + "_" + flag if len(band) > 0 else band + flag
344 for flag in flagCols for band in self.bands]
345 yield from filterColumns
347 def __call__(self, df, **kwargs):
348 """The flags to use for selecting sources for coadd QA
350 Parameters
351 ----------
352 df : `pandas.core.frame.DataFrame`
354 Returns
355 -------
356 result : `numpy.ndarray`
357 A mask of the objects that satisfy the given
358 flag cuts.
360 Notes
361 -----
362 These flags are taken from pipe_analysis and are considered to
363 be the standard flags for general QA plots. Some of the plots
364 will require a different set of flags, or additional ones on
365 top of the ones specified here. These should be specifed in
366 an additional selector rather than adding to this one.
367 """
369 result = None
370 flagCols = ["psfFlux_flag", "pixelFlags_saturatedCenter", "extendedness_flag"]
371 filterColumns = ["xy_flag"]
372 filterColumns += [band + "_" + flag if len(band) > 0 else band + flag
373 for flag in flagCols for band in self.bands]
374 for flag in filterColumns:
375 selected = (df[flag].values == 0)
376 if result is None:
377 result = selected
378 else:
379 result &= selected
380 result &= (df["detect_isPatchInner"] == 1)
381 result &= (df["detect_isDeblendedSource"] == 1)
382 return result