Description
Bug report
Bug summary
When plotting short (sub-second) time intervals, issues with tick labels and tick locations can be observed, and even the plot frames start looking jagged.
Code for reproduction
import datetime as pydt
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=7, ncols=1, figsize=(6, 10))
for i, ut in enumerate([60*1e6, 1e6, 1e5, 1e4, 1e3, 100, 10]):
td = pydt.timedelta(microseconds=ut)
dti = [pydt.datetime(2017, 12, 21, 12, 2, 59, 999922),
pydt.datetime(2017, 12, 21, 12, 2, 59, 999922) + td]
axes[i].plot(dti, [1, 1])
axes[i].set_title('delta t = {}'.format(td), position=(0.5, 0.4))
for l in axes[i].xaxis.get_majorticklabels():
l.set_rotation(45)
l.set_horizontalalignment('right')
plt.tight_layout()
Actual outcome
Expected outcome
Investigation results
The underlying issue is MPL's internal datetime representation as a float: time in days since 0001-01-01 UTC, plus 1. While microsecond resolution is supported by datetime (and also by the AutoDateLocator and AutoDateFormatter), the floats lose actual microsecond precision after some years (in the order of 300 years). It is simply not possible to obtain microsecond resolution plots, with datetimes around today, without changing the internal time representation.
The workaround is: if you need microsecond resolution plots, shift your datetimes. Using year 1 instead of the current year will give highest precision. The default tick labels won't show the year anyway.
Perhaps this limitation & workaround could be placed somewhere in the documentation?
To make this work even better, I'd also like to suggest some small changes to the code (in dates._from_ordinalf()). Pull request will follow shortly.