Skip to content

Commit ebfcfad

Browse files
committed
Merge branch 'tickets/DM-41049'
2 parents c7e23a7 + 93ab550 commit ebfcfad

24 files changed

Lines changed: 770 additions & 200 deletions

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ repos:
66
- id: end-of-file-fixer
77
- id: trailing-whitespace
88
- repo: https://github.com/psf/black
9-
rev: 23.3.0
9+
rev: 24.3.0
1010
hooks:
1111
- id: black
1212
# It is recommended to specify the latest version of Python
@@ -15,7 +15,7 @@ repos:
1515
# https://pre-commit.com/#top_level-default_language_version
1616
language_version: "python3.11"
1717
- repo: https://github.com/pycqa/isort
18-
rev: 5.12.0
18+
rev: 5.13.2
1919
hooks:
2020
- id: isort
2121
name: isort (python)

doc/lsst.analysis.tools/faqs.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ FAQs
66
What Order are Configs Applied In?
77
----------------------------------
88

9-
In analysis tools there are a number of ways to set config options which are applied in a certain order. If
9+
In analysis tools there are a number of ways to set config options which are applied in a certain order. If
1010
you get this order wrong you might be suprised by what your action is doing. In order from first applied to
1111
last applied:
1212

@@ -16,8 +16,8 @@ last applied:
1616
4. The pipeline file configs
1717
5. The command line --config and --config-file options
1818

19-
Due to this configs that are obs package specific should not be specified in the pipeline file because they
20-
overwrite the obs specific configs. For example the bands option, if that is set in the pipeline file it will
19+
Due to this configs that are obs package specific should not be specified in the pipeline file because they
20+
overwrite the obs specific configs. For example the bands option, if that is set in the pipeline file it will
2121
overwrite the obs package which means that if you try to apply the same pipeline to HSC and DC2 data (for
2222
example) it will not work for both as each survey has different band coverage.
2323

@@ -30,12 +30,12 @@ to be applied in the bands that the plot is being made in then the flag config o
3030
Where is the line between python and YAML?
3131
------------------------------------------
3232

33-
This can be a bit of a blurry line and in the end is up to the individual developer. A rough guideline is that
33+
This can be a bit of a blurry line and in the end is up to the individual developer. A rough guideline is that
3434
if the code is reusable either for variants of the original action or useful for other actions then it belongs
3535
in its own python class. If it is single use or a specific instance of a class then it should be done through
3636
the YAML config. An example of this is the photometric repeatability metrics. Here there is a base action
3737
called PhotometricRepeatability, defined in python, which is then configured for each individual application
38-
in the pipeline YAML.
38+
in the pipeline YAML.
3939

4040
.. code-block:: yaml
4141
@@ -46,18 +46,18 @@ in the pipeline YAML.
4646
atools.modelPhotRepGalSn5to10.process.filterActions.perGroupStdevFiltered.selectors.sn.maximum: 10
4747
4848
The first line calls the action defined in python, after that the specific configuration is set in the
49-
pipeline YAML. This is a good balance between defining the entire action in YAML and having duplicate actions
49+
pipeline YAML. This is a good balance between defining the entire action in YAML and having duplicate actions
5050
defined in the python with only very mild differences.
5151

5252
Can analysis tools put things in the butler?
5353
--------------------------------------------
5454

5555
Short answer, yes! Long answer, while the tools themselves do not put things in the butler the tasks in the
5656
pipelines contained in analysis tools can. As an example lets look at the plots and metrics calculated from
57-
matching to the reference catalogues. First there is a task that matches the input data to the reference
57+
matching to the reference catalogues. First there is a task that matches the input data to the reference
5858
catalogue. This then saves in the butler the matched output so that it can be read in later by multiple
59-
atools and also used in a notebook or script if further QA is required. After the matched catalogue is made
60-
the plotting/metric/calculation atools read it in, then act on it. The atools themselves do not butler put
59+
atools and also used in a notebook or script if further QA is required. After the matched catalogue is made
60+
the plotting/metric/calculation atools read it in, then act on it. The atools themselves do not butler put
6161
the metric/plot/calculated data but return them to the task that ran them which then puts them in the right
6262
place. Most of this is hidden from the user and the interfaces handle putting plots and metrics themselves.
6363

pipelines/coaddDiffMatchedQualityExtended.yaml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
description: |
22
Matched difference (measured vs reference) plots/metrics
33
parameters:
4+
color_diff_min: -250
5+
color_diff_max: 250
46
mag_x_min: 17
57
mag_x_max: 29
68
mag_diff_min: -1000
@@ -17,10 +19,16 @@ tasks:
1719
config:
1820
connections.outputName: diff_matched_truth_summary_objectTable_tract
1921

