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

168 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-25 03:15 -0800

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 "Ap12PsfSkyPlot", 

28 "WPerpPSFPlot", 

29 "WPerpCModelPlot", 

30 "XPerpPSFPlot", 

31 "XPerpCModelPlot", 

32 "YPerpPSFPlot", 

33 "YPerpCModelPlot", 

34 "TargetRefCatDeltaRAScatterPlot", 

35 "TargetRefCatDeltaRAScatterPlot", 

36) 

37 

38from lsst.pex.config import Field 

39 

40from ..actions.plot.colorColorFitPlot import ColorColorFitPlot 

41from ..actions.plot.histPlot import HistPanel, HistPlot 

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

43from ..actions.plot.skyPlot import SkyPlot 

44from ..actions.vector import ( 

45 AstromDiff, 

46 CoaddPlotFlagSelector, 

47 DownselectVector, 

48 ExtinctionCorrectedMagDiff, 

49 LoadVector, 

50 MagColumnNanoJansky, 

51 SnSelector, 

52 StarSelector, 

53 VectorSelector, 

54) 

55from ..analysisParts.baseFluxRatio import BasePsfApRatio 

56from ..analysisParts.genericPrep import CoaddPrep, VisitPrep 

57from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin 

58from ..analysisParts.stellarLocus import WPerpCModel, WPerpPSF, XPerpCModel, XPerpPSF, YPerpCModel, YPerpPSF 

59from ..interfaces import AnalysisPlot 

60 

61 

62class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin): 

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

64 

65 This is shared by size and ellipticity plots. 

66 """ 

67 

68 def setDefaults(self): 

69 super().setDefaults() 

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

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

72 

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

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

75 

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

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

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

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

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

81 

82 self.process.filterActions.xStars = DownselectVector( 

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

84 ) 

85 # downselect the psfFlux as well 

86 self.process.filterActions.psfFlux = DownselectVector( 

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

88 ) 

89 self.process.filterActions.psfFluxErr = DownselectVector( 

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

91 ) 

92 

93 self.process.filterActions.patch = DownselectVector( 

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

95 ) 

96 

97 self.process.calculateActions.stars = ScatterPlotStatsAction( 

98 vectorKey="yStars", 

99 ) 

100 # use the downselected psfFlux 

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

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

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

104 

105 self.produce = ScatterPlotWithTwoHists() 

106 

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

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

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

110 self.produce.addSummaryPlot = True 

111 

112 

113class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot): 

114 def setDefaults(self): 

115 super().setDefaults() 

116 self.process.filterActions.yStars = DownselectVector( 

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

118 ) 

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

120 

121 

122class E1DiffScatterPlot(BasePsfResidualScatterPlot): 

123 def setDefaults(self): 

124 super().setDefaults() 

125 self.process.filterActions.yStars = DownselectVector( 

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

127 ) 

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

129 

130 

131class E2DiffScatterPlot(BasePsfResidualScatterPlot): 

132 def setDefaults(self): 

133 super().setDefaults() 

134 self.process.filterActions.yStars = DownselectVector( 

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

136 ) 

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

138 

139 

140class WPerpPSFPlot(WPerpPSF, AnalysisPlot): 

141 def setDefaults(self): 

142 super().setDefaults() 

143 

144 self.produce = ColorColorFitPlot() 

145 self.produce.xAxisLabel = "g - r (PSF) [mags]" 

146 self.produce.yAxisLabel = "r - i (PSF) [mags]" 

147 self.produce.magLabel = "PSF Mag" 

148 self.produce.plotName = "wPerp_psfFlux" 

149 

150 

151class WPerpCModelPlot(WPerpCModel, AnalysisPlot): 

152 def setDefaults(self): 

153 super().setDefaults() 

154 

155 self.produce = ColorColorFitPlot() 

156 self.produce.xAxisLabel = "g - r (CModel) [mags]" 

157 self.produce.yAxisLabel = "r - i (CModel) [mags]" 

158 self.produce.magLabel = "CModel Mag" 

159 self.produce.plotName = "wPerp_cmodelFlux" 

160 

161 

162class XPerpPSFPlot(XPerpPSF, AnalysisPlot): 

163 def setDefaults(self): 

164 super().setDefaults() 

165 

166 self.produce = ColorColorFitPlot() 

167 self.produce.xAxisLabel = "g - r (PSF) [mags]" 

168 self.produce.yAxisLabel = "r - i (PSF) [mags]" 

169 self.produce.magLabel = "PSF Mag" 

170 self.produce.plotName = "xPerp_psfFlux" 

171 

172 

173class XPerpCModelPlot(XPerpCModel, AnalysisPlot): 

174 def setDefaults(self): 

175 super().setDefaults() 

176 

177 self.produce = ColorColorFitPlot() 

178 self.produce.xAxisLabel = "g - r (CModel) [mags]" 

179 self.produce.yAxisLabel = "r - i (CModel) [mags]" 

180 self.produce.magLabel = "CModel Mag" 

181 self.produce.plotName = "xPerp_cmodelFlux" 

182 

183 

184class YPerpPSFPlot(YPerpPSF, AnalysisPlot): 

185 def setDefaults(self): 

186 super().setDefaults() 

187 

188 self.produce = ColorColorFitPlot() 

189 self.produce.xAxisLabel = "r - i (PSF) [mags]" 

190 self.produce.yAxisLabel = "i - z (PSF) [mags]" 

191 self.produce.magLabel = "PSF Mag" 

192 self.produce.plotName = "yPerp_psfFlux" 

193 

194 

195class YPerpCModelPlot(YPerpCModel, AnalysisPlot): 

196 def setDefaults(self): 

197 super().setDefaults() 

198 

199 self.produce = ColorColorFitPlot() 

200 self.produce.xAxisLabel = "r - i (CModel) [mags]" 

201 self.produce.yAxisLabel = "i - z (CModel) [mags]" 

202 self.produce.magLabel = "CModel Mag" 

203 self.produce.plotName = "yPerp_cmodelFlux" 

204 

205 

206class Ap12PsfSkyPlot(AnalysisPlot): 

207 def setDefaults(self): 

208 super().setDefaults() 

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

210 # Set this to an empty list to look at the band 

211 # the plot is being made in. 

212 self.prep.selectors.flagSelector.bands = [] 

213 

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

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

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

217 

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

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

220 

221 # TODO: Can we make these defaults somewhere? 

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

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

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

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

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

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

228 

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

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

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

232 

233 self.produce = SkyPlot() 

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

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

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

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

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

239 self.produce.plotOutlines = False 

240 

241 

242class TargetRefCatDelta(AnalysisPlot): 

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

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

245 """ 

