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

186 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-04 03:14 -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 "RhoStatisticsPlot", 

38) 

39 

40from lsst.pex.config import Field 

41 

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

43from ..actions.plot.colorColorFitPlot import ColorColorFitPlot 

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

45from ..actions.plot.rhoStatisticsPlot import RhoStatisticsPlotAction 

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

47from ..actions.plot.skyPlot import SkyPlot 

48from ..actions.scalar import CountAction 

49from ..actions.vector import ( 

50 AstromDiff, 

51 CoaddPlotFlagSelector, 

52 DownselectVector, 

53 ExtinctionCorrectedMagDiff, 

54 LoadVector, 

55 MagColumnNanoJansky, 

56 SnSelector, 

57 StarSelector, 

58 VectorSelector, 

59) 

60from ..analysisParts.baseFluxRatio import BasePsfApRatio 

61from ..analysisParts.baseSources import BaseSources 

62from ..analysisParts.genericPrep import CoaddPrep, VisitPrep 

63from ..analysisParts.rhoStatistics import RhoStatisticsMixin 

64from ..analysisParts.shapeSizeFractional import BasePsfResidualMixin 

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

66from ..interfaces import AnalysisPlot 

67 

68 

69class BasePsfResidualScatterPlot(AnalysisPlot, BasePsfResidualMixin): 

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

71 

72 This is shared by size and ellipticity plots. 

73 """ 

74 

75 def setDefaults(self): 

76 super().setDefaults() 

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

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

79 

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

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

82 

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

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

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

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

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

88 

89 self.process.filterActions.xStars = DownselectVector( 

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

91 ) 

92 # downselect the psfFlux as well 

93 self.process.filterActions.psfFlux = DownselectVector( 

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

95 ) 

96 self.process.filterActions.psfFluxErr = DownselectVector( 

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

98 ) 

99 

100 self.process.filterActions.patch = DownselectVector( 

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

102 ) 

103 

104 self.process.calculateActions.stars = ScatterPlotStatsAction( 

105 vectorKey="yStars", 

106 ) 

107 # use the downselected psfFlux 

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

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

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

111 

112 self.produce = ScatterPlotWithTwoHists() 

113 

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

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

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

117 self.produce.addSummaryPlot = True 

118 

119 

120class ShapeSizeFractionalDiffScatterPlot(BasePsfResidualScatterPlot): 

121 def setDefaults(self): 

122 super().setDefaults() 

123 self.process.filterActions.yStars = DownselectVector( 

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

125 ) 

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

127 

128 

129class E1DiffScatterPlot(BasePsfResidualScatterPlot): 

130 def setDefaults(self): 

131 super().setDefaults() 

132 self.process.filterActions.yStars = DownselectVector( 

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

134 ) 

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

136 

137 

138class E2DiffScatterPlot(BasePsfResidualScatterPlot): 

139 def setDefaults(self): 

140 super().setDefaults() 

141 self.process.filterActions.yStars = DownselectVector( 

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

143 ) 

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

145 

146 

147class RhoStatisticsPlot(AnalysisPlot, RhoStatisticsMixin): 

148 def setDefaults(self): 

149 super().setDefaults() 

150 self.produce = RhoStatisticsPlotAction() 

151 

152 

153class WPerpPSFPlot(WPerpPSF, AnalysisPlot): 

154 def setDefaults(self): 

155 super().setDefaults() 

156 

157 self.produce = ColorColorFitPlot() 

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

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

160 self.produce.magLabel = "PSF Mag" 

161 self.produce.plotName = "wPerp_psfFlux" 

162 

163 

164class WPerpCModelPlot(WPerpCModel, AnalysisPlot): 

165 def setDefaults(self): 

166 super().setDefaults() 

167 

168 self.produce = ColorColorFitPlot() 

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

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

171 self.produce.magLabel = "CModel Mag" 

172 self.produce.plotName = "wPerp_cmodelFlux" 

173 

174 

175class XPerpPSFPlot(XPerpPSF, AnalysisPlot): 

176 def setDefaults(self): 

177 super().setDefaults() 

178 

179 self.produce = ColorColorFitPlot() 

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

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

182 self.produce.magLabel = "PSF Mag" 

183 self.produce.plotName = "xPerp_psfFlux" 

184 

185 

186class XPerpCModelPlot(XPerpCModel, AnalysisPlot): 

187 def setDefaults(self): 

188 super().setDefaults() 

189 

190 self.produce = ColorColorFitPlot() 

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

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

193 self.produce.magLabel = "CModel Mag" 

194 self.produce.plotName = "xPerp_cmodelFlux" 

195 

196 

197class YPerpPSFPlot(YPerpPSF, AnalysisPlot): 

198 def setDefaults(self): 

199 super().setDefaults() 

200 

201 self.produce = ColorColorFitPlot() 

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

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

204 self.produce.magLabel = "PSF Mag" 

205 self.produce.plotName = "yPerp_psfFlux" 

206 

207 

208class YPerpCModelPlot(YPerpCModel, AnalysisPlot): 

209 def setDefaults(self): 

210 super().setDefaults() 

211 

212 self.produce = ColorColorFitPlot() 

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

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

215 self.produce.magLabel = "CModel Mag" 

216 self.produce.plotName = "yPerp_cmodelFlux" 

217 

218 

219class Ap12PsfSkyPlot(AnalysisPlot): 

220 def setDefaults(self): 

221 super().setDefaults() 

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

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

224 # the plot is being made in. 

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

226 

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

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

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

230 

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

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

233 

234 # TODO: Can we make these defaults somewhere? 

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

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

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

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

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

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

241 

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

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

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

245 

246 self.produce = SkyPlot() 

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

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

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

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

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

252 self.produce.plotOutlines = False 

253 

254 

255class TargetRefCatDelta(AnalysisPlot): 

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

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

258 """ 

