Coverage for python/lsst/analysis/tools/analysisPlots/analysisPlots.py: 28%
180 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-16 10:52 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-16 10:52 +0000
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 "TargetRefCatDeltaRAScatterPlot",
36 "SourcesPlot",
37)
39from lsst.pex.config import Field
41from ..actions.plot.barPlots import BarPanel, BarPlot
42from ..actions.plot.colorColorFitPlot import ColorColorFitPlot
43from ..actions.plot.histPlot import HistPanel, HistPlot
44from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
45from ..actions.plot.skyPlot import SkyPlot
46from ..actions.scalar import CountAction
47from ..actions.vector import (
48 AstromDiff,
49 CoaddPlotFlagSelector,
50 DownselectVector,
51 ExtinctionCorrectedMagDiff,
52 LoadVector,
53 MagColumnNanoJansky,
54 SnSelector,
55 StarSelector,
56 VectorSelector,
57)
58from ..analysisParts.baseFluxRatio import BasePsfApRatio
59from ..analysisParts.baseSources import BaseSources
60from ..analysisParts.genericPrep import CoaddPrep, VisitPrep
61from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin
62from ..analysisParts.stellarLocus import WPerpCModel, WPerpPSF, XPerpCModel, XPerpPSF, YPerpCModel, YPerpPSF
63from ..interfaces import AnalysisPlot
66class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin):
67 """Base class for scatter plots of PSF residuals.
69 This is shared by size and ellipticity plots.
70 """
72 def setDefaults(self):
73 super().setDefaults()
74 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
75 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
77 self.process.buildActions.patchWhole = LoadVector()
78 self.process.buildActions.patchWhole.vectorKey = "patch"
80 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
81 # pre-compute a stellar selector mask so it can be used in the filter
82 # actions while only being computed once, alternatively the stellar
83 # selector could be calculated and applied twice in the filter stage
84 self.process.buildActions.starSelector = StarSelector()
86 self.process.filterActions.xStars = DownselectVector(
87 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
88 )
89 # downselect the psfFlux as well
90 self.process.filterActions.psfFlux = DownselectVector(
91 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
92 )
93 self.process.filterActions.psfFluxErr = DownselectVector(
94 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
95 )
97 self.process.filterActions.patch = DownselectVector(
98 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector")
99 )
101 self.process.calculateActions.stars = ScatterPlotStatsAction(
102 vectorKey="yStars",
103 )
104 # use the downselected psfFlux
105 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
106 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
107 self.process.calculateActions.stars.fluxType = "psfFlux"
109 self.produce = ScatterPlotWithTwoHists()
111 self.produce.plotTypes = ["stars"]
112 self.produce.xAxisLabel = "PSF Magnitude (mag)"
113 self.produce.magLabel = "PSF Magnitude (mag)"
114 self.produce.addSummaryPlot = True
117class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot):
118 def setDefaults(self):
119 super().setDefaults()
120 self.process.filterActions.yStars = DownselectVector(
121 vectorKey="fracDiff", selector=VectorSelector(vectorKey="starSelector")
122 )
123 self.produce.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
126class E1DiffScatterPlot(BasePsfResidualScatterPlot):
127 def setDefaults(self):
128 super().setDefaults()
129 self.process.filterActions.yStars = DownselectVector(
130 vectorKey="e1Diff", selector=VectorSelector(vectorKey="starSelector")
131 )
132 self.produce.yAxisLabel = "Ellipticty residuals (e1 - e1_PSF)"
135class E2DiffScatterPlot(BasePsfResidualScatterPlot):
136 def setDefaults(self):
137 super().setDefaults()
138 self.process.filterActions.yStars = DownselectVector(
139 vectorKey="e2Diff", selector=VectorSelector(vectorKey="starSelector")
140 )
141 self.produce.yAxisLabel = "Ellipticty residuals (e2 - e2_PSF)"
144class WPerpPSFPlot(WPerpPSF, AnalysisPlot):
145 def setDefaults(self):
146 super().setDefaults()
148 self.produce = ColorColorFitPlot()
149 self.produce.xAxisLabel = "g - r (PSF) [mags]"
150 self.produce.yAxisLabel = "r - i (PSF) [mags]"
151 self.produce.magLabel = "PSF Mag"
152 self.produce.plotName = "wPerp_psfFlux"
155class WPerpCModelPlot(WPerpCModel, AnalysisPlot):
156 def setDefaults(self):
157 super().setDefaults()
159 self.produce = ColorColorFitPlot()
160 self.produce.xAxisLabel = "g - r (CModel) [mags]"
161 self.produce.yAxisLabel = "r - i (CModel) [mags]"
162 self.produce.magLabel = "CModel Mag"
163 self.produce.plotName = "wPerp_cmodelFlux"
166class XPerpPSFPlot(XPerpPSF, AnalysisPlot):
167 def setDefaults(self):
168 super().setDefaults()
170 self.produce = ColorColorFitPlot()
171 self.produce.xAxisLabel = "g - r (PSF) [mags]"
172 self.produce.yAxisLabel = "r - i (PSF) [mags]"
173 self.produce.magLabel = "PSF Mag"
174 self.produce.plotName = "xPerp_psfFlux"
177class XPerpCModelPlot(XPerpCModel, AnalysisPlot):
178 def setDefaults(self):
179 super().setDefaults()
181 self.produce = ColorColorFitPlot()
182 self.produce.xAxisLabel = "g - r (CModel) [mags]"
183 self.produce.yAxisLabel = "r - i (CModel) [mags]"
184 self.produce.magLabel = "CModel Mag"
185 self.produce.plotName = "xPerp_cmodelFlux"
188class YPerpPSFPlot(YPerpPSF, AnalysisPlot):
189 def setDefaults(self):
190 super().setDefaults()
192 self.produce = ColorColorFitPlot()
193 self.produce.xAxisLabel = "r - i (PSF) [mags]"
194 self.produce.yAxisLabel = "i - z (PSF) [mags]"
195 self.produce.magLabel = "PSF Mag"
196 self.produce.plotName = "yPerp_psfFlux"
199class YPerpCModelPlot(YPerpCModel, AnalysisPlot):
200 def setDefaults(self):
201 super().setDefaults()
203 self.produce = ColorColorFitPlot()
204 self.produce.xAxisLabel = "r - i (CModel) [mags]"
205 self.produce.yAxisLabel = "i - z (CModel) [mags]"
206 self.produce.magLabel = "CModel Mag"
207 self.produce.plotName = "yPerp_cmodelFlux"
210class Ap12PsfSkyPlot(AnalysisPlot):
211 def setDefaults(self):
212 super().setDefaults()
213 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
214 # Set this to an empty list to look at the band
215 # the plot is being made in.
216 self.prep.selectors.flagSelector.bands = []
218 self.prep.selectors.snSelector = SnSelector()
219 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux"
220 self.prep.selectors.snSelector.threshold = 300
222 self.prep.selectors.starSelector = StarSelector()
223 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness"
225 # TODO: Can we make these defaults somewhere?
226 self.process.buildActions.xStars = LoadVector()
227 self.process.buildActions.xStars.vectorKey = "coord_ra"
228 self.process.buildActions.yStars = LoadVector()
229 self.process.buildActions.yStars.vectorKey = "coord_dec"
230 self.process.buildActions.starStatMask = SnSelector()
231 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux"
233 self.process.buildActions.zStars = ExtinctionCorrectedMagDiff()
234 self.process.buildActions.zStars.magDiff.col1 = "{band}_ap12Flux"
235 self.process.buildActions.zStars.magDiff.col2 = "{band}_psfFlux"
237 self.produce = SkyPlot()
238 self.produce.plotTypes = ["stars"]
239 self.produce.plotName = "ap12-psf_{band}"
240 self.produce.xAxisLabel = "R.A. (degrees)"
241 self.produce.yAxisLabel = "Dec. (degrees)"
242 self.produce.zAxisLabel = "Ap 12 - PSF [mag]"
243 self.produce.plotOutlines = False
246class TargetRefCatDelta(AnalysisPlot):
247 """Plot the difference in milliseconds between a target catalog and a
248 reference catalog for the coordinate set in `setDefaults`.
249 """
251 parameterizedBand = Field[bool](
252 doc="Does this AnalysisTool support band as a name parameter", default=True
253 )
255 def coaddContext(self) -> None:
256 self.prep = CoaddPrep()
257 self.process.buildActions.starSelector.vectorKey = "{band}_extendedness"
258 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
259 self.process.filterActions.psfFlux = DownselectVector(
260 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
261 )
262 self.process.filterActions.psfFluxErr = DownselectVector(
263 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
264 )
266 def visitContext(self) -> None:
267 self.parameterizedBand = False
268 self.prep = VisitPrep()
269 self.process.buildActions.starSelector.vectorKey = "extendedness"
270 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="psfFlux")
271 self.process.filterActions.psfFlux = DownselectVector(
272 vectorKey="psfFlux", selector=VectorSelector(vectorKey="starSelector")
273 )
274 self.process.filterActions.psfFluxErr = DownselectVector(
275 vectorKey="psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
276 )
278 def setDefaults(self, coordinate):
279 super().setDefaults()
281 self.process.buildActions.starSelector = StarSelector()
282 coordStr = coordinate.lower()
283 self.process.buildActions.astromDiff = AstromDiff(
284 col1=f"coord_{coordStr}_target", col2=f"coord_{coordStr}_ref"
285 )
287 self.process.filterActions.xStars = DownselectVector(
288 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
289 )
290 self.process.filterActions.yStars = DownselectVector(
291 vectorKey="astromDiff", selector=VectorSelector(vectorKey="starSelector")
292 )
294 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
295 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
296 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
297 self.process.calculateActions.stars.fluxType = "psfFlux"
299 self.produce = ScatterPlotWithTwoHists()
301 self.produce.plotTypes = ["stars"]
302 self.produce.xAxisLabel = "PSF Magnitude (mag)"
303 self.produce.yAxisLabel = f"${coordinate}_{{target}} - {coordinate}_{{ref}}$ (marcsec)"
304 self.produce.magLabel = "PSF Magnitude (mag)"
307class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta):
308 """Plot the difference in milliseconds between the RA of a target catalog
309 and a reference catalog
310 """
312 def setDefaults(self):
313 super().setDefaults(coordinate="RA")
316class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta):
317 """Plot the difference in milliseconds between the Dec of a target catalog
318 and a reference catalog
319 """
321 def setDefaults(self):
322 super().setDefaults(coordinate="Dec")
325class FluxRatioPlot(AnalysisPlot, BasePsfApRatio):
326 """Plot a histogram of the PSF and AP flux ratios of sources."""
328 def setDefaults(self):
329 super().setDefaults()
331 self.produce = HistPlot()
333 self.produce.panels["panel_flux"] = HistPanel()
334 self.produce.panels["panel_flux"].label = "Psf/Ap Ratio"
335 self.produce.panels["panel_flux"].hists = dict(fluxRatioMetric="Ratio")
338class SourcesPlot(AnalysisPlot, BaseSources):
339 """Plot a histogram of the associated and unassociated sources."""
341 def setDefaults(self, **kwargs):
342 super().setDefaults()
344 self.process.calculateActions.associatedCount = CountAction(vectorKey="associatedVector")
345 self.process.calculateActions.unassociatedCount = CountAction(vectorKey="unassociatedVector")
347 self.produce = BarPlot()
348 self.produce.panels["panel_source"] = BarPanel()
349 self.produce.panels["panel_source"].label = "N Assoc and Unassoc Sources"
350 self.produce.panels["panel_source"].bars = dict(
351 associatedVector="Associated Sources",
352 unassociatedVector="Unassociated Sources",
353 )