diff --git a/doc/api/next_api_changes/2018-11-18-AL.rst b/doc/api/next_api_changes/2018-11-18-AL.rst new file mode 100644 index 000000000000..43c66db4854e --- /dev/null +++ b/doc/api/next_api_changes/2018-11-18-AL.rst @@ -0,0 +1,10 @@ +Deprecations +```````````` + +- The ``LogTransformBase``, ``Log10Transform``, ``Log2Transform``, + ``NaturalLogTransformLog``, ``InvertedLogTransformBase``, + ``InvertedLog10Transform``, ``InvertedLog2Transform``, and + ``InvertedNaturalLogTransform`` classes (all defined in + :mod:`matplotlib.scales`) are deprecated. As a replacement, use the general + `LogTransform` and `InvertedLogTransform` classes, whose constructors take a + *base* argument. diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 93bb610fb4ef..2e72053726eb 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -195,6 +195,7 @@ def set_default_locators_and_formatters(self, axis): axis.set_minor_locator(NullLocator()) +@cbook.deprecated("3.1", alternative="LogTransform") class LogTransformBase(Transform): input_dims = 1 output_dims = 1 @@ -206,28 +207,14 @@ def __init__(self, nonpos='clip'): self._clip = {"clip": True, "mask": False}[nonpos] def transform_non_affine(self, a): - # Ignore invalid values due to nans being passed to the transform - with np.errstate(divide="ignore", invalid="ignore"): - out = np.log(a) - out /= np.log(self.base) - if self._clip: - # SVG spec says that conforming viewers must support values up - # to 3.4e38 (C float); however experiments suggest that - # Inkscape (which uses cairo for rendering) runs into cairo's - # 24-bit limit (which is apparently shared by Agg). - # Ghostscript (used for pdf rendering appears to overflow even - # earlier, with the max value around 2 ** 15 for the tests to - # pass. On the other hand, in practice, we want to clip beyond - # np.log10(np.nextafter(0, 1)) ~ -323 - # so 1000 seems safe. - out[a <= 0] = -1000 - return out + return LogTransform.transform_non_affine(self, a) def __str__(self): return "{}({!r})".format( type(self).__name__, "clip" if self._clip else "mask") +@cbook.deprecated("3.1", alternative="InvertedLogTransform") class InvertedLogTransformBase(Transform): input_dims = 1 output_dims = 1 @@ -241,6 +228,7 @@ def __str__(self): return "{}()".format(type(self).__name__) +@cbook.deprecated("3.1", alternative="LogTransform") class Log10Transform(LogTransformBase): base = 10.0 @@ -248,6 +236,7 @@ def inverted(self): return InvertedLog10Transform() +@cbook.deprecated("3.1", alternative="InvertedLogTransform") class InvertedLog10Transform(InvertedLogTransformBase): base = 10.0 @@ -255,6 +244,7 @@ def inverted(self): return Log10Transform() +@cbook.deprecated("3.1", alternative="LogTransform") class Log2Transform(LogTransformBase): base = 2.0 @@ -262,6 +252,7 @@ def inverted(self): return InvertedLog2Transform() +@cbook.deprecated("3.1", alternative="InvertedLogTransform") class InvertedLog2Transform(InvertedLogTransformBase): base = 2.0 @@ -269,6 +260,7 @@ def inverted(self): return Log2Transform() +@cbook.deprecated("3.1", alternative="LogTransform") class NaturalLogTransform(LogTransformBase): base = np.e @@ -276,6 +268,7 @@ def inverted(self): return InvertedNaturalLogTransform() +@cbook.deprecated("3.1", alternative="InvertedLogTransform") class InvertedNaturalLogTransform(InvertedLogTransformBase): base = np.e @@ -283,37 +276,70 @@ def inverted(self): return NaturalLogTransform() -class LogTransform(LogTransformBase): +class LogTransform(Transform): + input_dims = 1 + output_dims = 1 + is_separable = True + has_inverse = True + def __init__(self, base, nonpos='clip'): - LogTransformBase.__init__(self, nonpos) + Transform.__init__(self) self.base = base + self._clip = {"clip": True, "mask": False}[nonpos] + + def __str__(self): + return "{}(base={}, nonpos={!r})".format( + type(self).__name__, self.base, "clip" if self._clip else "mask") + + def transform_non_affine(self, a): + # Ignore invalid values due to nans being passed to the transform. + with np.errstate(divide="ignore", invalid="ignore"): + log = {np.e: np.log, 2: np.log2, 10: np.log10}.get(self.base) + if log: # If possible, do everything in a single call to Numpy. + out = log(a) + else: + out = np.log(a) + out /= np.log(self.base) + if self._clip: + # SVG spec says that conforming viewers must support values up + # to 3.4e38 (C float); however experiments suggest that + # Inkscape (which uses cairo for rendering) runs into cairo's + # 24-bit limit (which is apparently shared by Agg). + # Ghostscript (used for pdf rendering appears to overflow even + # earlier, with the max value around 2 ** 15 for the tests to + # pass. On the other hand, in practice, we want to clip beyond + # np.log10(np.nextafter(0, 1)) ~ -323 + # so 1000 seems safe. + out[a <= 0] = -1000 + return out def inverted(self): return InvertedLogTransform(self.base) class InvertedLogTransform(InvertedLogTransformBase): + input_dims = 1 + output_dims = 1 + is_separable = True + has_inverse = True + def __init__(self, base): - InvertedLogTransformBase.__init__(self) + Transform.__init__(self) self.base = base + def __str__(self): + return "{}(base={})".format(type(self).__name__, self.base) + + def transform_non_affine(self, a): + return ma.power(self.base, a) + def inverted(self): return LogTransform(self.base) class LogScale(ScaleBase): """ - A standard logarithmic scale. Care is taken so non-positive - values are not plotted. - - For computational efficiency (to push as much as possible to Numpy - C code in the common cases), this scale provides different - transforms depending on the base of the logarithm: - - - base 10 (:class:`Log10Transform`) - - base 2 (:class:`Log2Transform`) - - base e (:class:`NaturalLogTransform`) - - arbitrary base (:class:`LogTransform`) + A standard logarithmic scale. Care is taken to only plot positive values. """ name = 'log' @@ -365,18 +391,13 @@ def __init__(self, axis, **kwargs): if base <= 0 or base == 1: raise ValueError('The log base cannot be <= 0 or == 1') - if base == 10.0: - self._transform = self.Log10Transform(nonpos) - elif base == 2.0: - self._transform = self.Log2Transform(nonpos) - elif base == np.e: - self._transform = self.NaturalLogTransform(nonpos) - else: - self._transform = self.LogTransform(base, nonpos) - - self.base = base + self._transform = self.LogTransform(base, nonpos) self.subs = subs + @property + def base(self): + return self._transform.base + def set_default_locators_and_formatters(self, axis): """ Set the locators and formatters to specialized versions for @@ -436,10 +457,12 @@ def forward(values: array-like) -> array-like """ forward, inverse = functions - self.base = base self.subs = None - transform = FuncTransform(forward, inverse) + LogTransform(base) - self._transform = transform + self._transform = FuncTransform(forward, inverse) + LogTransform(base) + + @property + def base(self): + return self._transform._b.base # Base of the LogTransform. def get_transform(self): """ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index db9cb33ed26f..8142829756b6 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -5282,8 +5282,7 @@ def test_title_location_roundtrip(): @image_comparison(baseline_images=["loglog"], remove_text=True, - extensions=['png'], - tol={'aarch64': 0.02}.get(platform.machine(), 0.0)) + extensions=['png'], tol=0.02) def test_loglog(): fig, ax = plt.subplots() x = np.arange(1, 11) diff --git a/lib/matplotlib/tests/test_scale.py b/lib/matplotlib/tests/test_scale.py index 75a61c310c1d..7f4aa7557c3a 100644 --- a/lib/matplotlib/tests/test_scale.py +++ b/lib/matplotlib/tests/test_scale.py @@ -105,8 +105,7 @@ def test_logscale_transform_repr(): @image_comparison(baseline_images=['logscale_nonpos_values'], remove_text=True, - tol={'aarch64': 0.02}.get(platform.machine(), 0.0), - extensions=['png'], style='mpl20') + extensions=['png'], tol=0.02, style='mpl20') def test_logscale_nonpos_values(): np.random.seed(19680801) xs = np.random.normal(size=int(1e3)) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy