Coverage for python/lsst/analysis/tools/atools/refCatMatchPlots.py: 22%
364 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-13 10:07 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-13 10:07 +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 "TargetRefCatDeltaRAScatterPlot",
25 "TargetRefCatDeltaDecScatterPlot",
26 "TargetRefCatDeltaRASkyPlot",
27 "TargetRefCatDeltaDecSkyPlot",
28 "TargetRefCatDeltaScatterPhotom",
29 "TargetRefCatDeltaScatterAstrom",
30 "TargetRefCatDeltaSkyPlotPhotom",
31 "TargetRefCatDeltaPsfScatterPlot",
32 "TargetRefCatDeltaCModelScatterPlot",
33 "TargetRefCatDeltaCModelSkyPlot",
34 "TargetRefCatDeltaPsfSkyPlot",
35 "TargetRefCatDeltaRASkyVisitPlot",
36 "TargetRefCatDeltaAp09ScatterVisitPlot",
37 "TargetRefCatDeltaPsfScatterVisitPlot",
38 "TargetRefCatDeltaAp09SkyVisitPlot",
39 "TargetRefCatDeltaPsfSkyVisitPlot",
40 "TargetRefCatDeltaDecSkyVisitPlot",
41 "TargetRefCatDeltaRAScatterVisitPlot",
42 "TargetRefCatDeltaDecScatterVisitPlot",
43 "TargetRefCatDeltaMetrics",
44 "TargetRefCatDeltaColorMetrics",
45 "TargetRefCatDeltaPhotomMetrics",
46)
48from lsst.pex.config import Field
50from ..actions.plot import HistPanel, HistPlot, HistStatsPanel
51from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
52from ..actions.plot.skyPlot import SkyPlot
53from ..actions.scalar.scalarActions import (
54 CountAction,
55 FracThreshold,
56 MeanAction,
57 MedianAction,
58 MedianGradientAction,
59 RmsAction,
60 SigmaMadAction,
61 StdevAction,
62)
63from ..actions.vector import (
64 AngularSeparation,
65 CoaddPlotFlagSelector,
66 ConvertFluxToMag,
67 ConvertUnits,
68 DownselectVector,
69 LoadVector,
70 MagDiff,
71 RAcosDec,
72 RangeSelector,
73 SnSelector,
74 StarSelector,
75 SubtractVector,
76 VisitPlotFlagSelector,
77)
78from ..contexts import CoaddContext, RefMatchContext, VisitContext
79from ..interfaces import AnalysisTool
82class TargetRefCatDelta(AnalysisTool):
83 """Plot the difference between a target catalog and a
84 reference catalog for the quantity set in `setDefaults`.
85 """
87 parameterizedBand = Field[bool](
88 doc="Does this AnalysisTool support band as a name parameter", default=True
89 )
91 def coaddContext(self) -> None:
92 """Apply coadd options for the ref cat plots.
93 Applies the coadd plot flag selector and sets
94 flux types.
95 """
96 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
97 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux_target"
98 self.prep.selectors.snSelector.threshold = 200
99 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target"
100 self.process.buildActions.starStatMask = SnSelector()
101 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux_target"
102 self.process.buildActions.patch = LoadVector()
103 self.process.buildActions.patch.vectorKey = "patch_target"
105 def visitContext(self) -> None:
106 """Apply visit options for the ref cat plots.
107 Applies the visit plot flag selector and sets
108 the flux types.
109 """
110 self.parameterizedBand = False
111 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
112 self.prep.selectors.starSelector.vectorKey = "extendedness_target"
113 self.prep.selectors.snSelector.fluxType = "psfFlux_target"
114 self.prep.selectors.snSelector.threshold = 50
116 self.process.buildActions.starStatMask = SnSelector()
117 self.process.buildActions.starStatMask.fluxType = "psfFlux_target"
118 self.process.buildActions.starStatMask.threshold = 200
120 def setDefaults(self):
121 super().setDefaults()
123 self.prep.selectors.snSelector = SnSelector()
124 self.prep.selectors.starSelector = StarSelector()
127class TargetRefCatDeltaScatterAstrom(TargetRefCatDelta):
128 """Plot the difference in milliseconds between a target catalog and a
129 reference catalog for the coordinate set in `setDefaults`. Plot it on
130 a scatter plot.
131 """
133 def setDefaults(self):
134 super().setDefaults()
136 self.process.buildActions.yStars = ConvertUnits(
137 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
138 )
139 self.process.buildActions.xStars = ConvertFluxToMag()
140 self.process.buildActions.xStars.vectorKey = "{band}_psfFlux_target"
141 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
142 self.process.calculateActions.stars.lowSNSelector.fluxType = "{band}_psfFlux_target"
143 self.process.calculateActions.stars.highSNSelector.fluxType = "{band}_psfFlux_target"
144 self.process.calculateActions.stars.fluxType = "{band}_psfFlux_target"
146 # Calculate median, std, sigmaMad, RMS, and number counts:
147 self.process.calculateActions.ref_offset = MedianAction(vectorKey="yStars")
148 self.process.calculateActions.ref_offset_mean = MeanAction(vectorKey="yStars")
149 self.process.calculateActions.ref_offset_stdev = StdevAction(vectorKey="yStars")
150 self.process.calculateActions.ref_offset_sigmaMad = SigmaMadAction(vectorKey="yStars")
151 self.process.calculateActions.ref_offset_rms = RmsAction(vectorKey="yStars")
152 self.process.calculateActions.ref_offset_nstars = CountAction(vectorKey="yStars")
153 self.process.calculateActions.ref_offset_gradient = MedianGradientAction(
154 xsVectorKey="xStars", ysVectorKey="yStars"
155 )
157 self.produce.plot = ScatterPlotWithTwoHists()
158 self.produce.plot.plotTypes = ["stars"]
159 self.produce.plot.magLabel = "PSF Magnitude (mag$_{{AB}}$)"
160 self.produce.plot.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)"
161 self.applyContext(CoaddContext)
162 self.applyContext(RefMatchContext)
165class TargetRefCatDeltaScatterAstromVisit(TargetRefCatDelta):
166 """Plot the difference in milliseconds between a target catalog and a
167 reference catalog for the coordinate set in `setDefaults`. Plot it on
168 a scatter plot.
169 """
171 def setDefaults(self):
172 super().setDefaults()
174 self.process.buildActions.yStars = ConvertUnits(
175 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
176 )
177 self.process.buildActions.xStars = ConvertFluxToMag()
178 self.process.buildActions.xStars.vectorKey = "psfFlux_target"
179 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
180 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux_target"
181 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux_target"
182 self.process.calculateActions.stars.fluxType = "psfFlux_target"
184 self.produce = ScatterPlotWithTwoHists()
185 self.produce.addSummaryPlot = False
186 self.produce.plotTypes = ["stars"]
187 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)"
188 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)"
189 self.applyContext(VisitContext)
190 self.applyContext(RefMatchContext)
193class TargetRefCatDeltaScatterPhotom(TargetRefCatDelta):
194 """Plot the difference in millimags between a target catalog and a
195 reference catalog for the flux type set in `setDefaults`.
196 """
198 def setDefaults(self):
199 super().setDefaults()
201 self.process.buildActions.yStars = MagDiff()
202 self.process.buildActions.yStars.col2 = "{band}_mag_ref"
203 self.process.buildActions.yStars.fluxUnits2 = "mag(AB)"
205 self.process.buildActions.xStars = ConvertFluxToMag()
206 self.process.buildActions.xStars.vectorKey = "{band}_psfFlux_target"
208 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
209 self.process.calculateActions.stars.lowSNSelector.fluxType = "{band}_psfFlux_target"
210 self.process.calculateActions.stars.highSNSelector.fluxType = "{band}_psfFlux_target"
211 self.process.calculateActions.stars.fluxType = "{band}_psfFlux_target"
213 self.produce = ScatterPlotWithTwoHists()
214 self.produce.plotTypes = ["stars"]
215 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)"
216 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)"
217 self.produce.yAxisLabel = "Output Mag - Ref Mag (mmag)"
218 self.applyContext(CoaddContext)
219 self.applyContext(RefMatchContext)
222class TargetRefCatDeltaScatterPhotomVisit(TargetRefCatDelta):
223 """Plot the difference in millimags between a target catalog and a
224 reference catalog for the flux type set in `setDefaults`.
225 """
227 def setDefaults(self):
228 super().setDefaults()
230 self.process.buildActions.yStars = MagDiff()
231 self.process.buildActions.yStars.col2 = "mag_ref"
232 self.process.buildActions.yStars.fluxUnits2 = "mag(AB)"
234 self.process.buildActions.xStars = ConvertFluxToMag()
235 self.process.buildActions.xStars.vectorKey = "psfFlux_target"
237 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
238 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux_target"
239 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux_target"
240 self.process.calculateActions.stars.fluxType = "psfFlux_target"
242 self.produce = ScatterPlotWithTwoHists()
243 self.produce.addSummaryPlot = False
244 self.produce.plotTypes = ["stars"]
245 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)"
246 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)"
247 self.produce.yAxisLabel = "Output Mag - Ref Mag (mmag)"
248 self.applyContext(VisitContext)
249 self.applyContext(RefMatchContext)
252class TargetRefCatDeltaPsfScatterPlot(TargetRefCatDeltaScatterPhotom):
253 """Plot the difference in millimags between the PSF flux
254 of a target catalog and a reference catalog
255 """
257 def setDefaults(self):
258 super().setDefaults()
260 self.process.buildActions.yStars.col1 = "{band}_psfFlux_target"
263class TargetRefCatDeltaCModelScatterPlot(TargetRefCatDeltaScatterPhotom):
264 """Plot the difference in millimags between the CModel flux
265 of a target catalog and a reference catalog.
266 """
268 def setDefaults(self):
269 super().setDefaults()
271 self.process.buildActions.yStars.col1 = "{band}_cModelFlux_target"
274class TargetRefCatDeltaPsfScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit):
275 """Plot the difference in millimags between the PSF flux
276 of a target catalog and a reference catalog
277 """
279 def setDefaults(self):
280 super().setDefaults()
282 self.process.buildActions.yStars.col1 = "psfFlux_target"
285class TargetRefCatDeltaAp09ScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit):
286 """Plot the difference in millimags between the aper 09 flux
287 of a target catalog and a reference catalog.
288 """
290 def setDefaults(self):
291 super().setDefaults()
293 self.process.buildActions.yStars.col1 = "ap09Flux_target"
296class TargetRefCatDeltaRAScatterPlot(TargetRefCatDeltaScatterAstrom):
297 """Plot the difference in milliseconds between the RA of a target catalog
298 and a reference catalog
299 """
301 def setDefaults(self):
302 super().setDefaults()
303 self.process.buildActions.yStars.buildAction.actionA = RAcosDec(
304 raKey="coord_ra_target", decKey="coord_dec_target"
305 )
306 self.process.buildActions.yStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
308 self.produce.plot.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (mas)"
310 self.produce.metric.units = {
311 "ref_offset": "mas",
312 "ref_offset_mean": "mas",
313 "ref_offset_stdev": "mas",
314 "ref_offset_sigmaMad": "mas",
315 "ref_offset_rms": "mas",
316 "ref_offset_nstars": "",
317 "ref_offset_gradient": "mas / mag",
318 }
320 self.produce.metric.newNames = {
321 "ref_offset": "{band}_ref_ra_offset_coadd",
322 "ref_offset_mean": "{band}_ref_ra_offset_mean_coadd",
323 "ref_offset_stdev": "{band}_ref_ra_offset_stdev_coadd",
324 "ref_offset_sigmaMad": "{band}_ref_ra_offset_sigmaMad_coadd",
325 "ref_offset_rms": "{band}_ref_ra_offset_rms_coadd",
326 "ref_offset_nstars": "{band}_ref_ra_offset_nstars_coadd",
327 "ref_offset_gradient": "{band}_ref_ra_offset_gradient_coadd",
328 }
331class TargetRefCatDeltaRAScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit):
332 """Plot the difference in milliseconds between the RA of a target catalog
333 and a reference catalog
334 """
336 def setDefaults(self):
337 super().setDefaults()
338 self.process.buildActions.yStars.buildAction.actionA = RAcosDec(
339 raKey="coord_ra_target", decKey="coord_dec_target"
340 )
341 self.process.buildActions.yStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
343 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (mas)"
346class TargetRefCatDeltaDecScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit):
347 """Plot the difference in milliseconds between the Decs of a target catalog
348 and a reference catalog
349 """
351 def setDefaults(self):
352 super().setDefaults()
353 self.process.buildActions.yStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
354 self.process.buildActions.yStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
356 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (mas)"
359class TargetRefCatDeltaDecScatterPlot(TargetRefCatDeltaScatterAstrom):
360 """Plot the difference in milliseconds between the Dec of a target catalog
361 and a reference catalog
362 """
364 def setDefaults(self):
365 super().setDefaults()
366 self.process.buildActions.yStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
367 self.process.buildActions.yStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
369 self.produce.plot.yAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (mas)"
371 self.produce.metric.units = {
372 "ref_offset": "mas",
373 "ref_offset_mean": "mas",
374 "ref_offset_stdev": "mas",
375 "ref_offset_sigmaMad": "mas",
376 "ref_offset_rms": "mas",
377 "ref_offset_nstars": "",
378 "ref_offset_gradient": "mas / mag",
379 }
381 self.produce.metric.newNames = {
382 "ref_offset": "{band}_ref_dec_offset_coadd",
383 "ref_offset_mean": "{band}_ref_dec_offset_mean_coadd",
384 "ref_offset_stdev": "{band}_ref_dec_offset_stdev_coadd",
385 "ref_offset_sigmaMad": "{band}_ref_dec_offset_sigmaMad_coadd",
386 "ref_offset_rms": "{band}_ref_dec_offset_rms_coadd",
387 "ref_offset_nstars": "{band}_ref_dec_offset_nstars_coadd",
388 "ref_offset_gradient": "{band}_ref_dec_offset_gradient_coadd",
389 }
392class TargetRefCatDeltaSkyPlot(TargetRefCatDelta):
393 """Base class for plotting the RA/Dec distribution of stars, with the
394 difference of the quantity defined in the vector key parameter between
395 the target and reference catalog as the color.
396 """
398 parameterizedBand = Field[bool](
399 doc="Does this AnalysisTool support band as a name parameter", default=True
400 )
402 def setDefaults(self):
403 super().setDefaults()
405 self.process.buildActions.xStars = LoadVector()
406 self.process.buildActions.xStars.vectorKey = "coord_ra_target"
407 self.process.buildActions.yStars = LoadVector()
408 self.process.buildActions.yStars.vectorKey = "coord_dec_target"
410 self.produce = SkyPlot()
411 self.produce.plotTypes = ["stars"]
412 self.produce.xAxisLabel = "R.A. (deg)"
413 self.produce.yAxisLabel = "Dec. (deg)"
414 self.produce.plotOutlines = False
417class TargetRefCatDeltaSkyPlotAstrom(TargetRefCatDeltaSkyPlot):
418 """Base class for plotting the RA/Dec distribution of stars, with the
419 difference between the RA or Dec of the target and reference catalog as
420 the color.
421 """
423 def setDefaults(self):
424 super().setDefaults()
426 self.process.buildActions.zStars = ConvertUnits(
427 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
428 )
430 self.applyContext(CoaddContext)
431 self.applyContext(RefMatchContext)
433 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux_target"
436class TargetRefCatDeltaSkyPlotAstromVisit(TargetRefCatDeltaSkyPlot):
437 """Base class for plotting the RA/Dec distribution of stars at
438 the visit level, with the difference between the RA or Dec of
439 the target and reference catalog as the color.
440 """
442 def setDefaults(self):
443 super().setDefaults()
445 self.process.buildActions.zStars = ConvertUnits(
446 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
447 )
449 self.applyContext(VisitContext)
450 self.applyContext(RefMatchContext)
453class TargetRefCatDeltaSkyPlotPhotomVisit(TargetRefCatDeltaSkyPlot):
454 """Base class for plotting the RA/Dec distribution of stars, with the
455 difference between the photometry of the target and reference catalog as
456 the color.
457 """
459 def setDefaults(self):
460 super().setDefaults()
462 self.process.buildActions.zStars = MagDiff()
463 self.process.buildActions.zStars.col2 = "mag_ref"
464 self.process.buildActions.zStars.fluxUnits2 = "mag(AB)"
466 self.produce.plotName = "photomDiffSky"
467 self.produce.zAxisLabel = "Output Mag - Ref Mag (mmag)"
468 self.applyContext(VisitContext)
469 self.applyContext(RefMatchContext)
472class TargetRefCatDeltaSkyPlotPhotom(TargetRefCatDeltaSkyPlot):
473 """Base class for plotting the RA/Dec distribution of stars, with the
474 difference between the photometry of the target and reference catalog as
475 the color.
476 """
478 def setDefaults(self):
479 super().setDefaults()
481 self.process.buildActions.zStars = MagDiff()
482 self.process.buildActions.zStars.col2 = "{band}_mag_ref"
483 self.process.buildActions.zStars.fluxUnits2 = "mag(AB)"
485 self.produce.plotName = "photomDiffSky_{band}"
486 self.produce.zAxisLabel = "Output Mag - Ref Mag (mmag)"
487 self.applyContext(CoaddContext)
488 self.applyContext(RefMatchContext)
491class TargetRefCatDeltaPsfSkyPlot(TargetRefCatDeltaSkyPlotPhotom):
492 """Plot the RA/Dec distribution of stars, with the
493 difference between the PSF photometry of the target and reference
494 catalog as the color.
495 """
497 def setDefaults(self):
498 super().setDefaults()
500 self.process.buildActions.zStars.col1 = "{band}_psfFlux_target"
503class TargetRefCatDeltaPsfSkyVisitPlot(TargetRefCatDeltaSkyPlotPhotomVisit):
504 """Plot the RA/Dec distribution of stars, with the
505 difference between the PSF photometry of the target and reference
506 catalog as the color.
507 """
509 def setDefaults(self):
510 super().setDefaults()
512 self.process.buildActions.zStars.col1 = "psfFlux_target"
515class TargetRefCatDeltaAp09SkyVisitPlot(TargetRefCatDeltaSkyPlotPhotomVisit):
516 """Plot the RA/Dec distribution of stars, with the
517 difference between the Ap09 photometry of the target and reference
518 catalog as the color.
519 """
521 def setDefaults(self):
522 super().setDefaults()
524 self.process.buildActions.zStars.col1 = "ap09Flux_target"
527class TargetRefCatDeltaCModelSkyPlot(TargetRefCatDeltaSkyPlotPhotom):
528 """Plot the RA/Dec distribution of stars, with the
529 difference between the CModel photometry of the target and reference
530 catalog as the color.
531 """
533 def setDefaults(self):
534 super().setDefaults()
536 self.process.buildActions.zStars.col1 = "{band}_cModelFlux_target"
539class TargetRefCatDeltaRASkyPlot(TargetRefCatDeltaSkyPlotAstrom):
540 """Plot the RA/Dec distribution of stars, with the
541 difference between the RA of the target and reference catalog as
542 the color.
543 """
545 def setDefaults(self):
546 super().setDefaults()
547 self.process.buildActions.zStars.buildAction.actionA = RAcosDec(
548 raKey="coord_ra_target", decKey="coord_dec_target"
549 )
550 self.process.buildActions.zStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
552 self.produce.plotName = "astromDiffSky_RA"
553 self.produce.zAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (mas)"
556class TargetRefCatDeltaRASkyVisitPlot(TargetRefCatDeltaSkyPlotAstromVisit):
557 """Plot the RA/Dec distribution of stars, with the
558 difference between the RA of the target and reference catalog as
559 the color.
560 """
562 def setDefaults(self):
563 super().setDefaults()
564 self.process.buildActions.zStars.buildAction.actionA = RAcosDec(
565 raKey="coord_ra_target", decKey="coord_dec_target"
566 )
567 self.process.buildActions.zStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
568 self.produce.plotName = "astromDiffSky_RA"
569 self.produce.zAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (mas)"
572class TargetRefCatDeltaDecSkyVisitPlot(TargetRefCatDeltaSkyPlotAstromVisit):
573 """Plot the RA/Dec distribution of stars, with the
574 difference between the RA of the target and reference catalog as
575 the color.
576 """
578 def setDefaults(self):
579 super().setDefaults()
580 self.process.buildActions.zStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
581 self.process.buildActions.zStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
583 self.produce.plotName = "astromDiffSky_Dec"
584 self.produce.zAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (mas)"
587class TargetRefCatDeltaDecSkyPlot(TargetRefCatDeltaSkyPlotAstrom):
588 """Plot the RA/Dec distribution of stars, with the
589 difference between the Dec of the target and reference catalog as
590 the color.
591 """
593 def setDefaults(self):
594 super().setDefaults()
595 self.process.buildActions.zStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
596 self.process.buildActions.zStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
598 self.produce.plotName = "astromDiffSky_Dec"
599 self.produce.zAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (mas)"
602class TargetRefCatDeltaMetrics(AnalysisTool):
603 """Calculate the AA1 metric and the sigma MAD from the difference between
604 the target and reference catalog coordinates.
605 """
607 parameterizedBand = Field[bool](
608 doc="Does this AnalysisTool support band as a name parameter", default=True
609 )
611 def coaddContext(self) -> None:
612 """Apply coadd options for the metrics. Applies the coadd plot flag
613 selector and sets flux types.
614 """
615 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
616 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target"
618 self.applyContext(RefMatchContext)
620 self.process.buildActions.mags.vectorKey = "{band}_psfFlux_target"
622 self.produce.metric.newNames = {
623 "AA1_RA": "{band}_AA1_RA_coadd",
624 "AA1_sigmaMad_RA": "{band}_AA1_sigmaMad_RA_coadd",
625 "AA1_Dec": "{band}_AA1_Dec_coadd",
626 "AA1_sigmaMad_Dec": "{band}_AA1_sigmaMad_Dec_coadd",
627 "AA1_tot": "{band}_AA1_tot_coadd",
628 "AA1_sigmaMad_tot": "{band}_AA1_sigmaMad_tot_coadd",
629 }
631 def visitContext(self) -> None:
632 """Apply visit options for the metrics. Applies the visit plot flag
633 selector and sets flux types.
634 """
635 self.parameterizedBand = False
636 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
637 self.prep.selectors.starSelector.vectorKey = "extendedness_target"
639 self.applyContext(RefMatchContext)
641 self.process.buildActions.mags.vectorKey = "psfFlux_target"
643 def setDefaults(self):
644 super().setDefaults()
646 self.prep.selectors.starSelector = StarSelector()
648 # Calculate difference in RA
649 self.process.buildActions.astromDiffRA = ConvertUnits(
650 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
651 )
652 self.process.buildActions.astromDiffRA.buildAction.actionA = RAcosDec(
653 raKey="coord_ra_target", decKey="dec_ref"
654 )
655 self.process.buildActions.astromDiffRA.buildAction.actionB = RAcosDec(
656 raKey="ra_ref", decKey="dec_ref"
657 )
658 # Calculate difference in Dec
659 self.process.buildActions.astromDiffDec = ConvertUnits(
660 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
661 )
662 self.process.buildActions.astromDiffDec.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
663 self.process.buildActions.astromDiffDec.buildAction.actionB = LoadVector(vectorKey="dec_ref")
664 # Calculate total difference (using astropy)
665 self.process.buildActions.astromDiffTot = AngularSeparation(
666 raKey_A="coord_ra_target",
667 decKey_A="coord_dec_target",
668 raKey_B="ra_ref",
669 decKey_B="dec_ref",
670 )
672 self.process.buildActions.mags = ConvertFluxToMag()
674 # Filter down to only objects with mag 17-21.5
675 self.process.filterActions.brightStarsRA = DownselectVector(vectorKey="astromDiffRA")
676 self.process.filterActions.brightStarsRA.selector = RangeSelector(
677 vectorKey="mags", minimum=17, maximum=21.5
678 )
680 self.process.filterActions.brightStarsDec = DownselectVector(vectorKey="astromDiffDec")
681 self.process.filterActions.brightStarsDec.selector = RangeSelector(
682 vectorKey="mags", minimum=17, maximum=21.5
683 )
685 self.process.filterActions.brightStarsTot = DownselectVector(vectorKey="astromDiffTot")
686 self.process.filterActions.brightStarsTot.selector = RangeSelector(
687 vectorKey="mags", minimum=17, maximum=21.5
688 )
690 # Calculate median and sigmaMad
691 self.process.calculateActions.AA1_RA = MedianAction(vectorKey="brightStarsRA")
692 self.process.calculateActions.AA1_sigmaMad_RA = SigmaMadAction(vectorKey="brightStarsRA")
694 self.process.calculateActions.AA1_Dec = MedianAction(vectorKey="brightStarsDec")
695 self.process.calculateActions.AA1_sigmaMad_Dec = SigmaMadAction(vectorKey="brightStarsDec")
697 self.process.calculateActions.AA1_tot = MedianAction(vectorKey="brightStarsTot")
698 self.process.calculateActions.AA1_sigmaMad_tot = SigmaMadAction(vectorKey="brightStarsTot")
700 self.produce.metric.units = {
701 "AA1_RA": "mas",
702 "AA1_sigmaMad_RA": "mas",
703 "AA1_Dec": "mas",
704 "AA1_sigmaMad_Dec": "mas",
705 "AA1_tot": "mas",
706 "AA1_sigmaMad_tot": "mas",
707 }
710class TargetRefCatDeltaColorMetrics(AnalysisTool):
711 """Calculate the AB1 and ABF1 metrics from the difference between the
712 target and reference catalog coordinates.
713 """
715 parameterizedBand: bool = False
717 AB2 = Field[float](
718 doc=(
719 "Separation in milliarcseconds used to calculate the ABF1 metric. ABF1 is the percentage of"
720 " sources whose distance from the reference is greater than AB2 mas from the mean."
721 ),
722 default=20,
723 )
725 def setDefaults(self):
726 super().setDefaults()
728 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
729 self.prep.selectors.starSelector = StarSelector()
730 self.prep.selectors.starSelector.vectorKey = "extendedness"
732 # Calculate difference in RA
733 self.process.buildActions.astromDiffRA = ConvertUnits(
734 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
735 )
736 self.process.buildActions.astromDiffRA.buildAction.actionA = RAcosDec(
737 raKey="coord_ra", decKey="coord_dec"
738 )
739 self.process.buildActions.astromDiffRA.buildAction.actionB = RAcosDec(raKey="r_ra", decKey="r_dec")
740 # Calculate difference in Dec
741 self.process.buildActions.astromDiffDec = ConvertUnits(
742 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
743 )
744 self.process.buildActions.astromDiffDec.buildAction.actionA = LoadVector(vectorKey="dec")
745 self.process.buildActions.astromDiffDec.buildAction.actionB = LoadVector(vectorKey="r_dec")
747 # Calculate total difference (using astropy)
748 self.process.buildActions.astromDiffTot = AngularSeparation(
749 raKey_A="coord_ra",
750 decKey_A="coord_dec",
751 raKey_B="r_ra",
752 decKey_B="r_dec",
753 )
755 self.process.buildActions.mags = ConvertFluxToMag()
756 self.process.buildActions.mags.vectorKey = "psfFlux"
758 # Filter down to only objects with mag 17-21.5
759 self.process.filterActions.brightStarsRA = DownselectVector(vectorKey="astromDiffRA")
760 self.process.filterActions.brightStarsRA.selector = RangeSelector(
761 vectorKey="mags", minimum=17, maximum=21.5
762 )
764 self.process.filterActions.brightStarsDec = DownselectVector(vectorKey="astromDiffDec")
765 self.process.filterActions.brightStarsDec.selector = RangeSelector(
766 vectorKey="mags", minimum=17, maximum=21.5
767 )
769 self.process.filterActions.brightStarsTot = DownselectVector(vectorKey="astromDiffTot")
770 self.process.filterActions.brightStarsTot.selector = RangeSelector(
771 vectorKey="mags", minimum=17, maximum=21.5
772 )
774 # Calculate RMS annd number of sources
775 self.process.calculateActions.AB1_RA = RmsAction(vectorKey="brightStarsRA")
776 self.process.calculateActions.AB1_Dec = RmsAction(vectorKey="brightStarsDec")
777 self.process.calculateActions.AB1_tot = RmsAction(vectorKey="brightStarsTot")
778 self.process.calculateActions.nSources = CountAction(vectorKey="brightStarsTot")
780 self.produce.metric.units = {
781 "AB1_RA": "mas",
782 "ABF1_RA": "percent",
783 "AB1_Dec": "mas",
784 "ABF1_Dec": "percent",
785 "AB1_tot": "mas",
786 "ABF1_tot": "percent",
787 }
789 self.produce.plot = HistPlot()
791 self.produce.plot.panels["panel_sep"] = HistPanel()
792 self.produce.plot.panels["panel_sep"].hists = dict(
793 brightStarsRA="Separations in RA",
794 brightStarsDec="Separations in Dec",
795 brightStarsTot="Total separations",
796 )
797 self.produce.plot.panels["panel_sep"].label = "Separation Distances (mas)"
799 self.produce.plot.panels["panel_sep"].statsPanel = HistStatsPanel()
800 self.produce.plot.panels["panel_sep"].statsPanel.statsLabels = ["N", "AB1", "ABF1 %"]
801 self.produce.plot.panels["panel_sep"].statsPanel.stat1 = ["nSources", "nSources", "nSources"]
802 self.produce.plot.panels["panel_sep"].statsPanel.stat2 = ["AB1_RA", "AB1_Dec", "AB1_tot"]
803 self.produce.plot.panels["panel_sep"].statsPanel.stat3 = ["ABF1_RA", "ABF1_Dec", "ABF1_tot"]
805 def finalize(self):
806 super().finalize()
808 # Calculate the percentage of outliers above the AB2 threshold
809 self.process.calculateActions.ABF1_RA = FracThreshold(
810 vectorKey="brightStarsRA",
811 op="gt",
812 threshold=self.AB2,
813 relative_to_median=True,
814 percent=True,
815 use_absolute_value=True,
816 )
817 self.process.calculateActions.ABF1_Dec = FracThreshold(
818 vectorKey="brightStarsDec",
819 threshold=self.AB2,
820 op="gt",
821 relative_to_median=True,
822 percent=True,
823 use_absolute_value=True,
824 )
825 self.process.calculateActions.ABF1_tot = FracThreshold(
826 vectorKey="brightStarsTot", threshold=self.AB2, op="gt", percent=True
827 )
830class TargetRefCatDeltaPhotomMetrics(TargetRefCatDeltaMetrics):
831 """Calculate statistics from the differences between
832 the target and reference catalog magnitudes.
833 """
835 parameterizedBand = Field[bool](
836 doc="Does this AnalysisTool support band as a name parameter", default=True
837 )
839 def coaddContext(self) -> None:
840 """Apply coadd options for the metrics. Applies the coadd plot flag
841 selector and sets flux types.
842 """
843 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
844 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target"
845 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux_target"
847 # Calculate magnitude difference
848 self.process.buildActions.srcRefMagdiffStars.col1 = "{band}_psfFlux_target"
849 self.process.buildActions.srcRefMagdiffStars.col2 = "{band}_mag_ref"
850 self.process.buildActions.psfMag = ConvertFluxToMag(
851 vectorKey="{band}_psfFlux_target", returnMillimags=True
852 )
854 self.applyContext(RefMatchContext)
856 self.process.buildActions.mags.vectorKey = "{band}_psfFlux_target"
858 self.produce.metric.newNames = {
859 "ref_photom_offset": "{band}_ref_photom_offset_coadd",
860 "ref_photom_offset_mean": "{band}_ref_photom_offset_mean_coadd",
861 "ref_photom_offset_stdev": "{band}_ref_photom_offset_stdev_coadd",
862 "ref_photom_offset_sigmaMad": "{band}_ref_photom_offset_sigmaMad_coadd",
863 "ref_photom_offset_rms": "{band}_ref_photom_offset_rms_coadd",
864 "ref_photom_offset_nstars": "{band}_ref_photom_offset_nstars_coadd",
865 "ref_photom_offset_gradient": "{band}_ref_photom_offset_gradient_coadd",
866 }
868 def visitContext(self) -> None:
869 """Apply visit options for the metrics. Applies the visit plot flag
870 selector and sets flux types.
871 """
872 self.parameterizedBand = False
873 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
874 self.prep.selectors.starSelector.vectorKey = "extendedness_target"
876 self.applyContext(RefMatchContext)
878 self.process.buildActions.mags.vectorKey = "psfFlux_target"
880 def setDefaults(self):
881 super().setDefaults()
883 self.prep.selectors.starSelector = StarSelector()
884 self.prep.selectors.snSelector = SnSelector()
885 self.prep.selectors.snSelector.fluxType = "psfFlux_target"
886 self.prep.selectors.snSelector.threshold = 200
888 # Calculate magnitude difference
889 self.process.buildActions.srcRefMagdiffStars = MagDiff()
890 self.process.buildActions.srcRefMagdiffStars.col1 = "psfFlux_target"
891 self.process.buildActions.srcRefMagdiffStars.col2 = "mag_ref"
892 self.process.buildActions.srcRefMagdiffStars.fluxUnits2 = "mag(AB)"
894 self.process.buildActions.psfMag = ConvertFluxToMag(vectorKey="psfFlux_target", returnMillimags=True)
896 # Calculate median, std, sigmaMad, RMS, and number counts:
897 self.process.calculateActions.ref_photom_offset = MedianAction(vectorKey="srcRefMagdiffStars")
898 self.process.calculateActions.ref_photom_offset_mean = MeanAction(vectorKey="srcRefMagdiffStars")
899 self.process.calculateActions.ref_photom_offset_stdev = StdevAction(vectorKey="srcRefMagdiffStars")
900 self.process.calculateActions.ref_photom_offset_sigmaMad = SigmaMadAction(
901 vectorKey="srcRefMagdiffStars"
902 )
903 self.process.calculateActions.ref_photom_offset_rms = RmsAction(vectorKey="srcRefMagdiffStars")
904 self.process.calculateActions.ref_photom_offset_nstars = CountAction(vectorKey="srcRefMagdiffStars")
905 self.process.calculateActions.ref_photom_offset_gradient = MedianGradientAction(
906 xsVectorKey="psfMag", ysVectorKey="srcRefMagdiffStars"
907 )
909 self.produce.metric.units = {
910 "ref_photom_offset": "mmag",
911 "ref_photom_offset_mean": "mmag",
912 "ref_photom_offset_stdev": "mmag",
913 "ref_photom_offset_sigmaMad": "mmag",
914 "ref_photom_offset_rms": "mmag",
915 "ref_photom_offset_nstars": "ct",
916 "ref_photom_offset_gradient": "",
917 }