From 87bfae6b125c84b18b39ab52fa114deb170c672b Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:32:47 +0100 Subject: [PATCH] MNT: Registered 3rd party scales do not need an axis parameter anymore First step of #29349. --- lib/matplotlib/scale.py | 32 ++++++++++++++++++++---------- lib/matplotlib/tests/test_scale.py | 26 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index ccaaae6caf5d..d10c7a32f449 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -681,14 +681,19 @@ def limit_range_for_scale(self, vmin, vmax, minpos): _scale_mapping = { - 'linear': LinearScale, - 'log': LogScale, - 'symlog': SymmetricalLogScale, - 'asinh': AsinhScale, - 'logit': LogitScale, - 'function': FuncScale, - 'functionlog': FuncScaleLog, - } + # values temporarily changed from Scale to tuple + # (Scale, accepts_axis_parameter) so that we can handle + # both scales with and without the historic *axis* parameter + # as the first argument + # change back when the axis parameter is completely removed + 'linear': (LinearScale, True), + 'log': (LogScale, True), + 'symlog': (SymmetricalLogScale, True), + 'asinh': (AsinhScale, True), + 'logit': (LogitScale, True), + 'function': (FuncScale, True), + 'functionlog': (FuncScaleLog, True), +} def get_scale_names(): @@ -705,8 +710,11 @@ def scale_factory(scale, axis, **kwargs): scale : {%(names)s} axis : `~matplotlib.axis.Axis` """ - scale_cls = _api.check_getitem(_scale_mapping, scale=scale) - return scale_cls(axis, **kwargs) + scale_cls, has_axis_parameter = _api.check_getitem(_scale_mapping, scale=scale) + if has_axis_parameter: + return scale_cls(axis, **kwargs) + else: + return scale_cls(**kwargs) if scale_factory.__doc__: @@ -723,7 +731,9 @@ def register_scale(scale_class): scale_class : subclass of `ScaleBase` The scale to register. """ - _scale_mapping[scale_class.name] = scale_class + # Monkey-patch the signature information onto the scale so + has_axis_parameter = "axis" in inspect.signature(scale_class).parameters + _scale_mapping[scale_class.name] = (scale_class, has_axis_parameter) def _get_scale_docs(): diff --git a/lib/matplotlib/tests/test_scale.py b/lib/matplotlib/tests/test_scale.py index 727397367762..4ca57352ccb4 100644 --- a/lib/matplotlib/tests/test_scale.py +++ b/lib/matplotlib/tests/test_scale.py @@ -14,6 +14,8 @@ import io import pytest +from lib.matplotlib.transforms import IdentityTransform + @check_figures_equal() def test_log_scales(fig_test, fig_ref): @@ -293,3 +295,27 @@ def test_bad_scale(self): AsinhScale(axis=None, linear_width=-1) s0 = AsinhScale(axis=None, ) s1 = AsinhScale(axis=None, linear_width=3.0) + + +def test_custom_scale_without_axis(): + """ + Test that one can register and use custom scales that don't take an *axis* param. + """ + class CustomTransform(IdentityTransform): + pass + + class CustomScale(mscale.ScaleBase): + def __init__(self): + self._transform = CustomTransform() + + def get_transform(self): + return self._transform + + try: + mscale.register_scale("custom", CustomScale) + fig, ax = plt.subplots() + ax.set_xscale('custom') + assert isinstance(ax.xaxis.get_transform(), CustomTransform) + finally: + # cleanup - there's no public unregister_scale() + del mscale._scale_mapping["custom"]