Coverage for python/lsst/analysis/tools/analysisPlots/analysisPlots.py: 25%
150 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-03 01:36 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-03 01:36 -0700
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 "WPerpPSFPlot",
28 "Ap12PsfSkyPlot",
29 "TargetRefCatDeltaRAScatterPlot",
30 "TargetRefCatDeltaRAScatterPlot",
31)
33from lsst.pex.config import Field
35from ..actions.keyedData.stellarLocusFit import StellarLocusFitAction
36from ..actions.plot.colorColorFitPlot import ColorColorFitPlot
37from ..actions.plot.histPlot import HistPanel, HistPlot
38from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
39from ..actions.plot.skyPlot import SkyPlot
40from ..actions.scalar import ApproxFloor
41from ..actions.vector import (
42 AstromDiff,
43 CoaddPlotFlagSelector,
44 DownselectVector,
45 ExtinctionCorrectedMagDiff,
46 LoadVector,
47 MagColumnNanoJansky,
48 SnSelector,
49 StarSelector,
50 VectorSelector,
51)
52from ..analysisParts.baseFluxRatio import BasePsfApRatio
53from ..analysisParts.genericPrep import CoaddPrep, VisitPrep
54from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin
55from ..interfaces import AnalysisPlot
58class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin):
59 """Base class for scatter plots of PSF residuals.
61 This is shared by size and ellipticity plots.
62 """
64 def setDefaults(self):
65 super().setDefaults()
66 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
67 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
69 self.process.buildActions.patchWhole = LoadVector()
70 self.process.buildActions.patchWhole.vectorKey = "patch"
72 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
73 # pre-compute a stellar selector mask so it can be used in the filter
74 # actions while only being computed once, alternatively the stellar
75 # selector could be calculated and applied twice in the filter stage
76 self.process.buildActions.starSelector = StarSelector()
78 self.process.filterActions.xStars = DownselectVector(
79 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
80 )
81 # downselect the psfFlux as well
82 self.process.filterActions.psfFlux = DownselectVector(
83 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
84 )
85 self.process.filterActions.psfFluxErr = DownselectVector(
86 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
87 )
89 self.process.filterActions.patch = DownselectVector(
90 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector")
91 )
93 self.process.calculateActions.stars = ScatterPlotStatsAction(
94 vectorKey="yStars",
95 )
96 # use the downselected psfFlux
97 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
98 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
99 self.process.calculateActions.stars.fluxType = "psfFlux"
101 self.produce = ScatterPlotWithTwoHists()
103 self.produce.plotTypes = ["stars"]
104 self.produce.xAxisLabel = "PSF Magnitude (mag)"
105 self.produce.magLabel = "PSF Magnitude (mag)"
106 self.produce.addSummaryPlot = True
109class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot):
110 def setDefaults(self):
111 super().setDefaults()
112 self.process.filterActions.yStars = DownselectVector(
113 vectorKey="fracDiff", selector=VectorSelector(vectorKey="starSelector")
114 )
115 self.produce.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
118class E1DiffScatterPlot(BasePsfResidualScatterPlot):
119 def setDefaults(self):
120 super().setDefaults()
121 self.process.filterActions.yStars = DownselectVector(
122 vectorKey="e1Diff", selector=VectorSelector(vectorKey="starSelector")
123 )
124 self.produce.yAxisLabel = "Ellipticty residuals (e1 - e1_PSF)"
127class E2DiffScatterPlot(BasePsfResidualScatterPlot):
128 def setDefaults(self):
129 super().setDefaults()
130 self.process.filterActions.yStars = DownselectVector(
131 vectorKey="e2Diff", selector=VectorSelector(vectorKey="starSelector")
132 )
133 self.produce.yAxisLabel = "Ellipticty residuals (e2 - e2_PSF)"
136class WPerpPSFPlot(AnalysisPlot):
137 # WPerp does not support running in multiband mode
138 multiband: bool = False
140 def setDefaults(self):
141 super().setDefaults()
142 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
143 self.prep.selectors.flagSelector.bands = ["g", "r", "i"]
145 self.prep.selectors.snSelector = SnSelector()
146 self.prep.selectors.snSelector.bands = ["r"]
147 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux"
148 self.prep.selectors.snSelector.threshold = 300
150 self.prep.selectors.starSelector = StarSelector()
151 self.prep.selectors.starSelector.vectorKey = "r_extendedness"
153 self.process.buildActions.x = ExtinctionCorrectedMagDiff()
154 self.process.buildActions.x.magDiff.col1 = "g_psfFlux"
155 self.process.buildActions.x.magDiff.col2 = "r_psfFlux"
156 self.process.buildActions.x.magDiff.returnMillimags = False
157 self.process.buildActions.y = ExtinctionCorrectedMagDiff()
158 self.process.buildActions.y.magDiff.col1 = "r_psfFlux"
159 self.process.buildActions.y.magDiff.col2 = "i_psfFlux"
160 self.process.buildActions.y.magDiff.returnMillimags = False
161 self.process.buildActions.mag = MagColumnNanoJansky(vectorKey="r_psfFlux")
163 self.process.calculateActions.approxMagDepth = ApproxFloor(vectorKey="mag")
164 self.process.calculateActions.wPerp_psfFlux = StellarLocusFitAction()
165 self.process.calculateActions.wPerp_psfFlux.stellarLocusFitDict = {
166 "xMin": 0.28,
167 "xMax": 1.0,
168 "yMin": 0.02,
169 "yMax": 0.48,
170 "mHW": 0.52,
171 "bHW": -0.08,
172 }
174 self.produce = ColorColorFitPlot()
175 self.produce.xAxisLabel = "g - r (PSF) [mags]"
176 self.produce.yAxisLabel = "r - i (PSF) [mags]"
177 self.produce.magLabel = "PSF Mag"
178 self.produce.plotName = "wPerp_psfFlux"
181class Ap12PsfSkyPlot(AnalysisPlot):
182 def setDefaults(self):
183 super().setDefaults()
184 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
185 self.prep.selectors.flagSelector.bands = ["{band}"]
187 self.prep.selectors.snSelector = SnSelector()
188 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux"
189 self.prep.selectors.snSelector.threshold = 300
191 self.prep.selectors.starSelector = StarSelector()
192 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness"
194 # TODO: Can we make these defaults somewhere?
195 self.process.buildActions.xStars = LoadVector()
196 self.process.buildActions.xStars.vectorKey = "coord_ra"
197 self.process.buildActions.yStars = LoadVector()
198 self.process.buildActions.yStars.vectorKey = "coord_dec"
199 self.process.buildActions.starStatMask = SnSelector()
200 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux"
202 self.process.buildActions.zStars = ExtinctionCorrectedMagDiff()
203 self.process.buildActions.zStars.magDiff.col1 = "{band}_ap12Flux"
204 self.process.buildActions.zStars.magDiff.col2 = "{band}_psfFlux"
206 self.produce = SkyPlot()
207 self.produce.plotTypes = ["stars"]
208 self.produce.plotName = "ap12-psf_{band}"
209 self.produce.xAxisLabel = "R.A. (degrees)"
210 self.produce.yAxisLabel = "Dec. (degrees)"
211 self.produce.zAxisLabel = "Ap 12 - PSF [mag]"
212 self.produce.plotOutlines = False
215class TargetRefCatDelta(AnalysisPlot):
216 """Plot the difference in milliseconds between a target catalog and a
217 reference catalog for the coordinate set in `setDefaults`.
218 """
220 parameterizedBand = Field[bool](
221 doc="Does this AnalysisTool support band as a name parameter", default=True
222 )
224 def coaddContext(self) -> None:
225 self.prep = CoaddPrep()
226 self.process.buildActions.starSelector.vectorKey = "{band}_extendedness"
227 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
228 self.process.filterActions.psfFlux = DownselectVector(
229 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
230 )
231 self.process.filterActions.psfFluxErr = DownselectVector(
232 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
233 )
235 def visitContext(self) -> None:
236 self.parameterizedBand = False
237 self.prep = VisitPrep()
238 self.process.buildActions.starSelector.vectorKey = "extendedness"
239 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="psfFlux")
240 self.process.filterActions.psfFlux = DownselectVector(
241 vectorKey="psfFlux", selector=VectorSelector(vectorKey="starSelector")
242 )
243 self.process.filterActions.psfFluxErr = DownselectVector(
244 vectorKey="psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
245 )
247 def setDefaults(self, coordinate):
248 super().setDefaults()
250 self.process.buildActions.starSelector = StarSelector()
251 coordStr = coordinate.lower()
252 self.process.buildActions.astromDiff = AstromDiff(
253 col1=f"coord_{coordStr}_target", col2=f"coord_{coordStr}_ref"
254 )
256 self.process.filterActions.xStars = DownselectVector(
257 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
258 )
259 self.process.filterActions.yStars = DownselectVector(
260 vectorKey="astromDiff", selector=VectorSelector(vectorKey="starSelector")
261 )
263 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
264 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
265 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
266 self.process.calculateActions.stars.fluxType = "psfFlux"
268 self.produce = ScatterPlotWithTwoHists()
270 self.produce.plotTypes = ["stars"]
271 self.produce.xAxisLabel = "PSF Magnitude (mag)"
272 self.produce.yAxisLabel = f"${coordinate}_{{target}} - {coordinate}_{{ref}}$ (marcsec)"
273 self.produce.magLabel = "PSF Magnitude (mag)"
276class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta):
277 """Plot the difference in milliseconds between the RA of a target catalog
278 and a reference catalog
279 """
281 def setDefaults(self):
282 super().setDefaults(coordinate="RA")
285class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta):
286 """Plot the difference in milliseconds between the Dec of a target catalog
287 and a reference catalog
288 """
290 def setDefaults(self):
291 super().setDefaults(coordinate="Dec")
294class FluxRatioPlot(AnalysisPlot, BasePsfApRatio):
295 """Plot a histogram of the PSF and AP flux ratios of sources."""
297 def setDefaults(self):
298 super().setDefaults()
300 self.produce = HistPlot()
302 self.produce.panels["panel_flux"] = HistPanel()
303 self.produce.panels["panel_flux"].label = "Psf/Ap Ratio"
304 self.produce.panels["panel_flux"].hists = dict(fluxRatioMetric="Ratio")