Coverage for python / lsst / analysis / tools / actions / plot / calculateRange.py: 62%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-22 09:32 +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__ = ( 

25 "MinMax", 

26 "Med2Mad", 

27 "Asinh", 

28 "Perc", 

29 "Linear", 

30) 

31 

32from typing import cast 

33 

34import numpy as np 

35from astropy.visualization import ( 

36 AsinhStretch, 

37 LinearStretch, 

38 PercentileInterval, 

39) 

40 

41from lsst.pex.config import Field 

42 

43from ...interfaces import Tensor, TensorAction, Vector, VectorAction 

44from ...math import nanMax, nanMedian, nanMin, nanSigmaMad 

45 

46 

47class MinMax(VectorAction): 

48 """Return the maximum and minimum values of an input vector to use as the 

49 minimum and maximum values of a colorbar range. 

50 

51 Parameters 

52 ---------- 

53 data : `Vector` 

54 A vector containing the data whose minimum and maximum are to be 

55 returned. 

56 

57 Returns 

58 ------- 

59 A two-element vector containing the minimum and maximum values of `data`. 

60 """ 

61 

62 def __call__(self, data: Vector, **kwargs) -> Vector: 

63 if len(data) == 0: 

64 return cast(Vector, [np.nan, np.nan]) 

65 else: 

66 return cast(Vector, [nanMin(data), nanMax(data)]) 

67 

68 

69class Med2Mad(VectorAction): 

70 """Return the median +/- 2*nansigmamad values of an input vector to use 

71 as the minimum and maximum values of a colorbar range. 

72 

73 Parameters 

74 ---------- 

75 data : `Vector` 

76 A vector containing the data whose median +/- 2*nansigmamad are to 

77 be returned. 

78 

79 Returns 

80 ------- 

81 A two-element vector containing the median +/- 2*nansigmamad values of 

82 `data`. 

83 """ 

84 

85 def __call__(self, data: Vector, **kwargs) -> Vector: 

86 med = nanMedian(data) 

87 mad = nanSigmaMad(data) 

88 cmin = med - 2 * mad 

89 cmax = med + 2 * mad 

90 return cast(Vector, [cmin, cmax]) 

91 

92 

93class Perc(VectorAction): 

94 """Return the minimum and maximum values of an input vector after 

95 excluding a fraction of values from either end of the distribution. 

96 

97 Parameters 

98 ---------- 

99 data : `Vector` 

100 A vector containing the data whose minimum and maximum are to be 

101 calculated following the exclusion of a fraction of extreme upper 

102 and lower values. 

103 

104 Returns 

105 ------- 

106 A two-element vector containing the minimum and maximum values of 

107 the input vector, following the exclusion of a fraction of extreme 

108 upper and lower values. 

109 """ 

110 

111 percentile = Field[float]( 

112 doc="The fraction of values to keep. The same fraction of values is " 

113 "eliminated from both ends of the distribution. Default: 97.", 

114 default=97.0, 

115 ) 

116 

117 def __call__(self, data, **kwargs): 

118 return PercentileInterval(self.percentile).get_limits(data) 

119 

120 

121class Asinh(VectorAction, TensorAction): 

122 """Transform the input vector/tensor using the asinh stretch. 

123 

124 Parameters 

125 ---------- 

126 data : `Vector` | `Tensor` 

127 A vector or a tensor containing the data to be transformed 

128 using the asinh stretch. 

129 

130 Returns 

131 ------- 

132 A vector or tensor of the same size as the input, transformed 

133 using the asinh stretch. 

134 """ 

135 

136 def __call__(self, data: Vector | Tensor, **kwargs) -> Vector | Tensor: 

137 return AsinhStretch()(data) 

138 

139 

140class Linear(VectorAction, TensorAction): 

141 """Transform the input vector/tensor using the linear stretch. 

142 

143 Parameters 

144 ---------- 

145 data : `Vector` 

146 A vector or a tensor containing the data to be transformed 

147 using the linear stretch. 

148 

149 Returns 

150 ------- 

151 A vector or tensor of the same size as the input, transformed 

152 using the linear stretch. 

153 """ 

154 

155 intercept = Field[float](doc="The offset of the linear stretch. Default: 0.", default=0.0) 

156 

157 slope = Field[float](doc="The slope of the linear stretch. Default: 1.", default=1.0) 

158 

159 def __call__(self, data: Vector | Tensor, **kwargs) -> Vector | Tensor: 

160 return LinearStretch(self.slope, self.intercept)(data)