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

180 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-12-16 02:54 -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 "SourcesPlot", 

37) 

38 

39from lsst.pex.config import Field 

40 

41from ..actions.plot.barPlots import BarPanel, BarPlot 

42from ..actions.plot.colorColorFitPlot import ColorColorFitPlot 

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

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

45from ..actions.plot.skyPlot import SkyPlot 

46from ..actions.scalar import CountAction 

47from ..actions.vector import ( 

48 AstromDiff, 

49 CoaddPlotFlagSelector, 

50 DownselectVector, 

51 ExtinctionCorrectedMagDiff, 

52 LoadVector, 

53 MagColumnNanoJansky, 

54 SnSelector, 

55 StarSelector, 

56 VectorSelector, 

57) 

58from ..analysisParts.baseFluxRatio import BasePsfApRatio 

59from ..analysisParts.baseSources import BaseSources 

60from ..analysisParts.genericPrep import CoaddPrep, VisitPrep 

61from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin 

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

63from ..interfaces import AnalysisPlot 

64 

65 

66class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin): 

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

68 

69 This is shared by size and ellipticity plots. 

70 """ 

71 

72 def setDefaults(self): 

73 super().setDefaults() 

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

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

76 

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

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

79 

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

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

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

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

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

85 

86 self.process.filterActions.xStars = DownselectVector( 

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

88 ) 

89 # downselect the psfFlux as well 

90 self.process.filterActions.psfFlux = DownselectVector( 

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

92 ) 

93 self.process.filterActions.psfFluxErr = DownselectVector( 

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

95 ) 

96 

97 self.process.filterActions.patch = DownselectVector( 

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

99 ) 

100 

101 self.process.calculateActions.stars = ScatterPlotStatsAction( 

102 vectorKey="yStars", 

103 ) 

104 # use the downselected psfFlux 

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

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

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

108 

109 self.produce = ScatterPlotWithTwoHists() 

110 

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

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

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

114 self.produce.addSummaryPlot = True 

115 

116 

117class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot): 

118 def setDefaults(self): 

119 super().setDefaults() 

120 self.process.filterActions.yStars = DownselectVector( 

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

122 ) 

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

124 

125 

126class E1DiffScatterPlot(BasePsfResidualScatterPlot): 

127 def setDefaults(self): 

128 super().setDefaults() 

129 self.process.filterActions.yStars = DownselectVector( 

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

131 ) 

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

133 

134 

135class E2DiffScatterPlot(BasePsfResidualScatterPlot): 

136 def setDefaults(self): 

137 super().setDefaults() 

138 self.process.filterActions.yStars = DownselectVector( 

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

140 ) 

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

142 

143 

144class WPerpPSFPlot(WPerpPSF, AnalysisPlot): 

145 def setDefaults(self): 

146 super().setDefaults() 

147 

148 self.produce = ColorColorFitPlot() 

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

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

151 self.produce.magLabel = "PSF Mag" 

152 self.produce.plotName = "wPerp_psfFlux" 

153 

154 

155class WPerpCModelPlot(WPerpCModel, AnalysisPlot): 

156 def setDefaults(self): 

157 super().setDefaults() 

158 

159 self.produce = ColorColorFitPlot() 

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

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

162 self.produce.magLabel = "CModel Mag" 

163 self.produce.plotName = "wPerp_cmodelFlux" 

164 

165 

166class XPerpPSFPlot(XPerpPSF, AnalysisPlot): 

167 def setDefaults(self): 

168 super().setDefaults() 

169 

170 self.produce = ColorColorFitPlot() 

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

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

173 self.produce.magLabel = "PSF Mag" 

174 self.produce.plotName = "xPerp_psfFlux" 

175 

176 

177class XPerpCModelPlot(XPerpCModel, AnalysisPlot): 

178 def setDefaults(self): 

179 super().setDefaults() 

180 

181 self.produce = ColorColorFitPlot() 

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

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

184 self.produce.magLabel = "CModel Mag" 

185 self.produce.plotName = "xPerp_cmodelFlux" 

186 

187 

188class YPerpPSFPlot(YPerpPSF, AnalysisPlot): 

189 def setDefaults(self): 

190 super().setDefaults() 

191 

192 self.produce = ColorColorFitPlot() 

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

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

195 self.produce.magLabel = "PSF Mag" 

196 self.produce.plotName = "yPerp_psfFlux" 

197 

198 

199class YPerpCModelPlot(YPerpCModel, AnalysisPlot): 

200 def setDefaults(self): 

201 super().setDefaults() 

202 

203 self.produce = ColorColorFitPlot() 

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

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

206 self.produce.magLabel = "CModel Mag" 

207 self.produce.plotName = "yPerp_cmodelFlux" 

208 

209 

210class Ap12PsfSkyPlot(AnalysisPlot): 

211 def setDefaults(self): 

212 super().setDefaults() 

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

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

215 # the plot is being made in. 

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

217 

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

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

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

221 

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

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

224 

225 # TODO: Can we make these defaults somewhere? 

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

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

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

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

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

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

232 

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

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

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

236 

237 self.produce = SkyPlot() 

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

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

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

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

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

243 self.produce.plotOutlines = False 

244 

245 

246class TargetRefCatDelta(AnalysisPlot): 

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

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

249 """ 

