Description
Bug report
It appears that pyplot.hist
(and I believe the equivalent axis method) does not allow lists of date
or datetime
objects to be used as the bin edges, even if the things being binned are dates, so:
from datetime import datetime
import matplotlib as mpl
from matplotlib import pyplot as plt
dates = [
datetime(2019, 1, 5), datetime(2019, 1, 11), datetime(2019, 2, 1),
datetime(2019, 2, 5), datetime(2019, 2, 18), datetime(2019, 3, 1),
]
date_edges = [
datetime(2019, 1, 1), datetime(2019, 2, 1), datetime(2019, 3, 1),
]
plt.hist(dates) # Works
plt.hist(dates, bins=mpl.dates.date2num(date_edges)) # Works
plt.hist(dates, bins=date_edges) # Fails
The first hist
call works but doesn't specify the bins, the second one works and does what we want, but it requires actively converting date_edges
. The third one should do the same thing as the second one, but instead it fails with:
TypeError: '<' not supported between instances of 'float' and 'datetime.datetime'
Full error message below:
TypeError Traceback (most recent call last)
<ipython-input-27-5b07a69daccb> in <module>
----> 1 plt.hist(dates, bins=date_bins)
/tmp/mpl/lib/python3.7/site-packages/matplotlib/pyplot.py in hist(x, bins, range, density, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, normed, data, **kwargs)
2640 align=align, orientation=orientation, rwidth=rwidth, log=log,
2641 color=color, label=label, stacked=stacked, normed=normed,
-> 2642 **({"data": data} if data is not None else {}), **kwargs)
2643
2644
/tmp/mpl/lib/python3.7/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
1599 def inner(ax, *args, data=None, **kwargs):
1600 if data is None:
-> 1601 return func(ax, *map(sanitize_sequence, args), **kwargs)
1602
1603 bound = new_sig.bind(ax, *args, **kwargs)
/tmp/mpl/lib/python3.7/site-packages/matplotlib/axes/_axes.py in hist(self, x, bins, range, density, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, normed, **kwargs)
6765 # this will automatically overwrite bins,
6766 # so that each histogram uses the same bins
-> 6767 m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs)
6768 m = m.astype(float) # causes problems later if it's an int
6769 if mlast is None:
<__array_function__ internals> in histogram(*args, **kwargs)
/tmp/mpl/lib/python3.7/site-packages/numpy/lib/histograms.py in histogram(a, bins, range, normed, weights, density)
869 for i in _range(0, len(a), BLOCK):
870 sa = np.sort(a[i:i+BLOCK])
--> 871 cum_n += _search_sorted_inclusive(sa, bin_edges)
872 else:
873 zero = np.zeros(1, dtype=ntype)
/tmp/mpl/lib/python3.7/site-packages/numpy/lib/histograms.py in _search_sorted_inclusive(a, v)
452 """
453 return np.concatenate((
--> 454 a.searchsorted(v[:-1], 'left'),
455 a.searchsorted(v[-1:], 'right')
456 ))
TypeError: '<' not supported between instances of 'float' and 'datetime.datetime'
I think this is another manifestation of the same underlying problem we saw in #12863 (see my comments in there for some more details on that), which is that a lot of the datetime
stuff converts somewhat eagerly to floats but some of it doesn't.
I think this case is easier than #12863 in the sense that you can almost certainly translate this into an unambiguous point on the number line and eagerly convert the bin edges early on, depending on how matplotlib
treats naive datetimes. It's possible that you may want to detect if x
and bins
are both naive or both aware and throw an error if they aren't, but I don't see that as a major sticking point.
Matplotlib version
- Operating system: Linux
- Matplotlib version: 3.1.1
- Matplotlib backend (
print(matplotlib.get_backend())
): TkAgg - Python version: 3.7.4