8000 Deprecate redundant log-scale transform classes. · matplotlib/matplotlib@d19fd81 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d19fd81

Browse files
committed
Deprecate redundant log-scale transform classes.
1 parent 684a1ea commit d19fd81

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+
8000 ``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
8000 10000
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)
0