250 

251 parameterizedBand = Field[bool]( 

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

253 ) 

254 

255 def coaddContext(self) -> None: 

256 self.prep = CoaddPrep() 

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

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

259 self.process.filterActions.psfFlux = DownselectVector( 

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

261 ) 

262 self.process.filterActions.psfFluxErr = DownselectVector( 

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

264 ) 

265 

266 def visitContext(self) -> None: 

267 self.parameterizedBand = False 

268 self.prep = VisitPrep() 

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

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

271 self.process.filterActions.psfFlux = DownselectVector( 

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

273 ) 

274 self.process.filterActions.psfFluxErr = DownselectVector( 

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

276 ) 

277 

278 def setDefaults(self, coordinate): 

279 super().setDefaults() 

280 

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

282 coordStr = coordinate.lower() 

283 self.process.buildActions.astromDiff = AstromDiff( 

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

285 ) 

286 

287 self.process.filterActions.xStars = DownselectVector( 

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

289 ) 

290 self.process.filterActions.yStars = DownselectVector( 

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

292 ) 

293 

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

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

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

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

298 

299 self.produce = ScatterPlotWithTwoHists() 

300 

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

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

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

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

305 

306 

307class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta): 

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

309 and a reference catalog 

310 """ 

311 

312 def setDefaults(self): 

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

314 

315 

316class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta): 

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

318 and a reference catalog 

319 """ 

320 

321 def setDefaults(self): 

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

323 

324 

325class FluxRatioPlot(AnalysisPlot, BasePsfApRatio): 

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

327 

328 def setDefaults(self): 

329 super().setDefaults() 

330 

331 self.produce = HistPlot() 

332 

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

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

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

336 

337 

338class SourcesPlot(AnalysisPlot, BaseSources): 

339 """Plot a histogram of the associated and unassociated sources.""" 

340 

341 def setDefaults(self, **kwargs): 

342 super().setDefaults() 

343 

344 self.process.calculateActions.associatedCount = CountAction(vectorKey="associatedVector") 

345 self.process.calculateActions.unassociatedCount = CountAction(vectorKey="unassociatedVector") 

346 

347 self.produce = BarPlot() 

348 self.produce.panels["panel_source"] = BarPanel() 

349 self.produce.panels["panel_source"].label = "N Assoc and Unassoc Sources" 

350 self.produce.panels["panel_source"].bars = dict( 

351 associatedVector="Associated Sources", 

352 unassociatedVector="Unassociated Sources", 

353 )