Repository navigation
[Bug]: ax.bar raises for all-nan data on matplotlib 3.6.1 — Task 268 — matplotlib__matplotlib-24149 #34
Copy link
Copy link
Open
Description
[Bug]: ax.bar raises for all-nan data on matplotlib 3.6.1
Bug summary
ax.bar raises an exception in 3.6.1 when passed only NaN data. This breaks seaborn's histogram function (which draws and then removes a "phantom" bar to trip the color cycle).
Code for reproduction
import numpy as np
import matplotlib.pyplot as plt
f, ax = plt.subplots()
ax.bar([np.nan], [np.nan])Actual outcome
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
Cell In [1], line 4
2 import matplotlib.pyplot as plt
3 f, ax = plt.subplots()
----> 4 ax.bar([np.nan], [np.nan])[0].get_x()
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/__init__.py:1423, in _preprocess_data.<locals>.inner(ax, data, *args, **kwargs)
1420 @functools.wraps(func)
1421 def inner(ax, *args, data=None, **kwargs):
1422 if data is None:
-> 1423 return func(ax, *map(sanitize_sequence, args), **kwargs)
1425 bound = new_sig.bind(ax, *args, **kwargs)
1426 auto_label = (bound.arguments.get(label_namer)
or bound.kwargs.get(label_namer))
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/axes/_axes.py:2373, in Axes.bar(self, x, height, width, bottom, align, **kwargs)
2371 x0 = x
2372 x = np.asarray(self.convert_xunits(x))
-> 2373 width = self._convert_dx(width, x0, x, self.convert_xunits)
2374 if xerr is not None:
2375 xerr = self._convert_dx(xerr, x0, x, self.convert_xunits)
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/axes/_axes.py:2182, in Axes._convert_dx(dx, x0, xconv, convert)
2170 try:
2171 # attempt to add the width to x0; this works for
2172 # datetime+timedelta, for instance
(...)
2179 # removes the units from unit packages like `pint` that
2180 # wrap numpy arrays.
2181 try:
-> 2182 x0 = cbook._safe_first_finite(x0)
2183 except (TypeError, IndexError, KeyError):
2184 pass
File ~/miniconda/envs/py310/lib/python3.10/site-packages/matplotlib/cbook/__init__.py:1749, in _safe_first_finite(obj, skip_nonfinite)
1746 raise RuntimeError("matplotlib does not "
1747 "support generators as input")
1748 else:
-> 1749 return next(val for val in obj if safe_isfinite(val))
StopIteration: Expected outcome
On 3.6.0 this returns a BarCollection with one Rectangle, having nan for x and height.
Additional information
- Likely related to FIX: show bars when the first location is nan matplotlib/matplotlib#23751
- Root cause:
cbook._safe_first_finiteraisesStopIterationwhen no finite value exists (all-NaN). InAxes._convert_dx,StopIterationis not handled for both thex0andxconvpaths, so the exception propagates. - Observed asymmetry:
ax.bar([np.nan], [0])raises (due to NaN x)ax.bar([0], [np.nan])works
Research specification (from Emerson Gray)
- Fix scope:
lib/matplotlib/axes/_axes.py, methodAxes._convert_dx. - Behavior change: For both calls to
cbook._safe_first_finite(onx0andxconv), catchStopIterationand fall back tocbook.safe_first_elementso that NaN-only inputs do not raise. - Maintain existing exception handling for
(TypeError, IndexError, KeyError)and outer handler(ValueError, TypeError, AttributeError). - Expected post-fix behavior:
ax.bar([np.nan], [np.nan])returns a BarContainer with one Rectangle; its x and height are NaN (consistent with 3.6.0).ax.bar([np.nan], [0])returns without raising; x is NaN, height 0.ax.bar([0], [np.nan])continues to work.- No change to autoscaling semantics.
Test plan
Add regression tests to confirm:
ax.bar([np.nan], [np.nan])does not raise and returns a container with one Rectangle (optionally assert NaN x/height).ax.bar([np.nan], [0])does not raise (optionally assert NaN x, zero height).ax.bar([0], [np.nan])continues to work (optionally assert height is NaN).
Environment
- Reproducible on Matplotlib 3.6.1 (Python 3.10, NumPy 1.22/1.23). Newer versions may not reproduce the regression.
Task reference: Task 268 — matplotlib__matplotlib-24149
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity