Coverage for pesummary/utils/probability_dict.py: 93.5%

62 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-05-02 08:42 +0000

1# Licensed under an MIT style license -- see LICENSE.md 

2 

3from pesummary.utils.samples_dict import SamplesDict 

4from pesummary.utils.dict import Dict 

5from pesummary.utils.pdf import DiscretePDF, DiscretePDF2D 

6from pesummary.core.plots.latex_labels import latex_labels 

7from pesummary.gw.plots.latex_labels import GWlatex_labels 

8 

9__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"] 

10 

11latex_labels.update(GWlatex_labels) 

12 

13 

14class ProbabilityDict(Dict): 

15 """Class to store integers with discrete probabilities for multiple 

16 parameters. 

17 

18 Parameters 

19 ---------- 

20 args: dict 

21 dictionary containing the discrete probabilities for each parameter. 

22 Key should be the parameter name and value should be a 2d array of 

23 length 2. First element integers and second element probabilities 

24 corresponding to integers. See pesummary.utils.pdf.DiscretePDF for more 

25 details 

26 

27 Methods 

28 ------- 

29 rvs: 

30 randomly draw samples for each distribution in ProbabilityDict 

31 

32 Examples 

33 -------- 

34 >>> from pesummary.utils.probability_dict import ProbabilityDict 

35 >>> numbers = [1,2,3,4] 

36 >>> probabilities = [0.1, 0.2, 0.3, 0.4] 

37 >>> pdf = ProbabilityDict({"parameter": [numbers, probabilities]}) 

38 >>> print(type(pdf["parameter"])) 

39 <class 'pesummary.utils.pdf.DiscretePDF'> 

40 >>> print(pdf["parameter"].probs) 

41 [0.1, 0.2, 0.3, 0.4] 

42 """ 

43 def __init__(self, *args, logger_warn="warn", autoscale=False): 

44 super(ProbabilityDict, self).__init__( 

45 *args, value_class=DiscretePDF, logger_warn=logger_warn, 

46 make_dict_kwargs={"autoscale": autoscale}, latex_labels=latex_labels 

47 ) 

48 

49 @property 

50 def plotting_map(self): 

51 existing = super(ProbabilityDict, self).plotting_map 

52 modified = existing.copy() 

53 modified.update( 

54 { 

55 "marginalized_posterior": self._marginalized_posterior, 

56 "hist": self._marginalized_posterior, 

57 "pdf": self._analytic_pdf, 

58 } 

59 ) 

60 return modified 

61 

62 def rvs( 

63 self, size=None, parameters=None, interpolate=True, interp_kwargs={} 

64 ): 

65 """Randomly draw samples from each distribution in ProbabilityDict 

66 

67 Parameters 

68 ---------- 

69 size: int 

70 number of samples to draw 

71 parameters: list, optional 

72 list of parameters you wish to draw samples for. If not provided 

73 draw samples for all parameters in ProbabilityDict. Default None 

74 interpolate: Bool, optional 

75 if True, interpolate the discrete probabilities and then draw 

76 samples from the continous distribution. Default True 

77 interp_kwargs: dict, optional 

78 kwargs to pass to the DiscretePDF.interpolate() method 

79 """ 

80 if size is None: 

81 raise ValueError( 

82 "Please specify the number of samples you wish to draw from " 

83 "the interpolated distributions" 

84 ) 

85 if parameters is not None: 

86 if any(param not in self.parameters for param in parameters): 

87 raise ValueError( 

88 "Unable to draw samples because not all parameters have " 

89 "probabilities stored in ProbabilityDict. The list of " 

90 "available parameters are: {}".format( 

91 ", ".join(self.parameters) 

92 ) 

93 ) 

94 else: 

95 parameters = self.parameters 

96 

97 mydict = {} 

98 for param in parameters: 

99 if interpolate: 

100 mydict[param] = self[param].interpolate(**interp_kwargs).rvs( 

101 size=size 

102 ) 

103 else: 

104 mydict[param] = self[param].rvs(size=size) 

105 return SamplesDict(mydict) 

106 

107 def _marginalized_posterior( 

108 self, parameter, size=10**5, module="core", **kwargs 

109 ): 

110 """Draw samples from the probability distribution and histogram them 

111 via the `pesummary.core.plots.plot._1d_histogram_plot` or 

112 `pesummary.gw.plots.plot._1d_histogram_plot` 

113 

114 Parameters 

115 ---------- 

116 parameter: str 

117 name of the parameter you wish to plot 

118 size: int, optional 

119 number of samples to from the probability distribution to histogram 

120 module: str, optional 

121 module you wish to use for the plotting 

122 **kwargs: dict 

123 all additional kwargs are passed to the `_1d_histogram_plot` 

124 function 

125 """ 

126 samples = SamplesDict({parameter: self[parameter].rvs(size=size)}) 

127 return samples.plot(parameter, type="hist", module=module, **kwargs) 

128 

