Coverage for python/lsst/pipe/tasks/dataFrameActions/_actions.py: 57%

87 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-05 03:50 -0800

1from __future__ import annotations 

2 

3__all__ = ("SingleColumnAction", "MultiColumnAction", "CoordColumn", "MagColumnDN", "SumColumns", "AddColumn", 

4 "DivideColumns", "SubtractColumns", "MultiplyColumns", "FractionalDifferenceColumns", 

5 "MagColumnNanoJansky", "DiffOfDividedColumns", "PercentDiffOfDividedColumns",) 

6 

7from typing import Iterable 

8 

9import numpy as np 

10import pandas as pd 

11from astropy import units 

12 

13from ..configurableActions import ConfigurableActionStructField, ConfigurableActionField 

14from ._baseDataFrameActions import DataFrameAction 

15from ._evalColumnExpression import makeColumnExpressionAction 

16 

17from lsst.pex.config import Field 

18 

19 

20class SingleColumnAction(DataFrameAction): 

21 column = Field(doc="Column to load for this action", dtype=str, optional=False) 

22 

23 @property 

24 def columns(self) -> Iterable[str]: 

25 return (self.column, ) 

26 

27 def __call__(self, df, **kwargs): 

28 return df[self.column] 

29 

30 

31class MultiColumnAction(DataFrameAction): 

32 actions = ConfigurableActionStructField(doc="Configurable actions to use in a joint action") 

33 

34 @property 

35 def columns(self) -> Iterable[str]: 

36 yield from (column for action in self.actions for column in action.columns) 

37 

38 

39class CoordColumn(SingleColumnAction): 

40 inRadians = Field(doc="Return the column in radians if true", default=True, dtype=bool) 

41 

42 def __call__(self, df): 

43 col = super().__call__(df) 

44 return col * 180 / np.pi if self.inRadians else col 

45 

46 

47class MagColumnDN(SingleColumnAction): 

48 coadd_zeropoint = Field(doc="Magnitude zero point", dtype=float, default=27) 

49 

50 def __call__(self, df: pd.DataFrame, **kwargs): 

51 if not (fluxMag0 := kwargs.get('fluxMag0')): 

52 fluxMag0 = 1/np.power(10, -0.4*self.coadd_zeropoint) 

53 

54 with np.warnings.catch_warnings(): 

55 np.warnings.filterwarnings('ignore', r'invalid value encountered') 

56 np.warnings.filterwarnings('ignore', r'divide by zero') 

57 return -2.5 * np.log10(df[self.column] / fluxMag0) 

58 

59 

60class MagColumnNanoJansky(SingleColumnAction): 

61 

62 def __call__(self, df: pd.DataFrame, **kwargs): 

63 

64 with np.warnings.catch_warnings(): 

65 np.warnings.filterwarnings('ignore', r'invalid value encountered') 

66 np.warnings.filterwarnings('ignore', r'divide by zero') 

67 return -2.5 * np.log10((df[self.column] * 1e-9) / 3631.0) 

68 

69 

70class NanoJansky(SingleColumnAction): 

71 ab_flux_scale = Field(doc="Scaling of ab flux", dtype=float, default=(0*units.ABmag).to_value(units.nJy)) 

72 coadd_zeropoint = Field(doc="Magnitude zero point", dtype=float, default=27) 

73 

74 def __call__(self, df, **kwargs): 

75 dataNumber = super().__call__(df, **kwargs) 

76 if not (fluxMag0 := kwargs.get('fluxMag0')): 

77 fluxMag0 = 1/np.power(10, -0.4*self.coadd_zeropoint) 

78 return self.ab_flux_scale * dataNumber / fluxMag0 

79 

80 def setDefaults(self): 

81 super().setDefaults() 

82 self.cache = True # cache this action for future calls 

83 

84 

85class NanoJanskyErr(SingleColumnAction): 

86 flux_mag_err = Field(doc="Error in the magnitude zeropoint", dtype=float, default=0) 

87 flux_action = ConfigurableActionField(doc="Action to use if flux is not provided to the call method", 

88 default=NanoJansky, dtype=DataFrameAction) 

