Coverage for python/lsst/analysis/tools/analysisPlots/analysisPlots.py: 30%
186 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-23 09:29 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-23 09:29 +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 "RhoStatisticsPlot",
38)
40from lsst.pex.config import Field
42from ..actions.plot.barPlots import BarPanel, BarPlot
43from ..actions.plot.colorColorFitPlot import ColorColorFitPlot
44from ..actions.plot.histPlot import HistPanel, HistPlot
45from ..actions.plot.rhoStatisticsPlot import RhoStatisticsPlotAction
46from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
47from ..actions.plot.skyPlot import SkyPlot
48from ..actions.scalar import CountAction
49from ..actions.vector import (
50 AstromDiff,
51 CoaddPlotFlagSelector,
52 DownselectVector,
53 ExtinctionCorrectedMagDiff,
54 LoadVector,
55 MagColumnNanoJansky,
56 SnSelector,
57 StarSelector,
58 VectorSelector,
59)
60from ..analysisParts.baseFluxRatio import BasePsfApRatio
61from ..analysisParts.baseSources import BaseSources
62from ..analysisParts.genericPrep import CoaddPrep, VisitPrep
63from ..analysisParts.rhoStatistics import RhoStatisticsMixin
64from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin
65from ..analysisParts.stellarLocus import WPerpCModel, WPerpPSF, XPerpCModel, XPerpPSF, YPerpCModel, YPerpPSF
66from ..interfaces import AnalysisPlot
69class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin):
70 """Base class for scatter plots of PSF residuals.
72 This is shared by size and ellipticity plots.
73 """
75 def setDefaults(self):
76 super().setDefaults()
77 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
78 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
80 self.process.buildActions.patchWhole = LoadVector()
81 self.process.buildActions.patchWhole.vectorKey = "patch"
83 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
84 # pre-compute a stellar selector mask so it can be used in the filter
85 # actions while only being computed once, alternatively the stellar
86 # selector could be calculated and applied twice in the filter stage
87 self.process.buildActions.starSelector = StarSelector()
89 self.process.filterActions.xStars = DownselectVector(
90 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
91 )
92 # downselect the psfFlux as well
93 self.process.filterActions.psfFlux = DownselectVector(
94 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
95 )
96 self.process.filterActions.psfFluxErr = DownselectVector(
97 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
98 )
100 self.process.filterActions.patch = DownselectVector(
101 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector")
102 )
104 self.process.calculateActions.stars = ScatterPlotStatsAction(
105 vectorKey="yStars",
106 )
107 # use the downselected psfFlux
108 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
109 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
110 self.process.calculateActions.stars.fluxType = "psfFlux"
112 self.produce = ScatterPlotWithTwoHists()
114 self.produce.plotTypes = ["stars"]
115 self.produce.xAxisLabel = "PSF Magnitude (mag)"
116 self.produce.magLabel = "PSF Magnitude (mag)"
117 self.produce.addSummaryPlot = True
120class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot):
121 def setDefaults(self):
122 super().setDefaults()
123 self.process.filterActions.yStars = DownselectVector(
124 vectorKey="fracDiff", selector=VectorSelector(vectorKey="starSelector")
125 )
126 self.produce.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
129class E1DiffScatterPlot(BasePsfResidualScatterPlot):
130 def setDefaults(self):
131 super().setDefaults()
132 self.process.filterActions.yStars = DownselectVector(
133 vectorKey="e1Diff", selector=VectorSelector(vectorKey="starSelector")
134 )
135 self.produce.yAxisLabel = "Ellipticty residuals (e1 - e1_PSF)"
138class E2DiffScatterPlot(BasePsfResidualScatterPlot):
139 def setDefaults(self):
140 super().setDefaults()
141 self.process.filterActions.yStars = DownselectVector(
142 vectorKey="e2Diff", selector=VectorSelector(vectorKey="starSelector")
143 )
144 self.produce.yAxisLabel = "Ellipticty residuals (e2 - e2_PSF)"
147class RhoStatisticsPlot(AnalysisPlot, RhoStatisticsMixin):
148 def setDefaults(self):
149 super().setDefaults()
150 self.produce = RhoStatisticsPlotAction()
153class WPerpPSFPlot(WPerpPSF, AnalysisPlot):
154 def setDefaults(self):
155 super().setDefaults()
157 self.produce = ColorColorFitPlot()
158 self.produce.xAxisLabel = "g - r (PSF) [mags]"
159 self.produce.yAxisLabel = "r - i (PSF) [mags]"
160 self.produce.magLabel = "PSF Mag"
161 self.produce.plotName = "wPerp_psfFlux"
164class WPerpCModelPlot(WPerpCModel, AnalysisPlot):
165 def setDefaults(self):
166 super().setDefaults()
168 self.produce = ColorColorFitPlot()
169 self.produce.xAxisLabel = "g - r (CModel) [mags]"
170 self.produce.yAxisLabel = "r - i (CModel) [mags]"
171 self.produce.magLabel = "CModel Mag"
172 self.produce.plotName = "wPerp_cmodelFlux"
175class XPerpPSFPlot(XPerpPSF, AnalysisPlot):
176 def setDefaults(self):
177 super().setDefaults()
179 self.produce = ColorColorFitPlot()
180 self.produce.xAxisLabel = "g - r (PSF) [mags]"
181 self.produce.yAxisLabel = "r - i (PSF) [mags]"
182 self.produce.magLabel = "PSF Mag"
183 self.produce.plotName = "xPerp_psfFlux"
186class XPerpCModelPlot(XPerpCModel, AnalysisPlot):
187 def setDefaults(self):
188 super().setDefaults()
190 self.produce = ColorColorFitPlot()
191 self.produce.xAxisLabel = "g - r (CModel) [mags]"
192 self.produce.yAxisLabel = "r - i (CModel) [mags]"
193 self.produce.magLabel = "CModel Mag"
194 self.produce.plotName = "xPerp_cmodelFlux"
197class YPerpPSFPlot(YPerpPSF, AnalysisPlot):
198 def setDefaults(self):
199 super().setDefaults()
201 self.produce = ColorColorFitPlot()
202 self.produce.xAxisLabel = "r - i (PSF) [mags]"
203 self.produce.yAxisLabel = "i - z (PSF) [mags]"
204 self.produce.magLabel = "PSF Mag"
205 self.produce.plotName = "yPerp_psfFlux"
208class YPerpCModelPlot(YPerpCModel, AnalysisPlot):
209 def setDefaults(self):
210 super().setDefaults()
212 self.produce = ColorColorFitPlot()
213 self.produce.xAxisLabel = "r - i (CModel) [mags]"
214 self.produce.yAxisLabel = "i - z (CModel) [mags]"
215 self.produce.magLabel = "CModel Mag"
216 self.produce.plotName = "yPerp_cmodelFlux"
219class Ap12PsfSkyPlot(AnalysisPlot):
220 def setDefaults(self):
221 super().setDefaults()
222 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
223 # Set this to an empty list to look at the band
224 # the plot is being made in.
225 self.prep.selectors.flagSelector.bands = []
227 self.prep.selectors.snSelector = SnSelector()
228 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux"
229 self.prep.selectors.snSelector.threshold = 300
231 self.prep.selectors.starSelector = StarSelector()
232 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness"
234 # TODO: Can we make these defaults somewhere?
235 self.process.buildActions.xStars = LoadVector()
236 self.process.buildActions.xStars.vectorKey = "coord_ra"
237 self.process.buildActions.yStars = LoadVector()
238 self.process.buildActions.yStars.vectorKey = "coord_dec"
239 self.process.buildActions.starStatMask = SnSelector()
240 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux"
242 self.process.buildActions.zStars = ExtinctionCorrectedMagDiff()
243 self.process.buildActions.zStars.magDiff.col1 = "{band}_ap12Flux"
244 self.process.buildActions.zStars.magDiff.col2 = "{band}_psfFlux"
246 self.produce = SkyPlot()
247 self.produce.plotTypes = ["stars"]
248 self.produce.plotName = "ap12-psf_{band}"
249 self.produce.xAxisLabel = "R.A. (degrees)"
250 self.produce.yAxisLabel = "Dec. (degrees)"
251 self.produce.zAxisLabel = "Ap 12 - PSF [mag]"
252 self.produce.plotOutlines = False
255class TargetRefCatDelta(AnalysisPlot):
256 """Plot the difference in milliseconds between a target catalog and a
257 reference catalog for the coordinate set in `setDefaults`.
258 """
260 parameterizedBand = Field[bool](
261 doc="Does this AnalysisTool support band as a name parameter", default=True
262 )
264 def coaddContext(self) -> None:
265 self.prep = CoaddPrep()
266 self.process.buildActions.starSelector.vectorKey = "{band}_extendedness"
267 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
268 self.process.filterActions.psfFlux = DownselectVector(
269 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
270 )
271 self.process.filterActions.psfFluxErr = DownselectVector(
272 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
273 )
275 def visitContext(self) -> None:
276 self.parameterizedBand = False
277 self.prep = VisitPrep()
278 self.process.buildActions.starSelector.vectorKey = "extendedness"
279 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="psfFlux")
280 self.process.filterActions.psfFlux = DownselectVector(
281 vectorKey="psfFlux", selector=VectorSelector(vectorKey="starSelector")
282 )
283 self.process.filterActions.psfFluxErr = DownselectVector(
284 vectorKey="psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
285 )
287 def setDefaults(self, coordinate):
288 super().setDefaults()
290 self.process.buildActions.starSelector = StarSelector()
291 coordStr = coordinate.lower()
292 self.process.buildActions.astromDiff = AstromDiff(
293 col1=f"coord_{coordStr}_target", col2=f"coord_{coordStr}_ref"
294 )
296 self.process.filterActions.xStars = DownselectVector(
297 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
298 )
299 self.process.filterActions.yStars = DownselectVector(
300 vectorKey="astromDiff", selector=VectorSelector(vectorKey="starSelector")
301 )
303 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
304 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
305 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
306 self.process.calculateActions.stars.fluxType = "psfFlux"
308 self.produce = ScatterPlotWithTwoHists()
310 self.produce.plotTypes = ["stars"]
311 self.produce.xAxisLabel = "PSF Magnitude (mag)"
312 self.produce.yAxisLabel = f"${coordinate}_{{target}} - {coordinate}_{{ref}}$ (marcsec)"
313 self.produce.magLabel = "PSF Magnitude (mag)"
316class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta):
317 """Plot the difference in milliseconds between the RA of a target catalog
318 and a reference catalog
319 """
321 def setDefaults(self):
322 super().setDefaults(coordinate="RA")
325class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta):
326 """Plot the difference in milliseconds between the Dec of a target catalog
327 and a reference catalog
328 """
330 def setDefaults(self):
331 super().setDefaults(coordinate="Dec")
334class FluxRatioPlot(AnalysisPlot, BasePsfApRatio):
335 """Plot a histogram of the PSF and AP flux ratios of sources."""
337 def setDefaults(self):
338 super().setDefaults()
340 self.produce = HistPlot()
342 self.produce.panels["panel_flux"] = HistPanel()
343 self.produce.panels["panel_flux"].label = "Psf/Ap Ratio"
344 self.produce.panels["panel_flux"].hists = dict(fluxRatioMetric="Ratio")
347class SourcesPlot(AnalysisPlot, BaseSources):
348 """Plot a histogram of the associated and unassociated sources."""
350 def setDefaults(self, **kwargs):
351 super().setDefaults()
353 self.process.calculateActions.associatedCount = CountAction(vectorKey="associatedVector")
354 self.process.calculateActions.unassociatedCount = CountAction(vectorKey="unassociatedVector")
356 self.produce = BarPlot()
357 self.produce.panels["panel_source"] = BarPanel()
358 self.produce.panels["panel_source"].label = "N Assoc and Unassoc Sources"
359 self.produce.panels["panel_source"].bars = dict(
360 associatedVector="Associated Sources",
361 unassociatedVector="Unassociated Sources",
362 )