Description
Bug summary
I am seeing a deprecation warning coming out of numpy in my tests. It's triggered from within matplotlib when I set the limits on a categorical axis using categorical values.
It is fundamentally the same issue as #25744. That was a case where a user was passing an array where matplotlib expected a scalar, and closed (which is reasonable).
My case is a bit different. I'm honestly not sure if matplotlib expects this to work, but it currently does.
Code for reproduction
import matplotlib.pyplot as plt
import warnings
warnings.simplefilter("always", DeprecationWarning)
f, ax = plt.subplots()
ax.plot(["a", "b", "c", "d"], [1, 2, 3, 4])
ax.set(xlim=("b", "c"))
Actual outcome
/Users/mwaskom/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/transforms.py:2855: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
vmin, vmax = map(float, [vmin, vmax])
When converted to an error, I see this traceback:
---------------------------------------------------------------------------
DeprecationWarning Traceback (most recent call last)
Cell In [118], line 6
4 f, ax = plt.subplots()
5 ax.plot(["a", "b", "c", "d"], [1, 2, 3, 4])
----> 6 ax.set(xlim=("b", "c"))
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/artist.py:147, in Artist.__init_subclass__.<locals>.<lambda>(self, **kwargs)
139 if not hasattr(cls.set, '_autogenerated_signature'):
140 # Don't overwrite cls.set if the subclass or one of its parents
141 # has defined a set method set itself.
142 # If there was no explicit definition, cls.set is inherited from
143 # the hierarchy of auto-generated set methods, which hold the
144 # flag _autogenerated_signature.
145 return
--> 147 cls.set = lambda self, **kwargs: Artist.set(self, **kwargs)
148 cls.set.__name__ = "set"
149 cls.set.__qualname__ = f"{cls.__qualname__}.set"
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/artist.py:1226, in Artist.set(self, **kwargs)
1222 def set(self, **kwargs):
1223 # docstring and signature are auto-generated via
1224 # Artist._update_set_signature_and_docstring() at the end of the
1225 # module.
-> 1226 return self._internal_update(cbook.normalize_kwargs(kwargs, self))
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/artist.py:1218, in Artist._internal_update(self, kwargs)
1211 def _internal_update(self, kwargs):
1212 """
1213 Update artist properties without prenormalizing them, but generating
1214 errors as if calling `set`.
1215
1216 The lack of prenormalization is to maintain backcompatibility.
1217 """
-> 1218 return self._update_props(
1219 kwargs, "{cls.__name__}.set() got an unexpected keyword argument "
1220 "{prop_name!r}")
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/artist.py:1194, in Artist._update_props(self, props, errfmt)
1191 if not callable(func):
1192 raise AttributeError(
1193 errfmt.format(cls=type(self), prop_name=k))
-> 1194 ret.append(func(v))
1195 if ret:
1196 self.pchanged()
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/axes/_base.py:3646, in _AxesBase.set_xlim(self, left, right, emit, auto, xmin, xmax)
3644 raise TypeError("Cannot pass both 'right' and 'xmax'")
3645 right = xmax
-> 3646 return self.xaxis._set_lim(left, right, emit=emit, auto=auto)
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/axis.py:1239, in Axis._set_lim(self, v0, v1, emit, auto)
1235 _api.warn_external(
1236 f"Attempting to set identical low and high {name}lims "
1237 f"makes transformation singular; automatically expanding.")
1238 reverse = bool(v0 > v1) # explicit cast needed for python3.8+np.bool_.
-> 1239 v0, v1 = self.get_major_locator().nonsingular(v0, v1)
1240 v0, v1 = self.limit_range_for_scale(v0, v1)
1241 v0, v1 = sorted([v0, v1], reverse=bool(reverse))
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/ticker.py:1649, in Locator.nonsingular(self, v0, v1)
1635 def nonsingular(self, v0, v1):
1636 """
1637 Adjust a range as needed to avoid singularities.
1638
(...)
1647 - Otherwise, ``(v0, v1)`` is returned without modification.
1648 """
-> 1649 return mtransforms.nonsingular(v0, v1, expander=.05)
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/transforms.py:2855, in nonsingular(vmin, vmax, expander, tiny, increasing)
2851 swapped = True
2853 # Expand vmin, vmax to float: if they were integer types, they can wrap
2854 # around in abs (abs(np.int8(-128)) == -128) and vmax - vmin can overflow.
-> 2855 vmin, vmax = map(float, [vmin, vmax])
2857 maxabsvalue = max(abs(vmin), abs(vmax))
2858 if maxabsvalue < (1e6 / tiny) * np.finfo(float).tiny:
DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
Expected outcome
No warning. Alternatively, if matplotlib does not consider this proper use of the API, you could formally deprecating it and then handle + raise, to avoid a confusing error once the numpy deprecation is enacted.
Additional information
No response
Operating system
No response
Matplotlib Version
3.8.0.rc1
Matplotlib Backend
No response
Python version
No response
Jupyter version
No response
Installation
None