@@ -195,6 +195,7 @@ def set_default_locators_and_formatters(self, axis):
195195 axis .set_minor_locator (NullLocator ())
196196
197197
198+ @cbook .deprecated ("3.1" , alternative = "LogTransform" )
198199class LogTransformBase (Transform ):
199200 input_dims = 1
200201 output_dims = 1
@@ -206,28 +207,14 @@ def __init__(self, nonpos='clip'):
206207 self ._clip = {"clip" : True , "mask" : False }[nonpos ]
207208
208209 def transform_non_affine (self , a ):
209- # Ignore invalid values due to nans being passed to the transform
210- with np .errstate (divide = "ignore" , invalid = "ignore" ):
211- out = np .log (a )
212-
8000
out /= np .log (self .base )
213- if self ._clip :
214- # SVG spec says that conforming viewers must support values up
215- # to 3.4e38 (C float); however experiments suggest that
216- # Inkscape (which uses cairo for rendering) runs into cairo's
217- # 24-bit limit (which is apparently shared by Agg).
218- # Ghostscript (used for pdf rendering appears to overflow even
219- # earlier, with the max value around 2 ** 15 for the tests to
220- # pass. On the other hand, in practice, we want to clip beyond
221- # np.log10(np.nextafter(0, 1)) ~ -323
222- # so 1000 seems safe.
223- out [a <= 0 ] = - 1000
224- return out
210+ return LogTransform .transform_non_affine (self , a )
225211
226212 def __str__ (self ):
227213 return "{}({!r})" .format (
228214 type (self ).__name__ , "clip" if self ._clip else "mask" )
229215
230216
217+ @cbook .deprecated ("3.1" , alternative = "InvertedLogTransform" )
231218class InvertedLogTransformBase (Transform ):
232219 input_dims = 1
233220 output_dims = 1
@@ -241,79 +228,118 @@ def __str__(self):
241228 return "{}()" .format (type (self ).__name__ )
242229
243230
231+ @cbook .deprecated ("3.1" , alternative = "LogTransform" )
244232class Log10Transform (LogTransformBase ):
245233 base = 10.0
246234
247235 def inverted (self ):
248236 return InvertedLog10Transform ()
249237
250238
239+ @cbook .deprecated ("3.1" , alternative = "InvertedLogTransform" )
251240class InvertedLog10Transform (InvertedLogTransformBase ):
252241 base = 10.0
253242
254243 def inverted (self ):
255244 return Log10Transform ()
256245
257246
247+ @cbook .deprecated ("3.1" , alternative = "LogTransform" )
258248class Log2Transform (LogTransformBase ):
259249 base = 2.0
260250
261251 def inverted (self ):
262252 return InvertedLog2Transform ()
263253
264254
255+ @cbook .deprecated ("3.1" , alternative = "InvertedLogTransform" )
265256class InvertedLog2Transform (InvertedLogTransformBase ):
266257 base = 2.0
267258
268259 def inverted (self ):
269260 return Log2Transform ()
270261
271262
263+ @cbook .deprecated ("3.1" , alternative = "LogTransform" )
272264class NaturalLogTransform (LogTransformBase ):
273265 base = np .e
274266
275267 def inverted (self ):
276268 return InvertedNaturalLogTransform ()
277269
278270
271+ @cbook .deprecated ("3.1" , alternative = "InvertedLogTransform" )
279272class InvertedNaturalLogTransform (InvertedLogTransformBase ):
280273 base = np .e
281274
282275 def inverted (self ):
283276 return NaturalLogTransform ()
284277
285278
286- class LogTransform (LogTransformBase ):
279+ class LogTransform (Transform ):
280+ input_dims = 1
281+ output_dims = 1
282+ is_separable = True
283+ has_inverse = True
284+
287285 def __init__ (self , base , nonpos = 'clip' ):
288- LogTransformBase .__init__ (self , nonpos )
286+ Transform .__init__ (self )
289287 self .base = base
288+ self ._clip = {"clip" : True , "mask" : False }[nonpos ]
289+
290+ def __str__ (self ):
291+ return "{}(base={}, nonpos={!r})" .format (
292+ type (self ).__name__ , self .base , "clip" if self ._clip else "mask" )
293+
294+ def transform_non_affine (self , a ):
295+ # Ignore invalid values due to nans being passed to the transform.
296+ with np .errstate (divide = "ignore" , invalid = "ignore" ):
297+ log = {np .e : np .log , 2 : np .log2 , 10 : np .log10 }.get (self .base )
298+ if log : # If possible, do everything in a single call to Numpy.
299+ out = log (a )
300+ else :
301+ out = np .log (a )
302+ out /= np .log (self .base )
303+ if self ._clip :
304+ # SVG spec says that conforming viewers must support values up
305+ # to 3.4e38 (C float); however experiments suggest that
306+ # Inkscape (which uses cairo for rendering) runs into cairo's
307+ # 24-bit limit (which is apparently shared by Agg).
308+ # Ghostscript (used for pdf rendering appears to overflow even
309+ # earlier, with the max value around 2 ** 15 for the tests to
310+ # pass. On the other hand, in practice, we want to clip beyond
311+ # np.log10(np.nextafter(0, 1)) ~ -323
312+ # so 1000 seems safe.
313+ out [a <= 0 ] = - 1000
314+ return out
290315
291316 def inverted (self ):
292317 return InvertedLogTransform (self .base )
293318
294319
295320class InvertedLogTransform (InvertedLogTransformBase ):
321+ input_dims = 1
322+ output_dims = 1
323+ is_separable = True
324+ has_inverse = True
325+
296326 def __init__ (self , base ):
297- InvertedLogTransformBase .__init__ (self )
327+ Transform .__init__ (self )
298328 self .base = base
299329
330+ def __str__ (self ):
331+ return "{}(base={})" .format (type (self ).__name__ , self .base )
332+
333+ def transform_non_affine (self , a ):
334+ return ma .power (self .base , a )
335+
300336 def inverted (self ):
301337 return LogTransform (self .base )
302338
303339
304340class LogScale (ScaleBase ):
305341 """
306- A standard logarithmic scale. Care is taken so non-positive
307- values are not plotted.
308-
309- For computational efficiency (to push as much as possible to Numpy
310- C code in the common cases), this scale provides different
311- transforms depending on the base of the logarithm:
312-
313- - base 10 (:class:`Log10Transform`)
314- - base 2 (:class:`Log2Transform`)
315- - base e (:class:`NaturalLogTransform`)
316- - arbitrary base (:class:`LogTransform`)
342+ A standard logarithmic scale. Care is taken to only plot positive values.
317343 """
318344 name = 'log'
319345
@@ -365,18 +391,13 @@ def __init__(self, axis, **kwargs):
365391 if base <= 0 or base == 1 :
366392 raise ValueError ('The log base cannot be <= 0 or == 1' )
367393
368- if base == 10.0 :
369- self ._transform = self .Log10Transform (nonpos )
370- elif base == 2.0 :
371- self ._transform = self .Log2Transform (nonpos )
372- elif base == np .e :
373- self ._transform = self .NaturalLogTransform (nonpos )
374- else :
375- self ._transform = self .LogTransform (base , nonpos )
376-
377- self .base = base
394+ self ._transform = self .LogTransform (base , nonpos )
378395 self .subs = subs
379396
397+ @property
398+ def base (self ):
399+ return self ._transform .base
400+
380401 def set_default_locators_and_formatters (self , axis ):
381402 """
382403 Set the locators and formatters to specialized versions for
@@ -436,10 +457,12 @@ def forward(values: array-like) -> array-like
436457
437458 """
438459 forward , inverse = functions
439- self .base = base
440460 self .subs = None
441- transform = FuncTransform (forward , inverse ) + LogTransform (base )
442- self ._transform = transform
461+ self ._transform = FuncTransform (forward , inverse ) + LogTransform (base )
462+
463+ @property
464+ def base (self ):
465+ return self ._transform ._b .base # Base of the LogTransform.
443466
444467 def get_transform (self ):
445468 """
0 commit comments