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

150 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-03 08:39 +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 

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.histPlot import HistPanel, HistPlot 

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

39from ..actions.plot.skyPlot import SkyPlot 

40from ..actions.scalar import ApproxFloor 

41from ..actions.vector import ( 

42 AstromDiff, 

43 CoaddPlotFlagSelector, 

44 DownselectVector, 

45 ExtinctionCorrectedMagDiff, 

46 LoadVector, 

47 MagColumnNanoJansky, 

48 SnSelector, 

49 StarSelector, 

50 VectorSelector, 

51) 

52from ..analysisParts.baseFluxRatio import BasePsfApRatio 

53from ..analysisParts.genericPrep import CoaddPrep, VisitPrep 

54from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin 

55from ..interfaces import AnalysisPlot 

56 

57 

58class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin): 

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

60 

61 This is shared by size and ellipticity plots. 

62 """ 

63 

64 def setDefaults(self): 

65 super().setDefaults() 

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

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

68 

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

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

71 

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

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

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

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

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

77 

78 self.process.filterActions.xStars = DownselectVector( 

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

80 ) 

81 # downselect the psfFlux as well 

82 self.process.filterActions.psfFlux = DownselectVector( 

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

84 ) 

85 self.process.filterActions.psfFluxErr = DownselectVector( 

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

87 ) 

88 

89 self.process.filterActions.patch = DownselectVector( 

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

91 ) 

92 

93 self.process.calculateActions.stars = ScatterPlotStatsAction( 

94 vectorKey="yStars", 

95 ) 

96 # use the downselected psfFlux 

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

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

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

100 

101 self.produce = ScatterPlotWithTwoHists() 

102 

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

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

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

106 self.produce.addSummaryPlot = True 

107 

108 

109class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot): 

110 def setDefaults(self): 

111 super().setDefaults() 

112 self.process.filterActions.yStars = DownselectVector( 

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

114 ) 

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

116 

117 

118class E1DiffScatterPlot(BasePsfResidualScatterPlot): 

119 def setDefaults(self): 

120 super().setDefaults() 

121 self.process.filterActions.yStars = DownselectVector( 

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

123 ) 

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

125 

126 

127class E2DiffScatterPlot(BasePsfResidualScatterPlot): 

128 def setDefaults(self): 

129 super().setDefaults() 

130 self.process.filterActions.yStars = DownselectVector( 

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

132 ) 

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

134 

135 

136class WPerpPSFPlot(AnalysisPlot): 

137 # WPerp does not support running in multiband mode 

138 multiband: bool = False 

139 

140 def setDefaults(self): 

141 super().setDefaults() 

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

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

144 

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

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

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

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

149 

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

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

152 

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

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

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

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

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

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

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

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

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

162 

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

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

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

166 "xMin": 0.28, 

167 "xMax": 1.0, 

168 "yMin": 0.02, 

169 "yMax": 0.48, 

170 "mHW": 0.52, 

171 "bHW": -0.08, 

172 } 

173 

174 self.produce = ColorColorFitPlot() 

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

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

177 self.produce.magLabel = "PSF Mag" 

178 self.produce.plotName = "wPerp_psfFlux" 

179 

180 

181class Ap12PsfSkyPlot(AnalysisPlot): 

182 def setDefaults(self): 

183 super().setDefaults() 

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

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

186 

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

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

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

190 

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

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

193 

194 # TODO: Can we make these defaults somewhere? 

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

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

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

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

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

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

201 

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

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

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

205 

206 self.produce = SkyPlot() 

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

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

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

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

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

212 self.produce.plotOutlines = False 

213 

214 

215class TargetRefCatDelta(AnalysisPlot): 

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

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

218 """ 

219 

220 parameterizedBand = Field[bool]( 

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

222 ) 

223 

224 def coaddContext(self) -> None: 

225 self.prep = CoaddPrep() 

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

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

228 self.process.filterActions.psfFlux = DownselectVector( 

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

230 ) 

231 self.process.filterActions.psfFluxErr = DownselectVector( 

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

233 ) 

234 

235 def visitContext(self) -> None: 

236 self.parameterizedBand = False 

237 self.prep = VisitPrep() 

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

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

240 self.process.filterActions.psfFlux = DownselectVector( 

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

242 ) 

243 self.process.filterActions.psfFluxErr = DownselectVector( 

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

245 ) 

246 

247 def setDefaults(self, coordinate): 

248 super().setDefaults() 

249 

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

251 coordStr = coordinate.lower() 

252 self.process.buildActions.astromDiff = AstromDiff( 

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

254 ) 

255 

256 self.process.filterActions.xStars = DownselectVector( 

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

258 ) 

259 self.process.filterActions.yStars = DownselectVector( 

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

261 ) 

262 

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

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

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

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

267 

268 self.produce = ScatterPlotWithTwoHists() 

269 

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

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

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

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

274 

275 

276class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta): 

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

278 and a reference catalog 

279 """ 

280 

281 def setDefaults(self): 

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

283 

284 

285class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta): 

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

287 and a reference catalog 

288 """ 

289 

290 def setDefaults(self): 

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

292 

293 

294class FluxRatioPlot(AnalysisPlot, BasePsfApRatio): 

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

296 

297 def setDefaults(self): 

298 super().setDefaults() 

299 

300 self.produce = HistPlot() 

301 

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

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

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