259 

260 parameterizedBand = Field[bool]( 

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

262 ) 

263 

264 def coaddContext(self) -> None: 

265 self.prep = CoaddPrep() 

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

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

268 self.process.filterActions.psfFlux = DownselectVector( 

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

270 ) 

271 self.process.filterActions.psfFluxErr = DownselectVector( 

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

273 ) 

274 

275 def visitContext(self) -> None: 

276 self.parameterizedBand = False 

277 self.prep = VisitPrep() 

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

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

280 self.process.filterActions.psfFlux = DownselectVector( 

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

282 ) 

283 self.process.filterActions.psfFluxErr = DownselectVector( 

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

285 ) 

286 

287 def setDefaults(self, coordinate): 

288 super().setDefaults() 

289 

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

291 coordStr = coordinate.lower() 

292 self.process.buildActions.astromDiff = AstromDiff( 

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

294 ) 

295 

296 self.process.filterActions.xStars = DownselectVector( 

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

298 ) 

299 self.process.filterActions.yStars = DownselectVector( 

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

301 ) 

302 

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

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

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

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

307 

308 self.produce = ScatterPlotWithTwoHists() 

309 

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

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

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

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

314 

315 

316class TargetRefCatDeltaRAScatterPlot(TargetRefCatDelta): 

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

318 and a reference catalog 

319 """ 

320 

321 def setDefaults(self): 

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

323 

324 

325class TargetRefCatDeltaDecScatterPlot(TargetRefCatDelta): 

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

327 and a reference catalog 

328 """ 

329 

330 def setDefaults(self): 

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

332 

333 

334class FluxRatioPlot(AnalysisPlot, BasePsfApRatio): 

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

336 

337 def setDefaults(self): 

338 super().setDefaults() 

339 

340 self.produce = HistPlot() 

341 

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

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

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

345 

346 

347class SourcesPlot(AnalysisPlot, BaseSources): 

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

349 

350 def setDefaults(self, **kwargs): 

351 super().setDefaults() 

352 

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

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

355 

356 self.produce = BarPlot() 

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

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

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

360 associatedVector="Associated Sources", 

361 unassociatedVector="Unassociated Sources", 

362 )