Coverage for python/lsst/analysis/tools/analysisPlots/analysisPlots.py: 33%

138 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-16 01:43 -0700

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 

22 

23__all__ = ( 

24 "E1DiffScatterPlot", 

25 "E2DiffScatterPlot", 

26 "ShapeSizeFractionalDiffScatterPlot", 

27 "WPerpPSFPlot", 

28 "Ap12PsfSkyPlot", 

29 "TargetRefCatDeltaRAScatterPlot", 

30 "TargetRefCatDeltaRAScatterPlot", 

31) 

32 

33from lsst.pex.config import Field 

34 

35from ..actions.keyedData.stellarLocusFit import StellarLocusFitAction 

36from ..actions.plot.colorColorFitPlot import ColorColorFitPlot 

37from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists 

38from ..actions.plot.skyPlot import SkyPlot 

39from ..actions.scalar import ApproxFloor 

40from ..actions.vector import ( 

41 AstromDiff, 

42 CoaddPlotFlagSelector, 

43 DownselectVector, 

44 ExtinctionCorrectedMagDiff, 

45 LoadVector, 

46 MagColumnNanoJansky, 

47 SnSelector, 

48 StarSelector, 

49 VectorSelector, 

50) 

51from ..analysisParts.genericPrep import CoaddPrep, VisitPrep 

52from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin 

53from ..interfaces import AnalysisPlot 

54 

55 

56class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin): 

57 """Base class for scatter plots of PSF residuals. 

58 

59 This is shared by size and ellipticity plots. 

60 """ 

61 

62 def setDefaults(self): 

63 super().setDefaults() 

64 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

65 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100) 

66 

67 self.process.buildActions.patchWhole = LoadVector() 

68 self.process.buildActions.patchWhole.vectorKey = "patch" 

69 

70 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux") 

71 # pre-compute a stellar selector mask so it can be used in the filter 

72 # actions while only being computed once, alternatively the stellar 

73 # selector could be calculated and applied twice in the filter stage 

74 self.process.buildActions.starSelector = StarSelector() 

75 

76 self.process.filterActions.xStars = DownselectVector( 

77 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector") 

78 ) 

79 # downselect the psfFlux as well 

80 self.process.filterActions.psfFlux = DownselectVector( 

81 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector") 

82 ) 

83 self.process.filterActions.psfFluxErr = DownselectVector( 

84 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector") 

85 ) 

86 

87 self.process.filterActions.patch = DownselectVector( 

88 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector") 

89 ) 

90 

91 self.process.calculateActions.stars = ScatterPlotStatsAction( 

92 vectorKey="yStars", 

93 ) 

94 # use the downselected psfFlux 

95 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux" 

96 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux" 

97 self.process.calculateActions.stars.fluxType = "psfFlux" 

98 

99 self.produce = ScatterPlotWithTwoHists() 

100 

101 self.produce.plotTypes = ["stars"] 

102 self.produce.xAxisLabel = "PSF Magnitude (mag)" 

103 self.produce.magLabel = "PSF Magnitude (mag)" 

104 self.produce.addSummaryPlot = True 

105 

106 

107class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot): 

108 def setDefaults(self): 

109 super().setDefaults() 

110 self.process.filterActions.yStars = DownselectVector( 

111 vectorKey="fracDiff", selector=VectorSelector(vectorKey="starSelector") 

112 ) 

113 self.produce.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)" 

114 

115 

116class E1DiffScatterPlot(BasePsfResidualScatterPlot): 

117 def setDefaults(self): 

118 super().setDefaults() 

119 self.process.filterActions.yStars = DownselectVector( 

120 vectorKey="e1Diff", selector=VectorSelector(vectorKey="starSelector") 

121 ) 

122 self.produce.yAxisLabel = "Ellipticty residuals (e1 - e1_PSF)" 

123 

124 

125class E2DiffScatterPlot(BasePsfResidualScatterPlot): 

126 def setDefaults(self): 

127 super().setDefaults() 

128 self.process.filterActions.yStars = DownselectVector( 

129 vectorKey="e2Diff", selector=VectorSelector(vectorKey="starSelector") 

130 ) 

131 self.produce.yAxisLabel = "Ellipticty residuals (e2 - e2_PSF)" 

132 

133 

134class WPerpPSFPlot(AnalysisPlot): 

135 # WPerp does not support running in multiband mode 

136 multiband: bool = False 

137 

138 def setDefaults(self): 

139 super().setDefaults() 

140 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

141 self.prep.selectors.flagSelector.bands = ["g", "r", "i"] 

142 

143 self.prep.selectors.snSelector = SnSelector() 

144 self.prep.selectors.snSelector.bands = ["r"] 

145 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux" 

146 self.prep.selectors.snSelector.threshold = 300 

147 

148 self.prep.selectors.starSelector = StarSelector() 

149 self.prep.selectors.starSelector.vectorKey = "r_extendedness" 

150 

151 self.process.buildActions.x = ExtinctionCorrectedMagDiff() 

152 self.process.buildActions.x.magDiff.col1 = "g_psfFlux" 

153 self.process.buildActions.x.magDiff.col2 = "r_psfFlux" 

154 self.process.buildActions.x.magDiff.returnMillimags = False 

155 self.process.buildActions.y = ExtinctionCorrectedMagDiff() 

156 self.process.buildActions.y.magDiff.col1 = "r_psfFlux" 

157 self.process.buildActions.y.magDiff.col2 = "i_psfFlux" 

