@@ -87,6 +87,10 @@ def _mask_non_positives(a):
8787 return ma .MaskedArray (a , mask = mask )
8888 return a
8989
90+ def _clip_non_positives (a ):
91+ a [a <= 0.0 ] = 1e-300
92+ return a
93+
9094class LogScale (ScaleBase ):
9195 """
9296 A standard logarithmic scale. Care is taken so non-positive
@@ -104,14 +108,24 @@ class LogScale(ScaleBase):
104108
105109 name = 'log'
106110
107- class Log10Transform (Transform ):
111+ class LogTransformBase (Transform ):
108112 input_dims = 1
109113 output_dims = 1
110114 is_separable = True
115+
116+ def __init__ (self , nonpos ):
117+ Transform .__init__ (self )
118+ if nonpos == 'mask' :
119+ self ._handle_nonpos = _mask_non_positives
120+ else :
121+ self ._handle_nonpos = _clip_non_positives
122+
123+
124+ class Log10Transform (LogTransformBase ):
111125 base = 10.0
112126
113127 def transform (self , a ):
114- a = _mask_non_positives (a * 10.0 )
128+ a = self . _handle_nonpos (a * 10.0 )
115129 if isinstance (a , MaskedArray ):
116130 return ma .log10 (a )
117131 return np .log10 (a )
@@ -131,14 +145,11 @@ def transform(self, a):
131145 def inverted (self ):
132146 return LogScale .Log10Transform ()
133147
134- class Log2Transform (Transform ):
135- input_dims = 1
136- output_dims = 1
137- is_separable = True
148+ class Log2Transform (LogTransformBase ):
138149 base = 2.0
139150
140151 def transform (self , a ):
141- a = _mask_non_positives (a * 2.0 )
152+ a = self . _handle_nonpos (a * 2.0 )
142153 if isinstance (a , MaskedArray ):
143154 return ma .log (a ) / np .log (2 )
144155 return np .log2 (a )
@@ -158,14 +169,11 @@ def transform(self, a):
158169 def inverted (self ):
159170 return LogScale .Log2Transform ()
160171
161- class NaturalLogTransform (Transform ):
162- input_dims = 1
163- output_dims = 1
164- is_separable = True
172+ class NaturalLogTransform (LogTransformBase ):
165173 base = np .e
166174
167175 def transform (self , a ):
168- a = _mask_non_positives (a * np .e )
176+ a = self . _handle_nonpos (a * np .e )
169177 if isinstance (a , MaskedArray ):
170178 return ma .log (a )
171179 return np .log (a )
@@ -190,12 +198,16 @@ class LogTransform(Transform):
190198 output_dims = 1
191199 is_separable = True
192200
193- def __init__ (self , base ):
201+ def __init__ (self , base , nonpos ):
194202 Transform .__init__ (self )
195203 self .base = base
204+ if nonpos == 'mask' :
205+ self ._handle_nonpos = _mask_non_positives
206+ else :
207+ self ._handle_nonpos = _clip_non_positives
196208
197209 def transform (self , a ):
198- a = _mask_non_positives (a * self .base )
210+ a = self . _handle_nonpos (a * self .base )
199211 if isinstance (a , MaskedArray ):
200212 return ma .log (a ) / np .log (self .base )
201213 return np .log (a ) / np .log (self .base )
@@ -224,6 +236,10 @@ def __init__(self, axis, **kwargs):
224236 *basex*/*basey*:
225237 The base of the logarithm
226238
239+ *nonposx*/*nonposy*: ['mask' | 'clip' ]
240+ non-positive values in *x* or *y* can be masked as
241+ invalid, or clipped to a very small positive number
242+
227243 *subsx*/*subsy*:
228244 Where to place the subticks between each major tick.
229245 Should be a sequence of integers. For example, in a log10
@@ -235,18 +251,23 @@ def __init__(self, axis, **kwargs):
235251 if axis .axis_name == 'x' :
236252 base = kwargs .pop ('basex' , 10.0 )
237253 subs = kwargs .pop ('subsx' , None )
254+ nonpos = kwargs .pop ('nonposx' , 'mask' )
238255 else :
239256 base = kwargs .pop ('basey' , 10.0 )
240257 subs = kwargs .pop ('subsy' , None )
258+ nonpos = kwargs .pop ('nonposy' , 'mask' )
259+
260+ if nonpos not in ['mask' , 'clip' ]:
261+ raise ValueError ("nonposx, nonposy kwarg must be 'mask' or 'clip'" )
241262
242263 if base == 10.0 :
243- self ._transform = self .Log10Transform ()
264+ self ._transform = self .Log10Transform (nonpos )
244265 elif base == 2.0 :
245- self ._transform = self .Log2Transform ()
266+ self ._transform = self .Log2Transform (nonpos )
246267 elif base == np .e :
247- self ._transform = self .NaturalLogTransform ()
268+ self ._transform = self .NaturalLogTransform (nonpos )
248269 else :
249- self ._transform = self .LogTransform (base )
270+ self ._transform = self .LogTransform (base , nonpos )
250271
251272 self .base = base
252273 self .subs = subs
0 commit comments