20-
# plots
22+
atools.matchedRefCModelColorDiff: MatchedRefCoaddDiffColorTool
23+
atools.matchedRefCModelColorDiff.produce.plot.xLims: lims_mag_x
24+
atools.matchedRefCModelColorDiff.produce.plot.yLims: lims_color_diff
25+
26+
atools.matchedRefCModelColorChi: MatchedRefCoaddDiffColorTool
27+
atools.matchedRefCModelColorChi.compute_chi: true
28+
atools.matchedRefCModelColorChi.produce.plot.xLims: lims_mag_x
29+
atools.matchedRefCModelColorChi.produce.plot.yLims: lims_mag_chi
30+
2131
atools.matchedRefCModelMagDiff: MatchedRefCoaddDiffMagTool
22-
# Doesn't work; interpreted as float
23-
# atools.matchedRefCModelMagDiff.produce.plot.xLims: [parameters.mag_x_min, parameters.mag_x_max]
2432
atools.matchedRefCModelMagDiff.produce.plot.xLims: lims_mag_x
2533
atools.matchedRefCModelMagDiff.produce.plot.yLims: lims_mag_diff
2634

@@ -29,7 +37,6 @@ tasks:
2937
atools.matchedRefCModelMagChi.produce.plot.xLims: lims_mag_x
3038
atools.matchedRefCModelMagChi.produce.plot.yLims: lims_mag_chi
3139

32-
# TODO: Can this be a one liner?
3340
atools.matchedRefPositionXDiff: MatchedRefCoaddDiffPositionTool
3441
atools.matchedRefPositionXDiff.coord_meas: x
3542
atools.matchedRefPositionXDiff.coord_ref: refcat_x
@@ -55,12 +62,13 @@ tasks:
5562
atools.matchedRefPositionYChi.produce.plot.xLims: lims_mag_x
5663
atools.matchedRefPositionYChi.produce.plot.yLims: lims_pos_chi
5764
atools.matchedRefPositionYChi.compute_chi: true
58-
5965
python: |
6066
from lsst.analysis.tools.atools.diffMatched import (
67+
MatchedRefCoaddDiffColorTool,
6168
MatchedRefCoaddDiffMagTool,
6269
MatchedRefCoaddDiffPositionTool,
6370
)
71+
lims_color_diff = (parameters.color_diff_min, parameters.color_diff_max)
6472
lims_mag_x = (parameters.mag_x_min, parameters.mag_x_max)
6573
lims_mag_chi = (parameters.mag_chi_min, parameters.mag_chi_max)
6674
lims_mag_diff = (parameters.mag_diff_min, parameters.mag_diff_max)

pipelines/coaddQualityCore.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ tasks:
2727
atools.shapeSizeDetRadiusVsCmodelMag.size_type: "determinantRadius"
2828
atools.shapeSizeDetRadiusVsCmodelMag.mag_x: "cmodel_err"
2929
atools.shapeSizeDetRadiusVsCmodelMag.size_y: "shape_slot"
30+
atools.shapeSizeDetRadiusVsCmodelMag.produce.plot.xLims: (17, 29)
31+
atools.shapeSizeDetRadiusVsCmodelMag.produce.plot.yLims: (-4, 3)
3032
atools.shapeSizeDetRadiusVsCmodelMag.applyContext: CoaddContext
3133
atools.shapeSizeDetRadiusVsPsfMag: SizeMagnitudePlot
3234
atools.shapeSizeDetRadiusVsPsfMag.size_type: "determinantRadius"
@@ -37,11 +39,15 @@ tasks:
3739
atools.cModelBulgeSizeVsCmodelBulgeMag.size_type: "singleColumnSize"
3840
atools.cModelBulgeSizeVsCmodelBulgeMag.mag_x: "bulge_err"
3941
atools.cModelBulgeSizeVsCmodelBulgeMag.size_y: "bulge"
42+
atools.cModelBulgeSizeVsCmodelBulgeMag.produce.plot.xLims: (17, 29)
43+
atools.cModelBulgeSizeVsCmodelBulgeMag.produce.plot.yLims: (-4, 3)
4044
atools.cModelBulgeSizeVsCmodelBulgeMag.applyContext: CoaddContext
4145
atools.cModelDiskSizeVsCmodelDiskMag: SizeMagnitudePlot
4246
atools.cModelDiskSizeVsCmodelDiskMag.size_type: "singleColumnSize"
4347
atools.cModelDiskSizeVsCmodelDiskMag.mag_x: "disk_err"
4448
atools.cModelDiskSizeVsCmodelDiskMag.size_y: "disk"
49+
atools.cModelDiskSizeVsCmodelDiskMag.produce.plot.xLims: (17, 29)
50+
atools.cModelDiskSizeVsCmodelDiskMag.produce.plot.yLims: (-4, 3)
4551
atools.cModelDiskSizeVsCmodelDiskMag.applyContext: CoaddContext
4652
python: |
4753
from lsst.analysis.tools.atools import *

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,3 @@ line_length = 110
88

