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

57 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-05 04:11 -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/>. 

21 

22from __future__ import annotations 

23 

24from typing import TYPE_CHECKING, Any, Iterable, Mapping 

25 

26__all__ = ("RhoStatisticsPlotAction",) 

27 

28import numpy as np 

29from lsst.pex.config import ConfigDictField 

30 

31from ...interfaces import PlotAction, Vector 

32from .plotUtils import addPlotInfo 

33from .xyPlot import XYPlot 

34 

35if TYPE_CHECKING: 35 ↛ 36line 35 didn't jump to line 36, because the condition on line 35 was never true

36 from matplotlib.figure import Figure 

37 

38 from ...interfaces import KeyedData, KeyedDataSchema 

39 

40 

41class RhoStatisticsPlotAction(PlotAction): 

42 rhoPlots = ConfigDictField( 

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

44 keytype=str, 

45 itemtype=XYPlot, 

46 default={}, 

47 ) 

48 

49 def setDefaults(self) -> None: 

50 super().setDefaults() 

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

52 

53 yLabels = { 

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

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

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

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

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

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

60 } 

61 

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

63 rhoPlot.xAxisLabel = "Separation [arcmin]" 

64 rhoPlot.yAxisLabel = yLabels[rhoId] 

65 rhoPlot.xScale = "log" 

66 rhoPlot.yScale = "symlog" 

67 rhoPlot.yLinThresh = 1e-6 

68 

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

70 

71 def getInputSchema(self) -> KeyedDataSchema: 

72 # Docstring inherited 

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

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

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

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

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

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

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

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

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

82 return base 

83 

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

85 # Docstring inherited 

86 return ("rho3alt", "rho1", "rho2", "rho3", "rho4", "rho5") 

87 

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

89 self._validateInput(data) 

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

91 

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

93 if not set(("rho3alt", "rho1", "rho2", "rho3", "rho4", "rho5")).issubset(data.keys()): 

94 raise ValueError("Input data must contain rho3alt, rho1, rho2, rho3, rho4, and rho5.") 

95 

96 def makePlot( 

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

98 ) -> Mapping[str, Figure]: 

99 """Make the plot. 

100 

101 Parameters 

102 ---------- 

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

104 The catalog containing various rho statistics. 

105 plotInfo : `dict` 

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

107 ``"run"`` 

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

109 ``"skymap"`` 

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

111 ``"filter"`` 

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

113 ``"tract"`` 

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

115 **kwargs 

116 Additional keyword arguments to pass to the plot 

117 """ 

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

119 for rho_name in ("rho1", "rho2", "rho3", "rho4", "rho5"): 

120 rho: XYPlot = self.rhoPlots[rho_name] 

121 # The prefix below must match the prefix in the pipeline yaml. 

122 # TODO: This will be fixed in DM-37431. 

123 rhoPlot_name = f"rhoStatisticsPlot_{rho_name}" 

124 subdata = { 

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

126 "y": data[rho_name].xip, # type: ignore 

127 "yerr": np.sqrt(data[rho_name].varxip), # type: ignore 

128 "xerr": None, 

129 } 

130 fig = rho(subdata, **kwargs) 

131 if plotInfo is not None: 

132 fig_dict[rhoPlot_name] = addPlotInfo(fig, plotInfo) 

133 

134 # rho3alt is handled differently because its attributes differ. 

135 subdata = { 

136 "x": data["rho3alt"].meanr, # type: ignore 

137 "y": data["rho3alt"].xi, # type: ignore 

138 "yerr": np.sqrt(data["rho3alt"].varxi), # type: ignore 

139 "xerr": None, 

140 } 

141 fig = self.rhoPlots["rho3alt"](subdata, **kwargs) # type: ignore[misc] 

142 if plotInfo is not None: 

143 fig_dict["rhoStatisticsPlot_rho3alt"] = addPlotInfo(fig, plotInfo) 

144 

145 return fig_dict