Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8137b4c

Browse files
authored
Merge pull request #12832 from anntzer/fewer-log-transforms
Deprecate redundant log-scale transform classes.
2 parents 684a1ea + d19fd81 commit 8137b4c

File tree

4 files changed

+78
-47
lines changed

4 files changed

+78
-47
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Deprecations
2+
````````````
3+
4+
- The ``LogTransformBase``, ``Log10Transform``, ``Log2Transform``,
5+
``NaturalLogTransformLog``, ``InvertedLogTransformBase``,
6+
``InvertedLog10Transform``, ``InvertedLog2Transform``, and
7+
``InvertedNaturalLogTransform`` classes (all defined in
8+
:mod:`matplotlib.scales`) are deprecated. As a replacement, use the general
9+
`LogTransform` and `InvertedLogTransform` classes, whose constructors take a
10+
*base* argument.

lib/matplotlib/scale.py

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -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")
198199
class 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-
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")
231218
class 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")
244232
class Log10Transform(LogTransformBase):
245233
base = 10.0
246234

247235
def inverted(self):
248236
return InvertedLog10Transform()
249237

250238

239+
@cbook.deprecated("3.1", alternative="InvertedLogTransform")
251240
class InvertedLog10Transform(InvertedLogTransformBase):
252241
base = 10.0
253242

254243
def inverted(self):
255244
return Log10Transform()
256245

257246

247+
@cbook.deprecated("3.1", alternative="LogTransform")
258248
class Log2Transform(LogTransformBase):
259249
base = 2.0
260250

261251
def inverted(self):
262252
return InvertedLog2Transform()
263253

264254

255+
@cbook.deprecated("3.1", alternative="InvertedLogTransform")
265256
class InvertedLog2Transform(InvertedLogTransformBase):
266257
base = 2.0
267258

268259
def inverted(self):
269260
return Log2Transform()
270261

271262

263+
@cbook.deprecated("3.1", alternative="LogTransform")
272264
class NaturalLogTransform(LogTransformBase):
273265
base = np.e
274266

275267
def inverted(self):
276268
return InvertedNaturalLogTransform()
277269

278270

271+
@cbook.deprecated("3.1", alternative="InvertedLogTransform")
279272
class 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

295320
class 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

304340
class 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
"""

lib/matplotlib/tests/test_axes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5282,8 +5282,7 @@ def test_title_location_roundtrip():
52825282

52835283

52845284
@image_comparison(baseline_images=["loglog"], remove_text=True,
5285-
extensions=['png'],
5286-
tol={'aarch64': 0.02}.get(platform.machine(), 0.0))
5285+
extensions=['png'], tol=0.02)
52875286
def test_loglog():
52885287
fig, ax = plt.subplots()
52895288
x = np.arange(1, 11)

lib/matplotlib/tests/test_scale.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ def test_logscale_transform_repr():
105105

106106

107107
@image_comparison(baseline_images=['logscale_nonpos_values'], remove_text=True,
108-
tol={'aarch64': 0.02}.get(platform.machine(), 0.0),
109-
extensions=['png'], style='mpl20')
108+
extensions=['png'], tol=0.02, style='mpl20')
110109
def test_logscale_nonpos_values():
111110
np.random.seed(19680801)
112111
xs = np.random.normal(size=int(1e3))

0 commit comments

Comments
 (0)