Description
Bug report
Calling plot with xunits=None or yunits=None more than once throws an exception.
Matplotlib version
- Operating system: RedHat Enterprise 7
- Matplotlib version: 2.2.2
- Matplotlib backend (
print(matplotlib.get_backend())
): Qt5Agg - Python version: 2.7.14
Bug summary
Note that I know this looks weird - but this in an application library that where the user may or may not set units. So we always pass that info though to the kwarg and it may be None in some cases.
import pylab as P
from datetime import datetime
t0 = datetime( 2018, 3, 1 )
t1 = datetime( 2018, 3, 2 )
t2 = datetime( 2018, 3, 3 )
t3 = datetime( 2018, 3, 4 )
# First call works, second call throws.
P.plot( [t0, t1], ["V1", "V1"], xunits=None, yunits=None )
P.plot( [t2, t3], ["V1", "V1"], xunits=None, yunits=None )
P.show()
Actual outcome
Traceback (most recent call last):
File "t.py", line 10, in <module>
P.plot( [t2, t3], ["V1", "V1"], xunits=None, yunits=None )
File "site-packages/matplotlib/pyplot.py", line 3358, in plot
ret = ax.plot(*args, **kwargs)
File "site-packages/matplotlib/__init__.py", line 1855, in inner
return func(ax, *args, **kwargs)
File "site-packages/matplotlib/axes/_axes.py", line 1527, in plot
for line in self._get_lines(*args, **kwargs):
File "site-packages/matplotlib/axes/_base.py", line 194, in __call__
self.axes.yaxis.set_units(yunits)
File "site-packages/matplotlib/axis.py", line 1544, in set_units
self._update_axisinfo()
File "site-packages/matplotlib/axis.py", line 1486, in _update_axisinfo
info = self.converter.axisinfo(self.units, self)
File "site-packages/matplotlib/category.py", line 93, in axisinfo
majloc = StrCategoryLocator(unit._mapping)
AttributeError: 'NoneType' object has no attribute '_mapping'
The issue is in axes/_base.py:2130 in the _process_unit_info() method. If the xunits or yunits kwarg is set, it's used even if it's None. The question here is what is None in this context. Before 2.2.2, None meant "use the default units". But now that's not possible because it depends on what was plotted before that call whether that will work or not.
My suggestion is that None should mean "I'm not setting this" and behave the way it did before. I think that adding these lines to process_unit_info would fix this (repeat for yunits).
xunits = kwargs.pop('xunits', self.xaxis.units)
if xunits is None:
xunits = self.axis.units