Coverage for python/lsst/analysis/tools/actions/plot/rhoStatisticsPlot.py: 24%

58 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-05-01 12:36 +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/>. 

21 

22from __future__ import annotations 

23 

24__all__ = ("RhoStatisticsPlot",) 

25 

26from typing import Any, Iterable, Mapping 

27 

28import numpy as np 

29from lsst.pex.config import ConfigDictField 

30from matplotlib.figure import Figure 

31 

32from ...interfaces import KeyedData, KeyedDataSchema, PlotAction, Vector 

33from .plotUtils import addPlotInfo 

34from .xyPlot import XYPlot 

35 

36 

37class RhoStatisticsPlot(PlotAction): 

38 """Make multiple plots of rho statistics. 

39 

40 Rho statistics capture the spatial correlation amongst various PSF size and 

41 shape residual quantities. For exact definitions, see 

42 :ref:`here <rho_definitions>`. 

43 """ 

44 

45 rhoPlots = ConfigDictField[str, XYPlot]( 

46 doc="A configurable dict describing the rho statistics to plot.", 

47 default={}, 

48 ) 

49 

50 def setDefaults(self) -> None: 

51 super().setDefaults() 

52 self.rhoPlots = {rhoName: XYPlot() for rhoName in ("rho3alt", "rho1", "rho2", "rho3", "rho4", "rho5")} 

53 

54 yLabels = { 

55 "rho3alt": r"$\rho'_{3}(\theta) = \langle \frac{\delta T}{T}, \frac{\delta T}{T}\rangle$", 

56 "rho1": r"$\rho_{1}(\theta) = \langle \delta e, \delta e \rangle$", 

57 "rho2": r"$\rho_{2}(\theta) = \langle e, \delta e \rangle$", 

58 "rho3": r"$\rho_{3}(\theta) = \langle e\frac{\delta T}{T} , e\frac{\delta T}{T} \rangle$", 

59 "rho4": r"$\rho_{4}(\theta) = \langle \delta e, e\frac{\delta T}{T} \rangle$", 

60 "rho5": r"$\rho_{5}(\theta) = \langle e, e\frac{\delta T}{T} \rangle$", 

61 } 

62 

63 for rhoId, rhoPlot in self.rhoPlots.items(): 

64 rhoPlot.xAxisLabel = "Separation [arcmin]" 

65 rhoPlot.yAxisLabel = yLabels[rhoId] 

66 rhoPlot.xScale = "log" 

67 rhoPlot.yScale = "symlog" 

68 rhoPlot.yLinThresh = 1e-6 

69 rhoPlot.yLine = 0.0 

70 

71 self.rhoPlots["rho3alt"].yScale = "linear" # type: ignore 

72 

73 def getInputSchema(self) -> KeyedDataSchema: 

74 # Docstring inherited 

75 base: list[tuple[str, type[Vector]]] = [] 

76 base.append(("coord_ra", Vector)) 

77 base.append(("coord_dec", Vector)) 

78 base.append(("{{band}}_ixx", Vector)) 

79 base.append(("{{band}}_iyy", Vector)) 

80 base.append(("{{band}}_ixy", Vector)) 

81 base.append(("{{band}}_ixxPSF", Vector)) 

82 base.append(("{{band}}_iyyPSF", Vector)) 

83 base.append(("{{band}}_ixyPSF", Vector)) 

84 return base 

85 

86 def getOutputNames(self) -> Iterable[str]: 

87 # Docstring inherited 

88 for key in self.rhoPlots.keys(): 

89 yield key 

90 

91 def __call__(self, data: KeyedData, **kwargs) -> Mapping[str, Figure]: 

92 self._validateInput(data) 

93 return self.makePlot(data, **kwargs) 

94 

95 def _validateInput(self, data: KeyedData) -> None: 

96 required = set(self.rhoPlots.keys()) 

97 if not required.issubset(data.keys()): 

98 raise ValueError(f"Input data must contain {', '.join(self.rhoPlots.keys())}") 

99 

100 def makePlot( 

101 self, data: KeyedData, plotInfo: Mapping[str, str] | None = None, **kwargs: Any 

102 ) -> Mapping[str, Figure]: 

103 r"""Make the plot(s). 

104 

105 Parameters 

106 ---------- 

107 data : `~pandas.core.frame.DataFrame` 

108 The catalog containing various rho statistics. 

109 plotInfo : `dict`, optional 

110 A dictionary of information about the data being plotted with keys: 

111 ``"run"`` 

112 The output run for the plots (`str`). 

113 ``"skymap"`` 

114 The type of skymap used for the data (`str`). 

115 ``"filter"`` 

116 The filter used for this data (`str`). 

117 ``"tract"`` 

118 The tract that the data comes from (`str`). 

119 **kwargs 

120 Additional keyword arguments to pass to the plot 

121 

122 Returns 

123 ------- 

124 fig_dict : `dict` [`~matplotlib.figure.Figure`] 

125 The resulting figures. 

126 The figure corresponding :math:`\rho_1(\theta)` can be accessed 

127 with the key `rho1` and similarly for the other rho statistics. 

128 :math:`\rho_3'` is accessed with the key `rho3alt`. 

129 

130 Examples 

131 -------- 

132 An example rho statistics plot may be seen below: 

133 

134 .. image:: /_static/analysis_tools/rhoPlotExample.png 

135 

136 For further details on how to generate a plot, please refer to the 

137 :ref:`getting started guide<analysis-tools-getting-started>`. 

138 """ 

139 fig_dict: dict[str, Figure] = {} 

140 for rho_name in self.rhoPlots.keys(): 

141 rho: XYPlot = self.rhoPlots[rho_name] 

142 subdata = { 

143 "x": data[rho_name].meanr, # type: ignore 

144 "xerr": None, 

145 } 

146 if rho_name == "rho3alt": 

147 subdata["y"] = data[rho_name].xi # type: ignore 

148 subdata["yerr"] = np.sqrt(data[rho_name].varxi) 

149 else: 

150 subdata["y"] = data[rho_name].xip # type: ignore 

151 subdata["yerr"] = np.sqrt(data[rho_name].varxip) # type: ignore 

152 fig = rho(subdata, **kwargs) 

153 if plotInfo is not None: 

154 fig_dict[rho_name] = addPlotInfo(fig, plotInfo) 

155 

156 return fig_dict