1
- import numpy as np
2
- import matplotlib
3
- from matplotlib .transforms import Transform
1
+ import numpy
4
2
from matplotlib .scale import ScaleBase
5
3
from matplotlib .ticker import (
6
4
FixedLocator ,
7
5
NullLocator ,
8
- Formatter ,
9
6
NullFormatter ,
10
7
FuncFormatter ,
11
8
)
12
9
13
-
14
- def _mask_non_positives (a ):
15
- """
16
- Return a Numpy array where all values outside ]0, 1[ are
17
- replaced with NaNs. If all values are inside ]0, 1[, the original
18
- array is returned.
19
- """
20
- mask = (a <= 0.0 ) | (a >= 1.0 )
21
- if mask .any ():
22
- return np .where (mask , np .nan , a )
23
- return a
24
-
25
-
26
- def _clip_non_positives (a ):
27
- a = np .array (a , float )
28
- a [a <= 0.0 ] = 1e-300
29
- a [a >= 1.0 ] = 1 - 1e-300
30
- return a
10
+ from .transforms import ProbTransform
11
+ from .formatters import PctFormatter , ProbFormatter
31
12
32
13
33
14
class _minimal_norm (object ):
34
- _A = - (8 * (np .pi - 3.0 ) / (3.0 * np .pi * (np .pi - 4.0 )))
15
+ _A = - (8 * (numpy .pi - 3.0 ) / (3.0 * numpy .pi * (numpy .pi - 4.0 )))
35
16
36
17
@classmethod
37
18
def _approx_erf (cls , x ):
@@ -41,8 +22,8 @@ def _approx_erf(cls, x):
41
22
42
23
"""
43
24
44
- guts = - x ** 2 * (4.0 / np .pi + cls ._A * x ** 2 ) / (1.0 + cls ._A * x ** 2 )
45
- return np .sign (x ) * np .sqrt (1.0 - np .exp (guts ))
25
+ guts = - x ** 2 * (4.0 / numpy .pi + cls ._A * x ** 2 ) / (1.0 + cls ._A * x ** 2 )
26
+ return numpy .sign (x ) * numpy .sqrt (1.0 - numpy .exp (guts ))
46
27
47
28
@classmethod
48
29
def _approx_inv_erf (cls , z ):
@@ -52,9 +33,9 @@ def _approx_inv_erf(cls, z):
52
33
53
34
"""
54
35
55
- _b = (2 / np .pi / cls ._A ) + (0.5 * np .log (1 - z ** 2 ))
56
- _c = np .log (1 - z ** 2 ) / cls ._A
57
- return np .sign (z ) * np .sqrt (np .sqrt (_b ** 2 - _c ) - _b )
36
+ _b = (2 / numpy .pi / cls ._A ) + (0.5 * numpy .log (1 - z ** 2 ))
37
+ _c = numpy .log (1 - z ** 2 ) / cls ._A
38
+ return numpy .sign (z ) * numpy .sqrt (numpy .sqrt (_b ** 2 - _c ) - _b )
58
39
59
40
@classmethod
60
41
def ppf (cls , q ):
@@ -63,7 +44,7 @@ def ppf(cls, q):
63
44
Wikipedia: https://goo.gl/Rtxjme
64
45
65
46
"""
66
- return np .sqrt (2 ) * cls ._approx_inv_erf (2 * q - 1 )
47
+ return numpy .sqrt (2 ) * cls ._approx_inv_erf (2 * q - 1 )
67
48
68
49
@classmethod
69
50
def cdf (cls , x ):
@@ -72,151 +53,7 @@ def cdf(cls, x):
72
53
Wikipedia: https://goo.gl/ciUNLx
73
54
74
55
"""
75
- return 0.5 * (1 + cls ._approx_erf (x / np .sqrt (2 )))
76
-
77
-
78
- class _FormatterMixin (Formatter ):
79
- @classmethod
80
- def _sig_figs (cls , x , n , expthresh = 5 , forceint = False ):
81
- """ Formats a number with the correct number of sig figs.
82
-
83
- Parameters
84
- ----------
85
- x : int or float
86
- The number you want to format.
87
- n : int
88
- The number of significan figures it should have.
89
- expthresh : int, optional (default = 5)
90
- The absolute value of the order of magnitude at which numbers
91
- are formatted in exponential notation.
92
- forceint : bool, optional (default is False)
93
- If true, simply returns int(x)
94
-
95
- Returns
96
- -------
97
- formatted : str
98
- The formatted number as a string
99
-
100
- Examples
101
- --------
102
- >>> print(_sig_figs(1247.15, 3))
103
- 1250
104
- >>> print(_sig_figs(1247.15, 7))
105
- 1247.150
106
-
107
- """
108
-
109
- # return a string value unaltered
110
- if isinstance (x , str ) or x == 0.0 :
111
- out = str (x )
112
-
113
- # check on the number provided
114
- elif x is not None and not np .isinf (x ) and not np .isnan (x ):
115
-
116
- # check on the _sig_figs
117
- if n < 1 :
118
- raise ValueError ("number of sig figs (n) must be greater than zero" )
119
-
120
- elif forceint :
121
- out = '{:,.0f}' .format (x )
122
-
123
- # logic to do all of the rounding
124
- else :
125
- order = np .floor (np .log10 (np .abs (x )))
126
-
127
- if (- 1.0 * expthresh <= order <= expthresh ):
128
- decimal_places = int (n - 1 - order )
129
-
130
- if decimal_places <= 0 :
131
- out = '{0:,.0f}' .format (round (x , decimal_places ))
132
-
133
- else :
134
- fmt = '{0:,.%df}' % decimal_places
135
- out = fmt .format (x )
136
-
137
- else :
138
- decimal_places = n - 1
139
- fmt = '{0:.%de}' % decimal_places
140
- out = fmt .format (x )
141
-
142
- # with NAs and INFs, just return 'NA'
143
- else :
144
- out = 'NA'
145
-
146
- return out
147
-
148
- def __call__ (self , x , pos = None ):
149
- if x < (10 / self .factor ):
150
- out = self ._sig_figs (x , 1 )
151
- elif x <= (99 / self .factor ):
152
- out = self ._sig_figs (x , 2 )
153
- else :
154
- order = np .ceil (np .round (np .abs (np .log10 (self .top - x )), 6 ))
155
- out = self ._sig_figs (x , order + self .offset )
156
-
157
- return '{}' .format (out )
158
-
159
-
160
- class PctFormatter (_FormatterMixin ):
161
- factor = 1.0
162
- offset = 2
163
- top = 100
164
-
165
-
166
- class ProbFormatter (_FormatterMixin ):
167
- factor = 100.0
168
- offset = 0
169
- top = 1
170
-
171
-
172
- class _ProbTransformMixin (Transform ):
173
- input_dims = 1
174
- output_dims = 1
175
- is_separable = True
176
- has_inverse = True
177
-
178
- def __init__ (self , dist , as_pct = True , nonpos = 'mask' ):
179
- Transform .__init__ (self )
180
- self .dist = dist
181
- if as_pct :
182
- self .factor = 100.0
183
- else :
184
- self .factor = 1.0
185
-
186
- if nonpos == 'mask' :
187
- self ._handle_nonpos = _mask_non_positives
188
- elif nonpos == 'clip' :
189
- self ._handle_nonpos = _clip_non_positives
190
- else :
191
- raise ValueError ("`nonpos` muse be either 'mask' or 'clip'" )
192
-
193
-
194
- class ProbTransform (_ProbTransformMixin ):
195
- def transform_non_affine (self , prob ):
196
- q = self .dist .ppf (prob / self .factor )
197
- return q
198
-
199
- def inverted (self ):
200
- return QuantileTransform (self .dist , as_pct = self .as_pct , nonpos = self .nonpos )
201
-
202
-
203
- class QuantileTransform (_ProbTransformMixin ):
204
- def transform_non_affine (self , q ):
205
- prob = self .dist .cdf (q ) * self .factor
206
- return prob
207
-
208
- class InvertedProbTransform (_ProbTransformMixin ):
209
- def transform_non_affine (self , a ):
210
- return self .dist .cdf (a ) * self .factor
211
-
212
-
213
- class InvertedProbTransform (_ProbTransformMixin ):
214
- def transform_non_affine (self , q ):
215
- prob = self .dist .cdf (q ) * self .factor
216
- return prob
217
-
218
- def inverted (self ):
219
- return ProbTransform (self .dist , as_pct = self .as_pct , nonpos = self .nonpos )
56
+ return 0.5 * (1 + cls ._approx_erf (x / numpy .sqrt (2 )))
220
57
221
58
222
59
class ProbScale (ScaleBase ):
@@ -237,7 +74,7 @@ class ProbScale(ScaleBase):
237
74
>>> from matplotlib import pyplot
238
75
>>> import probscale
239
76
>>> fig, ax = pyplot.subplots()
240
- >>> ax.set_scale ('prob')
77
+ >>> ax.set_xscale ('prob')
241
78
242
79
"""
243
80
@@ -259,21 +96,21 @@ def _get_probs(cls, nobs, as_pct):
259
96
else :
260
97
factor = 100.0
261
98
262
- order = int (np .floor (np .log10 (nobs )))
263
- base_probs = np .array ([10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 ])
99
+ order = int (numpy .floor (numpy .log10 (nobs )))
100
+ base_probs = numpy .array ([10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 ])
264
101
265
102
axis_probs = base_probs .copy ()
266
103
for n in range (order ):
267
104
if n <= 2 :
268
- lower_fringe = np .array ([1 , 2 , 5 ])
269
- upper_fringe = np .array ([5 , 8 , 9 ])
105
+ lower_fringe = numpy .array ([1 , 2 , 5 ])
106
+ upper_fringe = numpy .array ([5 , 8 , 9 ])
270
107
else :
271
- lower_fringe = np .array ([1 ])
272
- upper_fringe = np .array ([9 ])
108
+ lower_fringe = numpy .array ([1 ])
109
+ upper_fringe = numpy .array ([9 ])
273
110
274
111
new_lower = lower_fringe / 10 ** (n )
275
112
new_upper = upper_fringe / 10 ** (n ) + axis_probs .max ()
276
- axis_probs = np .hstack ([new_lower , axis_probs , new_upper ])
113
+ axis_probs = numpy .hstack ([new_lower , axis_probs , new_upper ])
277
114
locs = axis_probs / factor
278
115
return locs
279
116
0 commit comments