89 

90 @property 

91 def columns(self): 

92 yield from zip((self.column,), self.flux_action.columns) 

93 

94 def __call__(self, df, flux_column=None, flux_mag_err=None, **kwargs): 

95 if flux_column is None: 

96 flux_column = self.flux_action(df, **kwargs) 

97 if flux_mag_err is None: 

98 flux_mag_err = self.flux_mag_err 

99 

100 

101_docs = """This is a `DataFrameAction` that is designed to add two columns 

102together and return the result. 

103""" 

104SumColumns = makeColumnExpressionAction("SumColumns", "colA+colB", 

105 exprDefaults={"colA": SingleColumnAction, 

106 "colB": SingleColumnAction}, 

107 docstring=_docs) 

108 

109_docs = """This is a `MultiColumnAction` that is designed to subtract two columns 

110together and return the result. 

111""" 

112SubtractColumns = makeColumnExpressionAction("SubtractColumns", "colA-colB", 

113 exprDefaults={"colA": SingleColumnAction, 

114 "colB": SingleColumnAction}, 

115 docstring=_docs) 

116 

117_docs = """This is a `MultiColumnAction` that is designed to multiply two columns 

118together and return the result. 

119""" 

120MultiplyColumns = makeColumnExpressionAction("MultiplyColumns", "colA*colB", 

121 exprDefaults={"colA": SingleColumnAction, 

122 "colB": SingleColumnAction}, 

123 docstring=_docs) 

124 

125_docs = """This is a `MultiColumnAction` that is designed to divide two columns 

126together and return the result. 

127""" 

128DivideColumns = makeColumnExpressionAction("DivideColumns", "colA/colB", 

129 exprDefaults={"colA": SingleColumnAction, 

130 "colB": SingleColumnAction}, 

131 docstring=_docs) 

132 

133_docs = """This is a `MultiColumnAction` that is designed to divide two columns 

134together, subtract one and return the result. 

135""" 

136FractionalDifferenceColumns = makeColumnExpressionAction("FractionalDifferenceColumns", "(colA-colB)/colB", 

137 exprDefaults={"colA": SingleColumnAction, 

138 "colB": SingleColumnAction}, 

139 docstring=_docs) 

140 

141_docs = """This is a `MultiColumnAction` that is designed to subtract the division of two columns 

142from the division of two other columns and return the result (i.e. colA1/colB1 - colA2/colB2). 

143""" 

144DiffOfDividedColumns = makeColumnExpressionAction("DiffOfDividedColumns", "(colA1/colB1)-(colA2/colB2)", 

145 exprDefaults={"colA1": SingleColumnAction, 

146 "colB1": SingleColumnAction, 

147 "colA2": SingleColumnAction, 

148 "colB2": SingleColumnAction}, 

149 docstring=_docs) 

150_docs = """This is a `MultiColumnAction` that is designed to compute the percent difference 

151between the division of two columns and the division of two other columns and return the result 

152(i.e. 100*((colA1/colB1 - colA2/colB2)/(colA1/colB1))). 

153""" 

154PercentDiffOfDividedColumns = makeColumnExpressionAction("PercentDiffOfDividedColumns", 

155 "100*(((colA1/colB1)-(colA2/colB2))/(colA1/colB1))", 

156 exprDefaults={"colA1": SingleColumnAction, 

157 "colB1": SingleColumnAction, 

158 "colA2": SingleColumnAction, 

159 "colB2": SingleColumnAction}, 

160 docstring=_docs) 

161 

162 

163class AddColumn(DataFrameAction): 

164 aggregator = ConfigurableActionField(doc="This is an instance of a Dataframe action that will be used " 

165 "to create a new column", dtype=DataFrameAction) 

166 newColumn = Field(doc="Name of the new column to add", dtype=str) 

167 

168 @property 

169 def columns(self) -> Iterable[str]: 

170 yield from self.aggregator.columns 

171 

172 def __call__(self, df, **kwargs) -> pd.DataFrame: 

173 # do your calculation and and 

174 df[self.newColumn] = self.aggregator(df, kwargs) 

175 return df