246 

247 parameterizedBand = Field[bool]( 

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

249 ) 

250 

251 def coaddContext(self) -> None: 

252 self.prep = CoaddPrep() 

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

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

255 self.process.filterActions.psfFlux = DownselectVector( 

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

257 ) 

258 self.process.filterActions.psfFluxErr = DownselectVector( 

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

260 ) 

261 

262 def visitContext(self) -> None: 

263 self.parameterizedBand = False 

264 self.prep = VisitPrep() 

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

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

267 self.process.filterActions.psfFlux = DownselectVector( 

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

269 ) 

270 self.process.filterActions.psfFluxErr = DownselectVector( 

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

272 ) 

273 

274 def setDefaults(self, coordinate): 

275 super().setDefaults() 

276 

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

278 coordStr = coordinate.lower() 

279 self.process.buildActions.astromDiff = AstromDiff( 

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

281 ) 

282 

283 self.process.filterActions.xStars = DownselectVector( 

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

285 ) 

286 self.process.filterActions.yStars = DownselectVector( 

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

288 ) 

289 

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

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

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

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

294 

295 self.produce = ScatterPlotWithTwoHists() 

296 

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

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

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

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

301 

302 

303class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta): 

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

305 and a reference catalog 

306 """ 

307 

308 def setDefaults(self): 

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

310 

311 

312class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta): 

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

314 and a reference catalog 

315 """ 

316 

317 def setDefaults(self): 

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

319 

320 

321class FluxRatioPlot(AnalysisPlot, BasePsfApRatio): 

322 """Plot a histogram of the PSF and AP flux ratios of sources.""" 

323 

324 def setDefaults(self): 

325 super().setDefaults() 

326 

327 self.produce = HistPlot() 

328 

329 self.produce.panels["panel_flux"] = HistPanel() 

330 self.produce.panels["panel_flux"].label = "Psf/Ap Ratio" 

331 self.produce.panels["panel_flux"].hists = dict(fluxRatioMetric="Ratio")