Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove need for ConversionInterface to support unitless values. #20334

Merged
merged 1 commit into from Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/api/next_api_changes/deprecations/20334-AL.rst
@@ -0,0 +1,11 @@
``ConversionInterface.convert`` no longer needs to accept unitless values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previously, custom subclasses of `.units.ConversionInterface` needed to
implement a ``convert`` method that not only accepted instances of the
unit, but also unitless values (which are passed through as is). This is
no longer the case (``convert`` is never called with a unitless value),
and such support in `.StrCategoryConverter` is deprecated. Likewise, the
`.ConversionInterface.is_numlike` helper is deprecated.

Consider calling `.Axis.convert_units` instead, which still supports unitless
values.
2 changes: 0 additions & 2 deletions examples/units/basic_units.py
Expand Up @@ -343,8 +343,6 @@ def axisinfo(unit, axis):

@staticmethod
def convert(val, unit, axis):
if units.ConversionInterface.is_numlike(val):
return val
if np.iterable(val):
if isinstance(val, np.ma.MaskedArray):
val = val.astype(float).filled(np.nan)
Expand Down
3 changes: 0 additions & 3 deletions examples/units/evans_test.py
Expand Up @@ -48,9 +48,6 @@ def convert(obj, unit, axis):

If *obj* is a sequence, return the converted sequence.
"""
if units.ConversionInterface.is_numlike(obj):
return obj

if np.iterable(obj):
return [o.value(unit) for o in obj]
else:
Expand Down
8 changes: 2 additions & 6 deletions lib/matplotlib/axis.py
Expand Up @@ -2273,9 +2273,7 @@ def set_default_intervals(self):
if self.converter is not None:
info = self.converter.axisinfo(self.units, self)
if info.default_limits is not None:
valmin, valmax = info.default_limits
xmin = self.converter.convert(valmin, self.units, self)
xmax = self.converter.convert(valmax, self.units, self)
xmin, xmax = self.convert_units(info.default_limits)
if not dataMutated:
self.axes.dataLim.intervalx = xmin, xmax
if not viewMutated:
Expand Down Expand Up @@ -2538,9 +2536,7 @@ def set_default_intervals(self):
if self.converter is not None:
info = self.converter.axisinfo(self.units, self)
if info.default_limits is not None:
valmin, valmax = info.default_limits
ymin = self.converter.convert(valmin, self.units, self)
ymax = self.converter.convert(valmax, self.units, self)
ymin, ymax = self.convert_units(info.default_limits)
if not dataMutated:
self.axes.dataLim.intervaly = ymin, ymax
if not viewMutated:
Expand Down
12 changes: 9 additions & 3 deletions lib/matplotlib/category.py
Expand Up @@ -54,9 +54,15 @@ def convert(value, unit, axis):
# dtype = object preserves numerical pass throughs
values = np.atleast_1d(np.array(value, dtype=object))
# pass through sequence of non binary numbers
if all(units.ConversionInterface.is_numlike(v)
and not isinstance(v, (str, bytes))
for v in values):
with _api.suppress_matplotlib_deprecation_warning():
is_numlike = all(units.ConversionInterface.is_numlike(v)
and not isinstance(v, (str, bytes))
for v in values)
if is_numlike:
_api.warn_deprecated(
"3.5", message="Support for passing numbers through unit "
"converters is deprecated since %(since)s and support will be "
"removed %(removal)s; use Axis.convert_units instead.")
return np.asarray(values, dtype=float)
# force an update so it also does type checking
unit.update(values)
Expand Down
2 changes: 0 additions & 2 deletions lib/matplotlib/testing/jpl_units/EpochConverter.py
Expand Up @@ -81,8 +81,6 @@ def convert(value, unit, axis):

if not cbook.is_scalar_or_string(value):
return [EpochConverter.convert(x, unit, axis) for x in value]
if units.ConversionInterface.is_numlike(value):
return value
if unit is None:
unit = EpochConverter.default_units(value, axis)
if isinstance(value, U.Duration):
Expand Down
3 changes: 0 additions & 3 deletions lib/matplotlib/testing/jpl_units/StrConverter.py
Expand Up @@ -27,9 +27,6 @@ def axisinfo(unit, axis):
def convert(value, unit, axis):
# docstring inherited

if units.ConversionInterface.is_numlike(value):
return value

if value == []:
return []

Expand Down
5 changes: 0 additions & 5 deletions lib/matplotlib/testing/jpl_units/UnitDblConverter.py
Expand Up @@ -66,11 +66,6 @@ def convert(value, unit, axis):
# docstring inherited
if not cbook.is_scalar_or_string(value):
return [UnitDblConverter.convert(x, unit, axis) for x in value]
# If the incoming value behaves like a number,
# then just return it because we don't know how to convert it
# (or it is already converted)
if units.ConversionInterface.is_numlike(value):
return value
# If no units were specified, then get the default units to use.
if unit is None:
unit = UnitDblConverter.default_units(value, axis)
Expand Down
7 changes: 5 additions & 2 deletions lib/matplotlib/tests/test_category.py
Expand Up @@ -2,6 +2,7 @@
import pytest
import numpy as np

from matplotlib._api import MatplotlibDeprecationWarning
from matplotlib.axes import Axes
import matplotlib.pyplot as plt
import matplotlib.category as cat
Expand Down Expand Up @@ -100,12 +101,14 @@ def test_convert_one_string(self, value):
assert self.cc.convert(value, self.unit, self.ax) == 0

def test_convert_one_number(self):
actual = self.cc.convert(0.0, self.unit, self.ax)
with pytest.warns(MatplotlibDeprecationWarning):
actual = self.cc.convert(0.0, self.unit, self.ax)
np.testing.assert_allclose(actual, np.array([0.]))

def test_convert_float_array(self):
data = np.array([1, 2, 3], dtype=float)
actual = self.cc.convert(data, self.unit, self.ax)
with pytest.warns(MatplotlibDeprecationWarning):
actual = self.cc.convert(data, self.unit, self.ax)
np.testing.assert_allclose(actual, np.array([1., 2., 3.]))

@pytest.mark.parametrize("fvals", fvalues, ids=fids)
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/units.py
Expand Up @@ -48,7 +48,7 @@ def default_units(x, axis):
import numpy as np
from numpy import ma

from matplotlib import cbook
from matplotlib import _api, cbook


class ConversionError(TypeError):
Expand Down Expand Up @@ -134,6 +134,7 @@ def convert(obj, unit, axis):
return obj

@staticmethod
@_api.deprecated("3.5")
def is_numlike(x):
"""
The Matplotlib datalim, autoscaling, locators etc work with scalars
Expand Down