99
[tool.lsst_versions]
1010
write_to = "python/lsst/analysis/tools/version.py"
11-

python/lsst/analysis/tools/actions/plot/rhoStatisticsPlot.py

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,18 @@
2121

2222
from __future__ import annotations
2323

24-
from typing import TYPE_CHECKING, Any, Iterable, Mapping
25-
2624
__all__ = ("RhoStatisticsPlot",)
2725

26+
from typing import Any, Iterable, Mapping
27+
2828
import numpy as np
2929
from lsst.pex.config import ConfigDictField
30+
from matplotlib.figure import Figure
3031

31-
from ...interfaces import PlotAction, Vector
32+
from ...interfaces import KeyedData, KeyedDataSchema, PlotAction, Vector
3233
from .plotUtils import addPlotInfo
3334
from .xyPlot import XYPlot
3435

35-
if TYPE_CHECKING:
36-
from matplotlib.figure import Figure
37-
38-
from ...interfaces import KeyedData, KeyedDataSchema
39-
4036

4137
class RhoStatisticsPlot(PlotAction):
4238
"""Make multiple plots of rho statistics.
@@ -46,10 +42,8 @@ class RhoStatisticsPlot(PlotAction):
4642
:ref:`here <rho_definitions>`.
4743
"""
4844

49-
rhoPlots = ConfigDictField(
45+
rhoPlots = ConfigDictField[str, XYPlot](
5046
doc="A configurable dict describing the rho statistics to plot.",
51-
keytype=str,
52-
itemtype=XYPlot,
5347
default={},
5448
)
5549

@@ -91,15 +85,17 @@ def getInputSchema(self) -> KeyedDataSchema:
9185

9286
def getOutputNames(self) -> Iterable[str]:
9387
# Docstring inherited
94-
return ("rho3alt", "rho1", "rho2", "rho3", "rho4", "rho5")
88+
for key in self.rhoPlots.keys():
89+
yield key
9590

9691
def __call__(self, data: KeyedData, **kwargs) -> Mapping[str, Figure]:
9792
self._validateInput(data)
9893
return self.makePlot(data, **kwargs)
9994

10095
def _validateInput(self, data: KeyedData) -> None:
101-
if not set(("rho3alt", "rho1", "rho2", "rho3", "rho4", "rho5")).issubset(data.keys()):
102-
raise ValueError("Input data must contain rho3alt, rho1, rho2, rho3, rho4, and rho5.")
96+
required = set(self.rhoPlots.keys())
97+
if not required.issubset(data.keys()):
98+
raise ValueError(f"Input data must contain {', '.join(self.rhoPlots.keys())}")
10399

104100
def makePlot(
105101
self, data: KeyedData, plotInfo: Mapping[str, str] | None = None, **kwargs: Any
@@ -141,28 +137,20 @@ def makePlot(
141137
:ref:`getting started guide<analysis-tools-getting-started>`.
142138
"""
143139
fig_dict: dict[str, Figure] = {}
144-
for rho_name in ("rho1", "rho2", "rho3", "rho4", "rho5"):
140+
for rho_name in self.rhoPlots.keys():
145141
rho: XYPlot = self.rhoPlots[rho_name]
146-
147142
subdata = {
148143
"x": data[rho_name].meanr, # type: ignore
149-
"y": data[rho_name].xip, # type: ignore
150-
"yerr": np.sqrt(data[rho_name].varxip), # type: ignore
151144
"xerr": None,
152145
}
146+
if rho_name == "rho3alt":
147+
subdata["y"] = data[rho_name].xi # type: ignore
148+
subdata["yerr"] = np.sqrt(data[rho_name].varxi)
149+
else:
150+
subdata["y"] = data[rho_name].xip # type: ignore
151+
subdata["yerr"] = np.sqrt(data[rho_name].varxip) # type: ignore
153152
fig = rho(subdata, **kwargs)
154153
if plotInfo is not None:
155154
fig_dict[rho_name] = addPlotInfo(fig, plotInfo)
156155

157-
# rho3alt is handled differently because its attributes differ.
158-
subdata = {
159-
"x": data["rho3alt"].meanr, # type: ignore
160-
"y": data["rho3alt"].xi, # type: ignore
161-
"yerr": np.sqrt(data["rho3alt"].varxi), # type: ignore
162-
"xerr": None,
163-
}
164-
fig = self.rhoPlots["rho3alt"](subdata, **kwargs) # type: ignore[misc]
165-
if plotInfo is not None:
166-
fig_dict["rho3alt"] = addPlotInfo(fig, plotInfo)
167-
168156
return fig_dict

0 commit comments

Comments
 (0)