Coverage for python / lsst / analysis / tools / atools / shapes.py: 28%
324 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-22 09:32 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-22 09:32 +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/>.
22from __future__ import annotations
24__all__ = (
25 "ShapeSizeFractionalScalars",
26 "BasePsfResidualCoadd",
27 "BasePsfResidualVisit",
28 "E1DiffScatter",
29 "E1DiffScatterVisit",
30 "E2DiffScatter",
31 "E2DiffScatterVisit",
32 "ShapeSizeFractionalDiffScatter",
33 "ShapeSizeFractionalDiffScatterVisit",
34 "E1DiffSky",
35 "E1DiffSkyVisit",
36 "E2DiffSky",
37 "E2DiffSkyVisit",
38 "ShapeSizeFractionalDiffSky",
39 "ShapeSizeFractionalDiffSkyVisit",
40 "RhoStatistics",
41 "RelativeSizeResidualPlot",
42 "EBase",
43 "EScatter",
44 "E1ScatterVisit",
45 "E2ScatterVisit",
46 "ESky",
47 "E1SkyVisit",
48 "E2SkyVisit",
49 "EFocalPlane",
50 "E1FocalPlane",
51 "E2FocalPlane",
52 "ShapeSizeFractionalDiffFocalPlane",
53)
55from lsst.pex.config import Field
56from lsst.pex.config.configurableActions import ConfigurableActionField
58from ..actions.keyedData import KeyedScalars
59from ..actions.plot import FocalPlanePlot
60from ..actions.plot.rhoStatisticsPlot import RhoStatisticsPlot
61from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
62from ..actions.plot.skyPlot import SkyPlot
63from ..actions.scalar import CountAction, MedianAction, SigmaMadAction
64from ..actions.vector import (
65 CalcE,
66 CalcE1,
67 CalcE2,
68 CalcEDiff,
69 CalcMomentSize,
70 CalcRhoStatistics,
71 CoaddPlotFlagSelector,
72 ConvertFluxToMag,
73 DownselectVector,
74 FractionalDifference,
75 LoadVector,
76 SnSelector,
77 StarSelector,
78 VectorSelector,
79 VisitPlotFlagSelector,
80)
81from ..contexts import CoaddContext, VisitContext
82from ..interfaces import AnalysisTool, KeyedData, VectorAction
85class ShapeSizeFractionalScalars(KeyedScalars):
86 vectorKey = Field[str](doc="Column key to compute scalars")
88 snFluxType = Field[str](doc="column key for the flux type used in SN selection")
90 selector = ConfigurableActionField[VectorAction](doc="Selector to use before computing Scalars")
92 def setDefaults(self):
93 super().setDefaults()
94 self.scalarActions.median = MedianAction(vectorKey=self.vectorKey) # type: ignore
95 self.scalarActions.sigmaMad = SigmaMadAction(vectorKey=self.vectorKey) # type: ignore
96 self.scalarActions.count = CountAction(vectorKey=self.vectorKey) # type: ignore
97 self.scalarActions.approxMag = MedianAction(vectorKey=self.snFluxType) # type: ignore
99 def __call__(self, data: KeyedData, **kwargs) -> KeyedData:
100 mask = kwargs.get("mask")
101 selection = self.selector(data, **kwargs)
102 if mask is not None:
103 mask &= selection
104 else:
105 mask = selection
106 return super().__call__(data, **kwargs | dict(mask=mask))
109class BasePsfResidualCoadd(AnalysisTool):
110 """Shared configuration for `prep` and `process` stages of PSF residuals.
112 This is a mixin class used by `BasePsfResidualScatterPlot` and
113 `BasePsfResidualMetric` to share common default configuration.
114 """
116 def setDefaults(self):
117 super().setDefaults()
119 self.prep.selectors.starSelector = StarSelector()
120 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
121 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
123 self.process.calculateActions.stars = ScatterPlotStatsAction(
124 vectorKey="yStars",
125 )
126 self.process.buildActions.mags = ConvertFluxToMag(vectorKey="{band}_psfFlux")
128 self.process.buildActions.fracDiff = FractionalDifference(
129 actionA=CalcMomentSize(colXx="{band}_ixx", colYy="{band}_iyy", colXy="{band}_ixy"),
130 actionB=CalcMomentSize(colXx="{band}_ixxPSF", colYy="{band}_iyyPSF", colXy="{band}_ixyPSF"),
131 )
132 # Define an eDiff action and let e1Diff and e2Diff differ only in
133 # component.
134 self.process.buildActions.eDiff = CalcEDiff(
135 colA=CalcE(colXx="{band}_ixx", colYy="{band}_iyy", colXy="{band}_ixy"),
136 colB=CalcE(colXx="{band}_ixxPSF", colYy="{band}_iyyPSF", colXy="{band}_ixyPSF"),
137 )
138 self.process.buildActions.e1Diff = self.process.buildActions.eDiff
139 self.process.buildActions.e1Diff.component = "1"
140 self.process.buildActions.e2Diff = self.process.buildActions.eDiff
141 self.process.buildActions.e2Diff.component = "2"
143 self.process.buildActions.patch = LoadVector()
144 self.process.buildActions.patch.vectorKey = "patch"
146 self.process.buildActions.xStars = ConvertFluxToMag(vectorKey="{band}_psfFlux")
147 self.process.buildActions.psfFlux = LoadVector(vectorKey="{band}_psfFlux")
148 self.process.buildActions.psfFluxErr = LoadVector(vectorKey="{band}_psfFluxErr")
151class BasePsfResidualVisit(AnalysisTool):
152 """Shared configuration for `prep` and `process` stages of PSF residuals.
154 This is a mixin class used by `BasePsfResidualScatterPlot` and
155 `BasePsfResidualMetric` to share common default configuration.
156 """
158 parameterizedBand: bool = False
160 def setDefaults(self):
161 super().setDefaults()
163 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
164 self.prep.selectors.snSelector = SnSelector(fluxType="psfFlux", threshold=50)
165 self.prep.selectors.starSelector = StarSelector(vectorKey="extendedness")
167 self.process.buildActions.xStars = ConvertFluxToMag(vectorKey="psfFlux")
169 self.process.buildActions.mags = ConvertFluxToMag(vectorKey="psfFlux")
171 self.process.buildActions.fracDiff = FractionalDifference(
172 actionA=CalcMomentSize(colXx="ixx", colYy="iyy", colXy="ixy"),
173 actionB=CalcMomentSize(colXx="ixxPSF", colYy="iyyPSF", colXy="ixyPSF"),
174 )
175 # Define an eDiff action and let e1Diff and e2Diff differ only in
176 # component.
177 self.process.buildActions.eDiff = CalcEDiff(
178 colA=CalcE(colXx="ixx", colYy="iyy", colXy="ixy"),
179 colB=CalcE(colXx="ixxPSF", colYy="iyyPSF", colXy="ixyPSF"),
180 )
181 self.process.buildActions.e1Diff = self.process.buildActions.eDiff
182 self.process.buildActions.e1Diff.component = "1"
183 self.process.buildActions.e2Diff = self.process.buildActions.eDiff
184 self.process.buildActions.e2Diff.component = "2"
187class SkyCoadd(BasePsfResidualCoadd):
188 """A base class for coadd level sky plots."""
190 def setDefaults(self):
191 super().setDefaults()
193 self.process.buildActions.xStars = LoadVector()
194 self.process.buildActions.xStars.vectorKey = "coord_ra"
195 self.process.buildActions.yStars = LoadVector()
196 self.process.buildActions.yStars.vectorKey = "coord_dec"
198 self.process.buildActions.starStatMask = SnSelector()
199 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux"
201 self.produce.plot = SkyPlot()
202 self.produce.plot.plotTypes = ["stars"]
203 self.produce.plot.xAxisLabel = "R.A. (deg)"
204 self.produce.plot.yAxisLabel = "Dec. (deg)"
207class SkyVisit(BasePsfResidualVisit):
208 """A base class for visit level sky plots."""
210 def setDefaults(self):
211 super().setDefaults()
213 self.process.buildActions.xStars = LoadVector()
214 self.process.buildActions.xStars.vectorKey = "coord_ra"
215 self.process.buildActions.yStars = LoadVector()
216 self.process.buildActions.yStars.vectorKey = "coord_dec"
218 self.process.buildActions.starStatMask = SnSelector()
219 self.process.buildActions.starStatMask.fluxType = "psfFlux"
221 self.produce.plot = SkyPlot()
223 self.produce.plot.plotTypes = ["stars"]
224 self.produce.plot.xAxisLabel = "R.A. (deg)"
225 self.produce.plot.yAxisLabel = "Dec. (deg)"
227 self.produce.plot.plotOutlines = False
230class ScatterCoadd(BasePsfResidualCoadd):
231 """A base class for coadd level scatter plots."""
233 def setDefaults(self):
234 super().setDefaults()
235 self.process.calculateActions.stars = ScatterPlotStatsAction(
236 vectorKey="yStars",
237 )
238 # use the downselected psfFlux
239 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
240 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
241 self.process.calculateActions.stars.fluxType = "psfFlux"
243 self.produce.metric.units = {
244 "{band}_highSNStars_median": "pixel",
245 "{band}_highSNStars_sigmaMad": "pixel",
246 "{band}_highSNStars_count": "count",
247 "{band}_lowSNStars_median": "pixel",
248 "{band}_lowSNStars_sigmaMad": "pixel",
249 "{band}_lowSNStars_count": "count",
250 }
252 self.produce.plot = ScatterPlotWithTwoHists()
254 self.produce.plot.plotTypes = ["stars"]
255 self.produce.plot.xAxisLabel = "PSF Magnitude (mag)"
256 self.produce.plot.magLabel = "PSF Magnitude (mag)"
259class ScatterVisit(BasePsfResidualVisit):
260 """A base class for visit level sky plots."""
262 def setDefaults(self):
263 super().setDefaults()
264 self.process.calculateActions.stars = ScatterPlotStatsAction(
265 vectorKey="yStars",
266 )
268 # use the downselected psfFlux
269 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
270 self.process.calculateActions.stars.highSNSelector.threshold = 500
271 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
272 self.process.calculateActions.stars.lowSNSelector.threshold = 100
273 self.process.calculateActions.stars.fluxType = "psfFlux"
275 self.produce.metric.units = {
276 "{band}_highSNStars_median": "pixel",
277 "{band}_highSNStars_sigmaMad": "pixel",
278 "{band}_highSNStars_count": "count",
279 "{band}_lowSNStars_median": "pixel",
280 "{band}_lowSNStars_sigmaMad": "pixel",
281 "{band}_lowSNStars_count": "count",
282 }
284 self.produce.metric.newNames = {
285 "{band}_highSNStars_median": "highSNStars_median",
286 "{band}_highSNStars_sigmaMad": "highSNStars_sigmaMad",
287 "{band}_highSNStars_count": "highSNStars_count",
288 "{band}_lowSNStars_median": "lowSNStars_median",
289 "{band}_lowSNStars_sigmaMad": "lowSNStars_sigmaMad",
290 "{band}_lowSNStars_count": "lowSNStars_count",
291 }
293 self.produce.plot = ScatterPlotWithTwoHists()
295 self.produce.plot.plotTypes = ["stars"]
296 self.produce.plot.xAxisLabel = "PSF Magnitude (mag)"
297 self.produce.plot.magLabel = "PSF Magnitude (mag)"
299 self.produce.plot.addSummaryPlot = False
302class E1DiffScatter(ScatterCoadd):
303 """The difference between E1 and E1 PSF plotted on
304 a scatter plot. Used in coaddQualityCore.
305 """
307 def setDefaults(self):
308 super().setDefaults()
309 self.applyContext(CoaddContext)
310 self.process.filterActions.yStars = LoadVector(vectorKey="e1Diff")
311 self.produce.plot.yAxisLabel = "Ellipticity residuals (e1 - e1_PSF)"
314class E1DiffScatterVisit(ScatterVisit):
315 """The difference between E1 and E1 PSF plotted on
316 a scatter plot for visit level data.
317 Used in debugPSF.
318 """
320 def setDefaults(self):
321 super().setDefaults()
322 self.process.filterActions.yStars = LoadVector(vectorKey="e1Diff")
323 self.applyContext(VisitContext)
324 self.produce.plot.yAxisLabel = "Ellipticity residuals (e1 - e1_PSF)"
327class E2DiffScatter(ScatterCoadd):
328 """The difference between E2 and E2 PSF plotted on
329 a scatter plot for coadd level data.
330 Used in coaddQualityCore.
331 """
333 def setDefaults(self):
334 super().setDefaults()
335 self.process.filterActions.yStars = LoadVector(vectorKey="e2Diff")
336 self.produce.plot.yAxisLabel = "Ellipticity residuals (e2 - e2_PSF)"
337 self.applyContext(CoaddContext)
340class E2DiffScatterVisit(ScatterVisit):
341 """The difference between E2 and E2 PSF plotted on
342 a scatter plot for visit level data.
343 Used in debugPSF.
344 """
346 def setDefaults(self):
347 super().setDefaults()
348 self.process.filterActions.yStars = LoadVector(vectorKey="e2Diff")
349 self.applyContext(VisitContext)
350 self.produce.plot.yAxisLabel = "Ellipticity residuals (e2 - e2_PSF)"
353class ShapeSizeFractionalDiffScatter(ScatterCoadd):
354 """The difference between shape and shape PSF plotted on
355 a scatter plot for coadd level data.
356 Used in coaddQualityCore.
357 """
359 def setDefaults(self):
360 super().setDefaults()
361 self.applyContext(CoaddContext)
362 self.process.filterActions.yStars = LoadVector(vectorKey="fracDiff")
363 self.produce.plot.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
366class ShapeSizeFractionalDiffScatterVisit(ScatterVisit):
367 """The difference between shape and shape PSF plotted on
368 a scatter plot for visit level data.
369 Used in debugPsf.
370 """
372 def setDefaults(self):
373 super().setDefaults()
374 self.process.filterActions.yStars = LoadVector(vectorKey="fracDiff")
375 self.applyContext(VisitContext)
376 self.produce.plot.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
379class E1DiffSky(SkyCoadd):
380 """The difference between E1 and E1 PSF plotted on
381 a sky plot for coadd level data.
382 Used in debugPSF.
383 """
385 def setDefaults(self):
386 super().setDefaults()
387 self.process.filterActions.zStars = LoadVector(vectorKey="e1Diff")
388 self.produce.plot.zAxisLabel = "E1 Diff"
389 self.produce.plot.plotName = "E1 Diff Sky"
390 self.applyContext(CoaddContext)
393class E1DiffSkyVisit(SkyVisit):
394 """The difference between E1 and E1 PSF plotted on
395 a sky plot for visit level data.
396 Used in debugPSF.
397 """
399 def setDefaults(self):
400 super().setDefaults()
401 self.process.filterActions.zStars = LoadVector(vectorKey="e1Diff")
402 self.produce.plot.zAxisLabel = "E1 Diff"
403 self.produce.plot.plotName = "E1 Diff Sky"
404 self.applyContext(VisitContext)
407class E2DiffSky(SkyCoadd):
408 """The difference between E2 and E2 PSF plotted on
409 a sky plot for coadd level data.
410 Used in debugPSF.
411 """
413 def setDefaults(self):
414 super().setDefaults()
415 self.process.filterActions.zStars = LoadVector(vectorKey="e2Diff")
416 self.produce.plot.zAxisLabel = "E2 Diff"
417 self.produce.plot.plotName = "E2 Diff Sky"
418 self.applyContext(CoaddContext)
421class E2DiffSkyVisit(SkyVisit):
422 """The difference between E2 and E2 PSF plotted on
423 a sky plot for visit level data.
424 Used in debugPSF.
425 """
427 def setDefaults(self):
428 super().setDefaults()
429 self.process.filterActions.zStars = LoadVector(vectorKey="e2Diff")
430 self.produce.plot.zAxisLabel = "E2 Diff"
431 self.produce.plot.plotName = "E2 Diff Sky"
432 self.applyContext(VisitContext)
435class ShapeSizeFractionalDiffSky(SkyCoadd):
436 """The difference between shape and shape PSF plotted on
437 a sky plot for coadd level data.
438 Used in debugPSF.
439 """
441 def setDefaults(self):
442 super().setDefaults()
443 self.applyContext(CoaddContext)
444 self.process.filterActions.zStars = LoadVector(vectorKey="fracDiff")
445 self.produce.plot.zAxisLabel = "E1 Diff"
446 self.produce.plot.plotName = "Fractional Diff Sky"
449class ShapeSizeFractionalDiffSkyVisit(SkyVisit):
450 """The difference between shape and shape PSF plotted on
451 a sky plot for visit level data.
452 Used in debugPSF.
453 """
455 def setDefaults(self):
456 super().setDefaults()
457 self.process.filterActions.zStars = LoadVector(vectorKey="fracDiff")
458 self.produce.plot.zAxisLabel = "E1 Diff"
459 self.produce.plot.plotName = "Fractional Diff Sky"
461 self.applyContext(VisitContext)
464class RhoStatistics(AnalysisTool):
465 parameterizedBand: bool = True
467 def setDefaults(self):
468 super().setDefaults()
469 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
470 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
471 self.prep.selectors.starSelector = StarSelector()
473 self.process.calculateActions.rho = CalcRhoStatistics()
474 self.process.calculateActions.rho.treecorr.nbins = 21
475 self.process.calculateActions.rho.treecorr.min_sep = 0.01
476 self.process.calculateActions.rho.treecorr.max_sep = 100.0
477 self.process.calculateActions.rho.treecorr.sep_units = "arcmin"
478 self.process.calculateActions.rho.treecorr.metric = "Arc"
480 self.produce.plot = RhoStatisticsPlot()
483class RelativeSizeResidualPlot(AnalysisTool):
484 def setDefaults(self):
485 super().setDefaults()
486 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
487 self.prep.selectors.starSelector = StarSelector()
488 self.prep.selectors.starSelector.vectorKey = "extendedness"
489 self.process.buildActions.x = LoadVector()
490 self.process.buildActions.x.vectorKey = "x"
491 self.process.buildActions.y = LoadVector()
492 self.process.buildActions.y.vectorKey = "y"
493 self.process.buildActions.z = FractionalDifference(
494 actionA=CalcMomentSize(colXx="ixx", colYy="iyy", colXy="ixy", sizeType="trace"),
495 actionB=CalcMomentSize(colXx="ixxPSF", colYy="iyyPSF", colXy="ixyPSF", sizeType="trace"),
496 )
497 self.process.buildActions.detector = LoadVector(vectorKey="detector")
498 self.produce.plot = FocalPlanePlot()
499 self.produce.plot.zAxisLabel = "Residuals"
500 self.process.buildActions.statMask = SnSelector()
501 self.process.buildActions.statMask.threshold = 20
502 self.process.buildActions.statMask.fluxType = "psfFlux"
505class EBase(AnalysisTool):
506 """A base class for plotting ellipticity plots."""
508 def setDefaults(self):
509 super().setDefaults()
511 self.prep.selectors.snSelector = SnSelector()
513 self.prep.selectors.starSelector = StarSelector()
515 def visitContext(self):
516 self.parameterizedBand = False
517 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
519 self.prep.selectors.snSelector.fluxType = "psfFlux"
520 self.prep.selectors.snSelector.threshold = 100
522 self.prep.selectors.starSelector.vectorKey = "extendedness"
524 self.process.buildActions.xStars.vectorKey = "psfFlux"
527class EScatter(EBase):
528 """Base class for ellipticity scatter plots."""
530 def setDefaults(self):
531 super().setDefaults()
533 self.process.buildActions.xStars = ConvertFluxToMag()
535 self.process.calculateActions.median = MedianAction()
536 self.process.calculateActions.median.vectorKey = "yStars"
537 self.process.calculateActions.sigmaMad = SigmaMadAction()
538 self.process.calculateActions.sigmaMad.vectorKey = "yStars"
540 self.produce.plot = ScatterPlotWithTwoHists()
541 self.produce.plot.plotTypes = ["stars"]
542 self.produce.plot.xAxisLabel = "PSF Magnitude (mag)"
543 self.produce.plot.magLabel = "PSF Magnitude (mag)"
545 self.produce.metric.units = {"median": "pix", "sigmaMad": "pix"}
548class E1ScatterVisit(EScatter):
549 """Visit level scatter plot for E1."""
551 parameterizedBand: bool = False
553 def setDefaults(self):
554 super().setDefaults()
556 self.process.buildActions.yStarsAll = CalcE1(colXx="ixx", colYy="iyy", colXy="ixy")
557 self.process.buildActions.yStars = DownselectVector(
558 vectorKey="yStarsAll", selector=VectorSelector(vectorKey="starSelector")
559 )
561 self.produce.plot.yAxisLabel = "e1"
563 self.produce.metric.newNames = {
564 "median": "e1_median",
565 "sigmaMad": "e1_sigmaMad",
566 }
567 self.applyContext(VisitContext)
570class E2ScatterVisit(EScatter):
571 """Visit level scatter plot for E2."""
573 parameterizedBand: bool = False
575 def setDefaults(self):
576 super().setDefaults()
578 self.process.buildActions.yStarsAll = CalcE2(colXx="ixx", colYy="iyy", colXy="ixy")
579 self.process.buildActions.yStars = DownselectVector(
580 vectorKey="yStarsAll", selector=VectorSelector(vectorKey="starSelector")
581 )
583 self.produce.plot.yAxisLabel = "e2"
585 self.produce.metric.newNames = {
586 "median": "e2_median",
587 "sigmaMad": "e2_sigmaMad",
588 }
589 self.applyContext(VisitContext)
592class ESky(EBase):
593 """Base class for ellipticity sky plots."""
595 def setDefaults(self):
596 super().setDefaults()
598 self.process.buildActions.xStars = LoadVector()
599 self.process.buildActions.xStars.vectorKey = "coord_ra"
600 self.process.buildActions.yStars = LoadVector()
601 self.process.buildActions.yStars.vectorKey = "coord_dec"
603 self.produce.plot = SkyPlot()
604 self.produce.plot.plotTypes = ["stars"]
605 self.produce.plot.xAxisLabel = "R.A. (deg)"
606 self.produce.plot.yAxisLabel = "Dec. (deg)"
609class E1SkyVisit(ESky):
610 """A sky plot of E1 for visit level data."""
612 parameterizedBand: bool = False
614 def setDefaults(self):
615 super().setDefaults()
617 self.process.buildActions.zStars = CalcE1(colXx="ixx", colYy="iyy", colXy="ixy")
619 self.produce.plot.zAxisLabel = "e1"
621 self.applyContext(VisitContext)
624class E2SkyVisit(ESky):
625 """A visit level sky plot for E2."""
627 parameterizedBand: bool = False
629 def setDefaults(self):
630 super().setDefaults()
632 self.process.buildActions.zStars = CalcE2(colXx="ixx", colYy="iyy", colXy="ixy")
634 self.produce.plot.zAxisLabel = "e2"
636 self.applyContext(VisitContext)
639class EFocalPlane(EBase):
640 """Base class for ellipticity focal plane plots."""
642 def setDefaults(self):
643 super().setDefaults()
645 self.process.buildActions.x = LoadVector(vectorKey="x")
646 self.process.buildActions.y = LoadVector(vectorKey="y")
647 self.process.buildActions.detector = LoadVector(vectorKey="detector")
649 self.process.buildActions.statMask = SnSelector()
650 self.process.buildActions.statMask.threshold = 20
651 self.process.buildActions.statMask.fluxType = "psfFlux"
653 self.produce.plot = FocalPlanePlot()
656class E1FocalPlane(EFocalPlane):
657 """A focal plane plot of E1."""
659 parameterizedBand: bool = False
661 def setDefaults(self):
662 super().setDefaults()
664 self.process.buildActions.z = CalcE1(colXx="ixx", colYy="iyy", colXy="ixy")
665 self.produce.plot.zAxisLabel = "e1"
668class E2FocalPlane(EFocalPlane):
669 """A focal plane plot of E2."""
671 parameterizedBand: bool = False
673 def setDefaults(self):
674 super().setDefaults()
676 self.process.buildActions.z = CalcE2(colXx="ixx", colYy="iyy", colXy="ixy")
677 self.produce.plot.zAxisLabel = "e2"
680class ShapeSizeFractionalDiffFocalPlane(EFocalPlane):
681 """A focal plane plot of shape - psf shape."""
683 parameterizedBand: bool = False
685 def setDefaults(self):
686 super().setDefaults()
687 self.process.buildActions.z = FractionalDifference(
688 actionA=CalcMomentSize(colXx="ixx", colYy="iyy", colXy="ixy"),
689 actionB=CalcMomentSize(colXx="ixxPSF", colYy="iyyPSF", colXy="ixyPSF"),
690 )
691 self.produce.plot.zAxisLabel = "Fractional size residuals (S/S_PSF - 1)"