129 def _analytic_pdf(self, parameter, **kwargs): 

130 """Wrapper for the `pesummary.core.plots.plot._1d_analytic_plot 

131 function 

132 

133 Parameters 

134 ---------- 

135 parameter: str 

136 name of the parameter you wish to plot 

137 **kwargs: dict, optional 

138 all additional kwargs are passed ot the `_1d_analytic_plot` function 

139 """ 

140 from pesummary.core.plots.plot import _1d_analytic_plot 

141 

142 return _1d_analytic_plot( 

143 parameter, self[parameter].x, self[parameter].probs, 

144 self.latex_labels[parameter], **kwargs 

145 ) 

146 

147 

148class ProbabilityDict2D(Dict): 

149 """Class to store the 2D discrete probability distributions for multiple 

150 parameters 

151 

152 Parameters 

153 ---------- 

154 args: dict 

155 dictionary containing the discrete probabilities for 2 or more 

156 parameters. Key should be 2 parameter names joined with `_` and 

157 value should be an array of length 3. First element integers for 

158 x, second element integers for y and third element the 2D discrete 

159 probability distribution for xy. See 

160 pesummary.utils.pdf.DiscretePDF2D for more details 

161 

162 Methods 

163 ------- 

164 plot: 

165 generate a plot to display the stored probability density functions 

166 

167 Examples 

168 -------- 

169 >>> from pesummary.utils.probability_dict.ProbabilityDict2D 

170 >>> x = [-1., 0., 1.] 

171 >>> y = [-1., 0., 1.] 

172 >>> prob_xy = [ 

173 ... [1./9, 1./9, 1./9], 

174 ... [1./9, 1./9, 1./9], 

175 ... [1./9, 1./9, 1./9] 

176 ... ] 

177 >>> pdf = ProbabilityDict2D({"x_y": [x, y, prob_xy]}) 

178 >>> print(type(pdf["x_y"])) 

179 <class 'pesummary.utils.pdf.DiscretePDF2D'> 

180 """ 

181 def __init__(self, *args, logger_warn="warn", autoscale=False): 

182 super(ProbabilityDict2D, self).__init__( 

183 *args, value_class=DiscretePDF2D, logger_warn=logger_warn, 

184 make_dict_kwargs={"autoscale": autoscale}, latex_labels=latex_labels 

185 ) 

186 

187 @property 

188 def plotting_map(self): 

189 existing = super(ProbabilityDict2D, self).plotting_map 

190 modified = existing.copy() 

191 modified.update( 

192 { 

193 "2d_kde": self._2d_kde, 

194 "triangle": self._triangle, 

195 "reverse_triangle": self._reverse_triangle 

196 } 

197 ) 

198 return modified 

199 

200 def _2d_kde(self, parameter, **kwargs): 

201 """Generate a 2d contour plot showing the probability distribution for 

202 xy. 

203 

204 Parameters 

205 ---------- 

206 parameter: str 

207 the key you wish to plot 

208 """ 

209 from pesummary.core.plots.publication import analytic_twod_contour_plot 

210 

211 if "levels" in kwargs.keys(): 

212 levels = self[parameter].probs_xy.level_from_confidence( 

213 kwargs["levels"] 

214 ) 

215 kwargs["levels"] = levels 

216 return analytic_twod_contour_plot( 

217 self[parameter].x, self[parameter].y, self[parameter].probs, 

218 **kwargs 

219 ) 

220 

221 def _base_triangle(self, parameter, function, **kwargs): 

222 pdf = self[parameter].marginalize() 

223 if "levels" in kwargs.keys(): 

224 levels = pdf.probs_xy.level_from_confidence( 

225 kwargs["levels"] 

226 ) 

227 kwargs["levels"] = levels 

228 return function( 

229 pdf.x, pdf.y, pdf.probs_x.probs, pdf.probs_y.probs, 

230 pdf.probs_xy.probs, **kwargs 

231 ) 

232 

233 def _triangle(self, parameter, **kwargs): 

234 """Generate a triangle plot showing the probability distribution for 

235 x, y and xy. The probability distributions for x and y are found 

236 through marginalization 

237 

238 Parameters 

239 ---------- 

240 parameter: str 

241 the key you wish to plot 

242 """ 

243 from pesummary.core.plots.publication import analytic_triangle_plot 

244 

245 return self._base_triangle( 

246 parameter, analytic_triangle_plot, **kwargs 

247 ) 

248 

249 def _reverse_triangle(self, parameter, **kwargs): 

250 """Generate a reverse triangle plot showing the probability distribution 

251 for x, y and xy. The probability distributions for x and y are found 

252 through marginalization 

253 

254 Parameters 

255 ---------- 

256 parameter: str 

257 the key you wish to plot 

258 """ 

259 from pesummary.core.plots.publication import ( 

260 analytic_reverse_triangle_plot 

261 ) 

262 

263 return self._base_triangle( 

264 parameter, analytic_reverse_triangle_plot, **kwargs 

265 )