matplitlib.dates.drange can return unexpected dates, depending on the delta. I think it's a precision issue from using fractions of a day as the delta in drange. For example, changing hours=6 to hours=4 in the main section of dates.py
d1 = datetime.datetime( 2000, 3, 1, tzinfo=tz)
d2 = datetime.datetime( 2000, 3, 5, tzinfo=tz)
delta = datetime.timedelta(hours=6) # change to 4 to see the issue
dates = drange(d1, d2, delta)
gives dates such as 2000-03-01 23:59:59.999989+00:00 instead of 2000-03-02 00:00:00+00:00
Would it be better to use datetimes and timedeltas to fill in the array returned by drange and convert the array to fractions of a day at the end of the calculations? Something like
def drange(dstart, dend, delta):
"""
Return a date range as float Gregorian ordinals. dstart and dend are :class:datetime instances. delta is a
:class:datetime.timedelta instance.
"""
dates = [dstart]
f1 = dstart + delta
while f1 <= dend:
dates.append(f1)
f1 += delta
return date2num(dates)
I ran into this problem trying to use drange to create 4 hour ticks in a date plot on a mac running OS X 10.6 with python 2.7.1, matplotlib 1.1.0 and numpy 2.0.0.dev-3071eab.
i think the problem is located at dates.py:
the function "def _from_ordinalf(x, tz=None):" (in current trunk it's line 190) converts an float-value to a datetime object,
there already these two lines try to fix roundig errors:
ifmicrosecond>999990: # compensate for rounding errorsdt+=datetime.timedelta(microseconds=1e6-microsecond)
But in drange, the sequently added timedeltas lead to larger rounding errors, which are no longer "fixed" by this.
however, this seems to be a problem only for very long "ranges",
i think on normal scales these rounding errors are not directly visible in the plots.
in the numpy doc it is stated about "np.arange", which is used to generate the datetime-floats, that:
"When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use linspace for these cases."
Indeed, i could create "better" results with linspace, but this requires the distance between dend and dstart to be an exact multiple of delta.
So i don't know, if i should try to create a fix involving linspace, or if these rounding-errors should be accepted.
Thanks for looking into the problem I was having. I am unable to reproduce the problem with the latest numpy and matplotlib from github.
The small rounding errors were not noticeable in the data points plotted, but the times in the X tick labels (%H:%M) were something like NN:59 instead of NN+1:00 for some values. This is not happening when I use drange with recent versions of numpy and matplotlib from github.
I have not noticed roundoff problems using python's datetimes and timedeltas. My thought was that the roundoff errors could be reduced by using the datetimes and the timedelta passed to drange to compute an array of datetime values, then convert the array to matplotlib's date/time format when drange returns with date2num. I guess that's not necessary since drange is working as expected now.
oh, thats interesting,
which versions of matplotlib/numpy do you use?
I tested it with matplotlib (actual developement branch) and numpy 2.0.0.dev-5e4a407 (after your message i did a numpy-update) but here the rounding errors are still present.
I think i will commit a fix, and maybe discuss it on the developement maillinglist. (because i'm not quite sure which is the better way to fix ist).
I had the same idea about creating an array of datetime-values, this works very well (and is easy to understand), but its much (really much!) slower than using numpy.
My mistake. I forgot that I had changed drange in my local copy of dates.py to use datetimes and timedeltas. I switched back to dates.py from the latest development version and I see the rounded-off NN:59 time values in my Xtick labels. Sorry for the confusion.
numpy's linspace worked well for the few simple tests I tried, so I would vote for using it in drange to avoid the roundoff errors.
Activity
faucon commented on Jul 4, 2011
i think the problem is located at dates.py:
the function "def _from_ordinalf(x, tz=None):" (in current trunk it's line 190) converts an float-value to a datetime object,
there already these two lines try to fix roundig errors:
But in drange, the sequently added timedeltas lead to larger rounding errors, which are no longer "fixed" by this.
however, this seems to be a problem only for very long "ranges",
i think on normal scales these rounding errors are not directly visible in the plots.
in the numpy doc it is stated about "np.arange", which is used to generate the datetime-floats, that:
"When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use linspace for these cases."
Indeed, i could create "better" results with linspace, but this requires the distance between dend and dstart to be an exact multiple of delta.
So i don't know, if i should try to create a fix involving linspace, or if these rounding-errors should be accepted.
thanks,
Maximilian
selasley commented on Jul 6, 2011
Thanks for looking into the problem I was having. I am unable to reproduce the problem with the latest numpy and matplotlib from github.
The small rounding errors were not noticeable in the data points plotted, but the times in the X tick labels (%H:%M) were something like NN:59 instead of NN+1:00 for some values. This is not happening when I use drange with recent versions of numpy and matplotlib from github.
I have not noticed roundoff problems using python's datetimes and timedeltas. My thought was that the roundoff errors could be reduced by using the datetimes and the timedelta passed to drange to compute an array of datetime values, then convert the array to matplotlib's date/time format when drange returns with date2num. I guess that's not necessary since drange is working as expected now.
Thanks again.
faucon commented on Jul 6, 2011
oh, thats interesting,
which versions of matplotlib/numpy do you use?
I tested it with matplotlib (actual developement branch) and numpy 2.0.0.dev-5e4a407 (after your message i did a numpy-update) but here the rounding errors are still present.
I think i will commit a fix, and maybe discuss it on the developement maillinglist. (because i'm not quite sure which is the better way to fix ist).
I had the same idea about creating an array of datetime-values, this works very well (and is easy to understand), but its much (really much!) slower than using numpy.
fix for issue matplotlib#135. Workaround for rounding problems
selasley commented on Jul 6, 2011
My mistake. I forgot that I had changed drange in my local copy of dates.py to use datetimes and timedeltas. I switched back to dates.py from the latest development version and I see the rounded-off NN:59 time values in my Xtick labels. Sorry for the confusion.
numpy's linspace worked well for the few simple tests I tried, so I would vote for using it in drange to avoid the roundoff errors.
efiring commented on Oct 7, 2011
Fix by faucon was merged.