Coverage for python/lsst/analysis/tools/analysisPlots/analysisPlots.py: 29%
218 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-19 03:18 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-19 03:18 -0800
1# This file is part of analysis_tools.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21from __future__ import annotations
23__all__ = (
24 "E1DiffScatterPlot",
25 "E2DiffScatterPlot",
26 "ShapeSizeFractionalDiffScatterPlot",
27 "Ap12PsfSkyPlot",
28 "WPerpPSFPlot",
29 "WPerpCModelPlot",
30 "XPerpPSFPlot",
31 "XPerpCModelPlot",
32 "YPerpPSFPlot",
33 "YPerpCModelPlot",
34 "TargetRefCatDeltaRAScatterPlot",
35 "TargetRefCatDeltaDecScatterPlot",
36 "TargetRefCatDeltaRASkyPlot",
37 "TargetRefCatDeltaDecSkyPlot",
38 "SourcesPlot",
39 "RhoStatisticsPlot",
40)
42from lsst.pex.config import Field
44from ..actions.plot.barPlots import BarPanel, BarPlot
45from ..actions.plot.colorColorFitPlot import ColorColorFitPlot
46from ..actions.plot.histPlot import HistPanel, HistPlot
47from ..actions.plot.rhoStatisticsPlot import RhoStatisticsPlotAction
48from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
49from ..actions.plot.skyPlot import SkyPlot
50from ..actions.scalar import CountAction
51from ..actions.vector import (
52 AstromDiff,
53 CoaddPlotFlagSelector,
54 DownselectVector,
55 ExtinctionCorrectedMagDiff,
56 LoadVector,
57 MagColumnNanoJansky,
58 SnSelector,
59 StarSelector,
60 VectorSelector,
61)
62from ..analysisParts.baseFluxRatio import BasePsfApRatio
63from ..analysisParts.baseSources import BaseSources
64from ..analysisParts.genericPrep import CoaddPrep, VisitPrep
65from ..analysisParts.rhoStatistics import RhoStatisticsMixin
66from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin
67from ..analysisParts.stellarLocus import WPerpCModel, WPerpPSF, XPerpCModel, XPerpPSF, YPerpCModel, YPerpPSF
68from ..interfaces import AnalysisPlot
71class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin):
72 """Base class for scatter plots of PSF residuals.
74 This is shared by size and ellipticity plots.
75 """
77 def setDefaults(self):
78 super().setDefaults()
79 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
80 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
82 self.process.buildActions.patchWhole = LoadVector()
83 self.process.buildActions.patchWhole.vectorKey = "patch"
85 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
86 # pre-compute a stellar selector mask so it can be used in the filter
87 # actions while only being computed once, alternatively the stellar
88 # selector could be calculated and applied twice in the filter stage
89 self.process.buildActions.starSelector = StarSelector()
91 self.process.filterActions.xStars = DownselectVector(
92 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
93 )
94 # downselect the psfFlux as well
95 self.process.filterActions.psfFlux = DownselectVector(
96 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
97 )
98 self.process.filterActions.psfFluxErr = DownselectVector(
99 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
100 )
102 self.process.filterActions.patch = DownselectVector(
103 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector")
104 )
106 self.process.calculateActions.stars = ScatterPlotStatsAction(
107 vectorKey="yStars",
108 )
109 # use the downselected psfFlux
110 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
111 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
112 self.process.calculateActions.stars.fluxType = "psfFlux"
114 self.produce = ScatterPlotWithTwoHists()
116 self.produce.plotTypes = ["stars"]
117 self.produce.xAxisLabel = "PSF Magnitude (mag)"
118 self.produce.magLabel = "PSF Magnitude (mag)"
119 self.produce.addSummaryPlot = True
122class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot):
123 def setDefaults(self):
124 super().setDefaults()
125 self.process.filterActions.yStars = DownselectVector(
126 vectorKey="fracDiff", selector=VectorSelector(vectorKey="starSelector")
127 )
128 self.produce.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
131class E1DiffScatterPlot(BasePsfResidualScatterPlot):
132 def setDefaults(self):
133 super().setDefaults()
134 self.process.filterActions.yStars = DownselectVector(
135 vectorKey="e1Diff", selector=VectorSelector(vectorKey="starSelector")
136 )
137 self.produce.yAxisLabel = "Ellipticty residuals (e1 - e1_PSF)"
140class E2DiffScatterPlot(BasePsfResidualScatterPlot):
141 def setDefaults(self):
142 super().setDefaults()
143 self.process.filterActions.yStars = DownselectVector(
144 vectorKey="e2Diff", selector=VectorSelector(vectorKey="starSelector")
145 )
146 self.produce.yAxisLabel = "Ellipticty residuals (e2 - e2_PSF)"
149class RhoStatisticsPlot(AnalysisPlot, RhoStatisticsMixin):
150 def setDefaults(self):
151 super().setDefaults()
152 self.produce = RhoStatisticsPlotAction()
155class WPerpPSFPlot(WPerpPSF, AnalysisPlot):
156 def setDefaults(self):
157 super().setDefaults()
159 self.produce = ColorColorFitPlot()
160 self.produce.xAxisLabel = "g - r (PSF) [mags]"
161 self.produce.yAxisLabel = "r - i (PSF) [mags]"
162 self.produce.magLabel = "PSF Mag"
163 self.produce.plotName = "wPerp_psfFlux"
166class WPerpCModelPlot(WPerpCModel, AnalysisPlot):
167 def setDefaults(self):
168 super().setDefaults()
170 self.produce = ColorColorFitPlot()
171 self.produce.xAxisLabel = "g - r (CModel) [mags]"
172 self.produce.yAxisLabel = "r - i (CModel) [mags]"
173 self.produce.magLabel = "CModel Mag"
174 self.produce.plotName = "wPerp_cmodelFlux"
177class XPerpPSFPlot(XPerpPSF, AnalysisPlot):
178 def setDefaults(self):
179 super().setDefaults()
181 self.produce = ColorColorFitPlot()
182 self.produce.xAxisLabel = "g - r (PSF) [mags]"
183 self.produce.yAxisLabel = "r - i (PSF) [mags]"
184 self.produce.magLabel = "PSF Mag"
185 self.produce.plotName = "xPerp_psfFlux"
188class XPerpCModelPlot(XPerpCModel, AnalysisPlot):
189 def setDefaults(self):
190 super().setDefaults()
192 self.produce = ColorColorFitPlot()
193 self.produce.xAxisLabel = "g - r (CModel) [mags]"
194 self.produce.yAxisLabel = "r - i (CModel) [mags]"
195 self.produce.magLabel = "CModel Mag"
196 self.produce.plotName = "xPerp_cmodelFlux"
199class YPerpPSFPlot(YPerpPSF, AnalysisPlot):
200 def setDefaults(self):
201 super().setDefaults()
203 self.produce = ColorColorFitPlot()
204 self.produce.xAxisLabel = "r - i (PSF) [mags]"
205 self.produce.yAxisLabel = "i - z (PSF) [mags]"
206 self.produce.magLabel = "PSF Mag"
207 self.produce.plotName = "yPerp_psfFlux"
210class YPerpCModelPlot(YPerpCModel, AnalysisPlot):
211 def setDefaults(self):
212 super().setDefaults()
214 self.produce = ColorColorFitPlot()
215 self.produce.xAxisLabel = "r - i (CModel) [mags]"
216 self.produce.yAxisLabel = "i - z (CModel) [mags]"
217 self.produce.magLabel = "CModel Mag"
218 self.produce.plotName = "yPerp_cmodelFlux"
221class Ap12PsfSkyPlot(AnalysisPlot):
222 def setDefaults(self):
223 super().setDefaults()
224 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
225 # Set this to an empty list to look at the band
226 # the plot is being made in.
227 self.prep.selectors.flagSelector.bands = []
229 self.prep.selectors.snSelector = SnSelector()
230 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux"
231 self.prep.selectors.snSelector.threshold = 300
233 self.prep.selectors.starSelector = StarSelector()
234 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness"
236 # TODO: Can we make these defaults somewhere?
237 self.process.buildActions.xStars = LoadVector()
238 self.process.buildActions.xStars.vectorKey = "coord_ra"
239 self.process.buildActions.yStars = LoadVector()
240 self.process.buildActions.yStars.vectorKey = "coord_dec"
241 self.process.buildActions.starStatMask = SnSelector()
242 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux"
244 self.process.buildActions.zStars = ExtinctionCorrectedMagDiff()
245 self.process.buildActions.zStars.magDiff.col1 = "{band}_ap12Flux"
246 self.process.buildActions.zStars.magDiff.col2 = "{band}_psfFlux"
248 self.produce = SkyPlot()
249 self.produce.plotTypes = ["stars"]
250 self.produce.plotName = "ap12-psf_{band}"
251 self.produce.xAxisLabel = "R.A. (degrees)"
252 self.produce.yAxisLabel = "Dec. (degrees)"
253 self.produce.zAxisLabel = "Ap 12 - PSF [mag]"
254 self.produce.plotOutlines = False
257class TargetRefCatDelta(AnalysisPlot):
258 """Plot the difference in milliseconds between a target catalog and a
259 reference catalog for the coordinate set in `setDefaults`.
260 """
262 parameterizedBand = Field[bool](
263 doc="Does this AnalysisTool support band as a name parameter", default=True
264 )
266 def coaddContext(self) -> None:
267 self.prep = CoaddPrep()
268 self.process.buildActions.starSelector.vectorKey = "{band}_extendedness"
269 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
270 self.process.filterActions.psfFlux = DownselectVector(
271 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
272 )
273 self.process.filterActions.psfFluxErr = DownselectVector(
274 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
275 )
277 def visitContext(self) -> None:
278 self.parameterizedBand = False
279 self.prep = VisitPrep()
280 self.process.buildActions.starSelector.vectorKey = "extendedness"
281 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="psfFlux")
282 self.process.filterActions.psfFlux = DownselectVector(
283 vectorKey="psfFlux", selector=VectorSelector(vectorKey="starSelector")
284 )
285 self.process.filterActions.psfFluxErr = DownselectVector(
286 vectorKey="psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
287 )
289 def setDefaults(self, coordinate):
290 super().setDefaults()
292 self.process.buildActions.starSelector = StarSelector()
293 coordStr = coordinate.lower()
294 self.process.buildActions.astromDiff = AstromDiff(
295 col1=f"coord_{coordStr}_target", col2=f"coord_{coordStr}_ref"
296 )
298 self.process.filterActions.xStars = DownselectVector(
299 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
300 )
301 self.process.filterActions.yStars = DownselectVector(
302 vectorKey="astromDiff", selector=VectorSelector(vectorKey="starSelector")
303 )
305 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
306 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
307 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
308 self.process.calculateActions.stars.fluxType = "psfFlux"
310 self.produce = ScatterPlotWithTwoHists()
312 self.produce.plotTypes = ["stars"]
313 self.produce.xAxisLabel = "PSF Magnitude (mag)"
314 self.produce.yAxisLabel = f"${coordinate}_{{target}} - {coordinate}_{{ref}}$ (marcsec)"
315 self.produce.magLabel = "PSF Magnitude (mag)"
318class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta):
319 """Plot the difference in milliseconds between the RA of a target catalog
320 and a reference catalog
321 """
323 def setDefaults(self):
324 super().setDefaults(coordinate="RA")
327class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta):
328 """Plot the difference in milliseconds between the Dec of a target catalog
329 and a reference catalog
330 """
332 def setDefaults(self):
333 super().setDefaults(coordinate="Dec")
336class TargetRefCatDeltaSkyPlot(AnalysisPlot):
337 """Base class for plotting the RA/Dec distribution of stars, with the
338 difference between the RA or Dec of the target and reference catalog as
339 the color.
340 """
342 parameterizedBand = Field[bool](
343 doc="Does this AnalysisTool support band as a name parameter", default=True
344 )
346 def coaddContext(self) -> None:
347 self.prep = CoaddPrep()
349 self.process.buildActions.starStatMask = SnSelector()
350 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux"
352 def visitContext(self) -> None:
353 self.parameterizedBand = False
354 self.prep = VisitPrep()
356 self.process.buildActions.starStatMask = SnSelector()
357 self.process.buildActions.starStatMask.fluxType = "psfFlux"
359 def setDefaults(self, coordinate):
360 super().setDefaults()
362 coordStr = coordinate.lower()
363 self.process.buildActions.zStars = AstromDiff(
364 col1=f"coord_{coordStr}_target", col2=f"coord_{coordStr}_ref"
365 )
366 self.process.buildActions.xStars = LoadVector()
367 self.process.buildActions.xStars.vectorKey = "coord_ra_target"
368 self.process.buildActions.yStars = LoadVector()
369 self.process.buildActions.yStars.vectorKey = "coord_dec_target"
371 self.produce = SkyPlot()
372 self.produce.plotTypes = ["stars"]
373 self.produce.plotName = f"astromDiffSky_{coordinate}"
374 self.produce.xAxisLabel = "R.A. (degrees)"
375 self.produce.yAxisLabel = "Dec. (degrees)"
376 self.produce.zAxisLabel = f"${coordinate}_{{target}} - {coordinate}_{{ref}}$ (marcsec)"
377 self.produce.plotOutlines = False
380class TargetRefCatDeltaRASkyPlot(TargetRefCatDeltaSkyPlot):
381 """Plot the difference in milliseconds between the RA of a target catalog
382 and a reference catalog as a function of RA and Dec.
383 """
385 def setDefaults(self):
386 super().setDefaults(coordinate="RA")
389class TargetRefCatDeltaDecSkyPlot(TargetRefCatDeltaSkyPlot):
390 """Plot the difference in milliseconds between the Dec of a target catalog
391 and a reference catalog as a function of RA and Dec.
392 """
394 def setDefaults(self):
395 super().setDefaults(coordinate="Dec")
398class FluxRatioPlot(AnalysisPlot, BasePsfApRatio):
399 """Plot a histogram of the PSF and AP flux ratios of sources."""
401 def setDefaults(self):
402 super().setDefaults()
404 self.produce = HistPlot()
406 self.produce.panels["panel_flux"] = HistPanel()
407 self.produce.panels["panel_flux"].label = "Psf/Ap Ratio"
408 self.produce.panels["panel_flux"].hists = dict(fluxRatioMetric="Ratio")
411class SourcesPlot(AnalysisPlot, BaseSources):
412 """Plot a histogram of the associated and unassociated sources."""
414 def setDefaults(self, **kwargs):
415 super().setDefaults()
417 self.process.calculateActions.associatedCount = CountAction(vectorKey="associatedVector")
418 self.process.calculateActions.unassociatedCount = CountAction(vectorKey="unassociatedVector")
420 self.produce = BarPlot()
421 self.produce.panels["panel_source"] = BarPanel()
422 self.produce.panels["panel_source"].label = "N Assoc and Unassoc Sources"
423 self.produce.panels["panel_source"].bars = dict(
424 associatedVector="Associated Sources",
425 unassociatedVector="Unassociated Sources",
426 )