158 self.process.buildActions.y.magDiff.returnMillimags = False 

159 self.process.buildActions.mag = MagColumnNanoJansky(vectorKey="r_psfFlux") 

160 

161 self.process.calculateActions.approxMagDepth = ApproxFloor(vectorKey="mag") 

162 self.process.calculateActions.wPerp_psfFlux = StellarLocusFitAction() 

163 self.process.calculateActions.wPerp_psfFlux.stellarLocusFitDict = { 

164 "xMin": 0.28, 

165 "xMax": 1.0, 

166 "yMin": 0.02, 

167 "yMax": 0.48, 

168 "mHW": 0.52, 

169 "bHW": -0.08, 

170 } 

171 

172 self.produce = ColorColorFitPlot() 

173 self.produce.plotName = "wPerp_psfFlux" 

174 

175 

176class Ap12PsfSkyPlot(AnalysisPlot): 

177 def setDefaults(self): 

178 super().setDefaults() 

179 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

180 self.prep.selectors.flagSelector.bands = ["{band}"] 

181 

182 self.prep.selectors.snSelector = SnSelector() 

183 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux" 

184 self.prep.selectors.snSelector.threshold = 300 

185 

186 self.prep.selectors.starSelector = StarSelector() 

187 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness" 

188 

189 # TODO: Can we make these defaults somewhere? 

190 self.process.buildActions.xStars = LoadVector() 

191 self.process.buildActions.xStars.vectorKey = "coord_ra" 

192 self.process.buildActions.yStars = LoadVector() 

193 self.process.buildActions.yStars.vectorKey = "coord_dec" 

194 self.process.buildActions.starStatMask = SnSelector() 

195 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux" 

196 

197 self.process.buildActions.zStars = ExtinctionCorrectedMagDiff() 

198 self.process.buildActions.zStars.magDiff.col1 = "{band}_ap12Flux" 

199 self.process.buildActions.zStars.magDiff.col2 = "{band}_psfFlux" 

200 

201 self.produce = SkyPlot() 

202 self.produce.plotTypes = ["stars"] 

203 self.produce.plotName = "ap12-psf_{band}" 

204 self.produce.xAxisLabel = "R.A. (degrees)" 

205 self.produce.yAxisLabel = "Dec. (degrees)" 

206 self.produce.zAxisLabel = "Ap 12 - PSF [mag]" 

207 self.produce.plotOutlines = False 

208 

209 

210class TargetRefCatDelta(AnalysisPlot): 

211 """Plot the difference in milliseconds between a target catalog and a 

212 reference catalog for the coordinate set in `setDefaults`. 

213 """ 

214 

215 parameterizedBand = Field[bool]( 

216 doc="Does this AnalysisTool support band as a name parameter", default=True 

217 ) 

218 

219 def coaddContext(self) -> None: 

220 self.prep = CoaddPrep() 

221 self.process.buildActions.starSelector.vectorKey = "{band}_extendedness" 

222 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux") 

223 self.process.filterActions.psfFlux = DownselectVector( 

224 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector") 

225 ) 

226 self.process.filterActions.psfFluxErr = DownselectVector( 

227 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector") 

228 ) 

229 

230 def visitContext(self) -> None: 

231 self.parameterizedBand = False 

232 self.prep = VisitPrep() 

233 self.process.buildActions.starSelector.vectorKey = "extendedness" 

234 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="psfFlux") 

235 self.process.filterActions.psfFlux = DownselectVector( 

236 vectorKey="psfFlux", selector=VectorSelector(vectorKey="starSelector") 

237 ) 

238 self.process.filterActions.psfFluxErr = DownselectVector( 

239 vectorKey="psfFluxErr", selector=VectorSelector(vectorKey="starSelector") 

240 ) 

241 

242 def setDefaults(self, coordinate): 

243 super().setDefaults() 

244 

245 self.process.buildActions.starSelector = StarSelector() 

246 coordStr = coordinate.lower() 

247 self.process.buildActions.astromDiff = AstromDiff( 

248 col1=f"coord_{coordStr}_target", col2=f"coord_{coordStr}_ref" 

249 ) 

250 

251 self.process.filterActions.xStars = DownselectVector( 

252 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector") 

253 ) 

254 self.process.filterActions.yStars = DownselectVector( 

255 vectorKey="astromDiff", selector=VectorSelector(vectorKey="starSelector") 

256 ) 

257 

258 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars") 

259 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux" 

260 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux" 

261 self.process.calculateActions.stars.fluxType = "psfFlux" 

262 

263 self.produce = ScatterPlotWithTwoHists() 

264 

265 self.produce.plotTypes = ["stars"] 

266 self.produce.xAxisLabel = "PSF Magnitude (mag)" 

267 self.produce.yAxisLabel = f"${coordinate}_{{target}} - {coordinate}_{{ref}}$ (marcsec)" 

268 self.produce.magLabel = "PSF Magnitude (mag)" 

269 

270 

271class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta): 

272 """Plot the difference in milliseconds between the RA of a target catalog 

273 and a reference catalog 

274 """ 

275 

276 def setDefaults(self): 

277 super().setDefaults(coordinate="RA") 

278 

279 

280class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta): 

281 """Plot the difference in milliseconds between the Dec of a target catalog 

282 and a reference catalog 

283 """ 

284 

285 def setDefaults(self): 

286 super().setDefaults(coordinate="Dec")