From 621a840de0c932041041b3a70e17dcc0cab36d39 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 09:24:40 -0600
Subject: [PATCH 01/23] Clean up docstrings (convert several single-quote
string comments to triple-quote docstrings for consistency.)
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 32 ++++++++++++++++++++++++--------
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index c2ade94c89fc..b487a7d0fb71 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -311,14 +311,18 @@ def date2num(d):
def julian2num(j):
- 'Convert a Julian date (or sequence) to a matplotlib date (or sequence).'
+ """
+ Convert a Julian date (or sequence) to a matplotlib date (or sequence).
+ """
if cbook.iterable(j):
j = np.asarray(j)
return j - 1721424.5
def num2julian(n):
- 'Convert a matplotlib date (or sequence) to a Julian date (or sequence).'
+ """
+ Convert a matplotlib date (or sequence) to a Julian date (or sequence).
+ """
if cbook.iterable(n):
n = np.asarray(n)
return n + 1721424.5
@@ -1207,7 +1211,9 @@ def _get_interval(self):
def _close_to_dt(d1, d2, epsilon=5):
- 'Assert that datetimes *d1* and *d2* are within *epsilon* microseconds.'
+ """
+ Assert that datetimes *d1* and *d2* are within *epsilon* microseconds.
+ """
delta = d2 - d1
mus = abs(delta.days * MUSECONDS_PER_DAY + delta.seconds * 1e6 +
delta.microseconds)
@@ -1300,22 +1306,30 @@ def date_ticker_factory(span, tz=None, numticks=5):
def seconds(s):
- 'Return seconds as days.'
+ """
+ Return seconds as days.
+ """
return float(s) / SEC_PER_DAY
def minutes(m):
- 'Return minutes as days.'
+ """
+ Return minutes as days.
+ """
return float(m) / MINUTES_PER_DAY
def hours(h):
- 'Return hours as days.'
+ """
+ Return hours as days.
+ """
return h / 24.
def weeks(w):
- 'Return weeks as days.'
+ """
+ Return weeks as days.
+ """
return w * 7.
@@ -1360,7 +1374,9 @@ def convert(value, unit, axis):
@staticmethod
def default_units(x, axis):
- 'Return the tzinfo instance of *x* or of its first element, or None'
+ """
+ Return the tzinfo instance of *x* or of its first element, or None
+ """
if isinstance(x, np.ndarray):
x = x.ravel()
From 504044e4e94663bbe0a3878a3e539b4d765942ea Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 09:31:12 -0600
Subject: [PATCH 02/23] Small expansions to docstrings in the date library.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index b487a7d0fb71..8ad33e7dd33f 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -609,6 +609,9 @@ def __getattr__(self, name):
class DateLocator(ticker.Locator):
+ """
+ Determines the tick locations when plotting dates.
+ """
hms0d = {'byhour': 0, 'byminute': 0, 'bysecond': 0}
def __init__(self, tz=None):
@@ -620,13 +623,22 @@ def __init__(self, tz=None):
self.tz = tz
def set_tzinfo(self, tz):
+ """
+ Set time zone info.
+ """
self.tz = tz
def datalim_to_dt(self):
+ """
+ Convert axis data interval to datetime objects.
+ """
dmin, dmax = self.axis.get_data_interval()
return num2date(dmin, self.tz), num2date(dmax, self.tz)
def viewlim_to_dt(self):
+ """
+ Converts the view interval to datetime objects.
+ """
vmin, vmax = self.axis.get_view_interval()
return num2date(vmin, self.tz), num2date(vmax, self.tz)
From 390c1f4397f0a29f828664ae8724432601086f46 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 17:28:43 -0600
Subject: [PATCH 03/23] Moved all the "magic numbers" into some centrally
defined constants for the moment.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 102 ++++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 40 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 8ad33e7dd33f..dd5f386de4d3 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -175,15 +175,28 @@ def _get_rc_timezone():
import pytz
return pytz.timezone(s)
+"""
+Time-related constants.
+"""
+EPOCH_OFFSET = 719163. # Days between 0001-01-01 and epoch, +1.
+JULIAN_OFFSET = 1721424.5 # Julian date at 0001-01-01
MICROSECONDLY = SECONDLY + 1
HOURS_PER_DAY = 24.
-MINUTES_PER_DAY = 60. * HOURS_PER_DAY
-SECONDS_PER_DAY = 60. * MINUTES_PER_DAY
+MIN_PER_HOUR = 60.
+SEC_PER_MIN = 60.
+MONTHS_PER_YEAR = 12.
+
+DAYS_PER_WEEK = 7.
+DAYS_PER_MONTH = 30.
+DAYS_PER_YEAR = 365.0
+
+MINUTES_PER_DAY = MIN_PER_HOUR * HOURS_PER_DAY
+SECONDS_PER_DAY = SEC_PER_MIN * MINUTES_PER_DAY
MUSECONDS_PER_DAY = 1e6 * SECONDS_PER_DAY
-SEC_PER_MIN = 60
-SEC_PER_HOUR = 3600
-SEC_PER_DAY = SEC_PER_HOUR * 24
-SEC_PER_WEEK = SEC_PER_DAY * 7
+
+SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR
+SEC_PER_DAY = SEC_PER_HOUR * HOURS_PER_DAY
+SEC_PER_WEEK = SEC_PER_DAY * DAYS_PER_WEEK # Days per week
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY = (
MO, TU, WE, TH, FR, SA, SU)
WEEKDAYS = (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY)
@@ -224,9 +237,9 @@ def _from_ordinalf(x, tz=None):
ix = int(x)
dt = datetime.datetime.fromordinal(ix)
remainder = float(x) - ix
- hour, remainder = divmod(24 * remainder, 1)
- minute, remainder = divmod(60 * remainder, 1)
- second, remainder = divmod(60 * remainder, 1)
+ hour, remainder = divmod(HOURS_PER_DAY * remainder, 1)
+ minute, remainder = divmod(MIN_PER_HOUR * remainder, 1)
+ second, remainder = divmod(SEC_PER_MIN * remainder, 1)
microsecond = int(1e6 * remainder)
if microsecond < 10:
microsecond = 0 # compensate for rounding errors
@@ -316,7 +329,7 @@ def julian2num(j):
"""
if cbook.iterable(j):
j = np.asarray(j)
- return j - 1721424.5
+ return j - JULIAN_OFFSET
def num2julian(n):
@@ -325,7 +338,7 @@ def num2julian(n):
"""
if cbook.iterable(n):
n = np.asarray(n)
- return n + 1721424.5
+ return n + JULIAN_OFFSET
def num2date(x, tz=None):
@@ -436,8 +449,19 @@ def _findall(self, text, substr):
# calendar.
def strftime(self, dt, fmt):
+ """
+ Prints `datetime.datetime` object `dt` using a C-like `strftime()`
+ format string.
+
+ Currently `datetime.datetime.strftime()` is not supported for
+ years <= 1900 in Python 2.x and years <= 1000 in Python 3.x. This
+ function extends this functionality to
+ """
fmt = self.illegal_s.sub(r"\1", fmt)
fmt = fmt.replace("%s", "s")
+
+ # strftime is not supported on datetime for years <= 1900 in Python 2.x
+ # or years <= 1000 in Python 3.x
if dt.year > 1900:
return cbook.unicode_safe(dt.strftime(fmt))
@@ -564,11 +588,11 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'):
self._tz = tz
self.defaultfmt = defaultfmt
self._formatter = DateFormatter(self.defaultfmt, tz)
- self.scaled = {365.0: '%Y',
- 30.: '%b %Y',
+ self.scaled = {DAYS_PER_YEAR: '%Y',
+ DAYS_PER_MONTH: '%b %Y',
1.0: '%b %d %Y',
- 1. / 24.: '%H:%M:%S',
- 1. / (24. * 60.): '%H:%M:%S.%f'}
+ 1. / HOURS_PER_DAY: '%H:%M:%S',
+ 1. / (MINUTES_PER_DAY): '%H:%M:%S.%f'}
def __call__(self, x, pos=None):
locator_unit_scale = float(self._locator._get_unit())
@@ -730,19 +754,19 @@ def _get_unit(self):
@staticmethod
def get_unit_generic(freq):
if (freq == YEARLY):
- return 365.0
+ return DAYS_PER_YEAR
elif (freq == MONTHLY):
- return 30.0
+ return DAYS_PER_MONTH
elif (freq == WEEKLY):
- return 7.0
+ return DAYS_PER_WEEK
elif (freq == DAILY):
return 1.0
elif (freq == HOURLY):
- return (1.0 / 24.0)
+ return (1.0 / HOURS_PER_DAY)
elif (freq == MINUTELY):
- return (1.0 / (24 * 60))
+ return (1.0 / MINUTES_PER_DAY)
elif (freq == SECONDLY):
- return (1.0 / (24 * 3600))
+ return (1.0 / SECONDS_PER_DAY)
else:
# error
return -1 # or should this just return '1'?
@@ -886,8 +910,8 @@ def nonsingular(self, vmin, vmax):
# whatever is thrown at us, we can scale the unit.
# But default nonsingular date plots at an ~4 year period.
if vmin == vmax:
- vmin = vmin - 365 * 2
- vmax = vmax + 365 * 2
+ vmin = vmin - DAYS_PER_YEAR * 2
+ vmax = vmax + DAYS_PER_YEAR * 2
return vmin, vmax
def set_axis(self, axis):
@@ -920,11 +944,11 @@ def get_locator(self, dmin, dmax):
delta = -delta
numYears = (delta.years * 1.0)
- numMonths = (numYears * 12.0) + delta.months
- numDays = (numMonths * 31.0) + delta.days
- numHours = (numDays * 24.0) + delta.hours
- numMinutes = (numHours * 60.0) + delta.minutes
- numSeconds = (numMinutes * 60.0) + delta.seconds
+ numMonths = (numYears * MONTHS_PER_YEAR) + delta.months
+ numDays = (numMonths * DAYS_PER_MONTH) + delta.days
+ numHours = (numDays * HOURS_PER_DAY) + delta.hours
+ numMinutes = (numHours * MIN_PER_HOUR) + delta.minutes
+ numSeconds = (numMinutes * SEC_PER_MIN) + delta.seconds
numMicroseconds = (numSeconds * 1e6) + delta.microseconds
nums = [numYears, numMonths, numDays, numHours, numMinutes,
@@ -1246,16 +1270,14 @@ def epoch2num(e):
Convert an epoch or sequence of epochs to the new date format,
that is days since 0001.
"""
- spd = 24. * 3600.
- return 719163 + np.asarray(e) / spd
+ return EPOCH_OFFSET + np.asarray(e) / SEC_PER_DAY
def num2epoch(d):
"""
Convert days since 0001 to epoch. *d* can be a number or sequence.
"""
- spd = 24. * 3600.
- return (np.asarray(d) - 719163) * spd
+ return (np.asarray(d) - EPOCH_OFFSET) * SEC_PER_DAY
def mx2num(mxdates):
@@ -1281,14 +1303,14 @@ def date_ticker_factory(span, tz=None, numticks=5):
"""
if span == 0:
- span = 1 / 24.
+ span = 1 / HOURS_PER_DAY
- minutes = span * 24 * 60
- hours = span * 24
+ minutes = span * MINUTES_PER_DAY
+ hours = span * HOURS_PER_DAY
days = span
- weeks = span / 7.
- months = span / 31. # approx
- years = span / 365.
+ weeks = span / DAYS_PER_WEEK
+ months = span / DAYS_PER_MONTH # Approx
+ years = span / DAYS_PER_YEAR # Approx
if years > numticks:
locator = YearLocator(int(years / numticks), tz=tz) # define
@@ -1335,14 +1357,14 @@ def hours(h):
"""
Return hours as days.
"""
- return h / 24.
+ return h / HOURS_PER_DAY
def weeks(w):
"""
Return weeks as days.
"""
- return w * 7.
+ return w * DAYS_PER_WEEK
class DateConverter(units.ConversionInterface):
From 5af753ccef87bdfd4ec7e1198273ebca83d9f7b1 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 17:49:30 -0600
Subject: [PATCH 04/23] Replace hard-coded conversion logic in _to_ordinalf
with functions from `datetime`.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index dd5f386de4d3..a79e92a93c0f 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -178,8 +178,8 @@ def _get_rc_timezone():
"""
Time-related constants.
"""
-EPOCH_OFFSET = 719163. # Days between 0001-01-01 and epoch, +1.
-JULIAN_OFFSET = 1721424.5 # Julian date at 0001-01-01
+EPOCH_OFFSET = float(datetime.datetime(1970, 1, 1)) # Epoch in ordinal
+JULIAN_OFFSET = 1721424.5 # Julian date at 0001-01-01
MICROSECONDLY = SECONDLY + 1
HOURS_PER_DAY = 24.
MIN_PER_HOUR = 60.
@@ -214,12 +214,13 @@ def _to_ordinalf(dt):
if delta is not None:
dt -= delta
- base = float(dt.toordinal())
- if hasattr(dt, 'hour'):
- base += (dt.hour / HOURS_PER_DAY + dt.minute / MINUTES_PER_DAY +
- dt.second / SECONDS_PER_DAY +
- dt.microsecond / MUSECONDS_PER_DAY
- )
+ base = dt.toordinal()
+ td_remainder = (dt-datetime.datetime.fromordinal(base)).total_seconds()
+
+ base = float(base)
+ if td_remainder > 0:
+ base ++ td_remainder / SECONDS_PER_DAY
+
return base
From ee7931cecddcf9f54eed5a399e6f4dd54f6c73bc Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 17:57:30 -0600
Subject: [PATCH 05/23] Make `from_ordinalf` use mostly functions from
`datetime` for time conversion.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 27 +++++++++------------------
1 file changed, 9 insertions(+), 18 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index a79e92a93c0f..b58f459386a7 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -191,12 +191,13 @@ def _get_rc_timezone():
DAYS_PER_YEAR = 365.0
MINUTES_PER_DAY = MIN_PER_HOUR * HOURS_PER_DAY
-SECONDS_PER_DAY = SEC_PER_MIN * MINUTES_PER_DAY
-MUSECONDS_PER_DAY = 1e6 * SECONDS_PER_DAY
SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR
SEC_PER_DAY = SEC_PER_HOUR * HOURS_PER_DAY
-SEC_PER_WEEK = SEC_PER_DAY * DAYS_PER_WEEK # Days per week
+SEC_PER_WEEK = SEC_PER_DAY * DAYS_PER_WEEK
+
+MUSECONDS_PER_DAY = 1e6 * SEC_PER_DAY
+
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY = (
MO, TU, WE, TH, FR, SA, SU)
WEEKDAYS = (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY)
@@ -219,7 +220,7 @@ def _to_ordinalf(dt):
base = float(base)
if td_remainder > 0:
- base ++ td_remainder / SECONDS_PER_DAY
+ base ++ td_remainder / SEC_PER_DAY
return base
@@ -238,18 +239,8 @@ def _from_ordinalf(x, tz=None):
ix = int(x)
dt = datetime.datetime.fromordinal(ix)
remainder = float(x) - ix
- hour, remainder = divmod(HOURS_PER_DAY * remainder, 1)
- minute, remainder = divmod(MIN_PER_HOUR * remainder, 1)
- second, remainder = divmod(SEC_PER_MIN * remainder, 1)
- microsecond = int(1e6 * remainder)
- if microsecond < 10:
- microsecond = 0 # compensate for rounding errors
- dt = datetime.datetime(
- dt.year, dt.month, dt.day, int(hour), int(minute), int(second),
- microsecond, tzinfo=UTC).astimezone(tz)
-
- if microsecond > 999990: # compensate for rounding errors
- dt += datetime.timedelta(microseconds=1e6 - microsecond)
+
+ dt += datetime.timedelta(seconds = remainder*SEC_PER_DAY)
return dt
@@ -374,7 +365,7 @@ def drange(dstart, dend, delta):
*dend* are :class:`datetime` instances. *delta* is a
:class:`datetime.timedelta` instance.
"""
- step = (delta.days + delta.seconds / SECONDS_PER_DAY +
+ step = (delta.days + delta.seconds / SEC_PER_DAY +
delta.microseconds / MUSECONDS_PER_DAY)
f1 = _to_ordinalf(dstart)
f2 = _to_ordinalf(dend)
@@ -767,7 +758,7 @@ def get_unit_generic(freq):
elif (freq == MINUTELY):
return (1.0 / MINUTES_PER_DAY)
elif (freq == SECONDLY):
- return (1.0 / SECONDS_PER_DAY)
+ return (1.0 / SEC_PER_DAY)
else:
# error
return -1 # or should this just return '1'?
From 4b0d94b446c978fc7f8ae3e46d33ff801adb3cc6 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 18:38:54 -0600
Subject: [PATCH 06/23] Fix issue causing failed builds.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index b58f459386a7..e605a94106da 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -178,7 +178,7 @@ def _get_rc_timezone():
"""
Time-related constants.
"""
-EPOCH_OFFSET = float(datetime.datetime(1970, 1, 1)) # Epoch in ordinal
+EPOCH_OFFSET = float(datetime.datetime(1970, 1, 1).toordinal())
JULIAN_OFFSET = 1721424.5 # Julian date at 0001-01-01
MICROSECONDLY = SECONDLY + 1
HOURS_PER_DAY = 24.
From ba623a78f540cb696b60f7c83c91354aa945f9ac Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 24 Dec 2014 21:17:35 -0600
Subject: [PATCH 07/23] Fix problem with inconsistent time zones. This now also
fixes Issue #3896.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index e605a94106da..bd30a5defc72 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -215,12 +215,16 @@ def _to_ordinalf(dt):
if delta is not None:
dt -= delta
- base = dt.toordinal()
- td_remainder = (dt-datetime.datetime.fromordinal(base)).total_seconds()
+ # Get a datetime object at midnight in the same time zone as dt.
+ cdate = dt.date()
+ midnight_time = datetime.time(0, 0, 0, tzinfo=dt.tzinfo)
- base = float(base)
+ rdt = datetime.datetime.combine(cdate, midnight_time)
+ td_remainder = (dt-rdt).total_seconds()
+
+ base = float(dt.toordinal())
if td_remainder > 0:
- base ++ td_remainder / SEC_PER_DAY
+ base += td_remainder / SEC_PER_DAY
return base
From 9f66ae2530d03e7ff102252a02e7c0cfd6f6419f Mon Sep 17 00:00:00 2001
From: Paul G
Date: Thu, 25 Dec 2014 14:34:57 -0600
Subject: [PATCH 08/23] Didn't realize that `_to_ordinalf` needs to support
datetime.date objects.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index bd30a5defc72..62f26313f209 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -205,11 +205,14 @@ def _get_rc_timezone():
def _to_ordinalf(dt):
"""
- Convert :mod:`datetime` to the Gregorian date as UTC float days,
- preserving hours, minutes, seconds and microseconds. Return value
+ Convert :mod:`datetime` or :mod:`date` to the Gregorian date as UTC float
+ days, preserving hours, minutes, seconds and microseconds. Return value
is a :func:`float`.
"""
+ if isinstance(dt, datetime.date):
+ return float(datetime.datetime.toordinal(dt))
+
if hasattr(dt, 'tzinfo') and dt.tzinfo is not None:
delta = dt.tzinfo.utcoffset(dt)
if delta is not None:
From d61397da93470e12e6a167c10b065bb1bdff096b Mon Sep 17 00:00:00 2001
From: Paul G
Date: Thu, 25 Dec 2014 14:36:42 -0600
Subject: [PATCH 09/23] PEP8 fix.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 62f26313f209..4a1a961448a9 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -247,7 +247,7 @@ def _from_ordinalf(x, tz=None):
dt = datetime.datetime.fromordinal(ix)
remainder = float(x) - ix
- dt += datetime.timedelta(seconds = remainder*SEC_PER_DAY)
+ dt += datetime.timedelta(seconds = remainder * SEC_PER_DAY)
return dt
From 0a5fbc68a08cf9e6ed48b6342822da07b1f987e1 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Fri, 26 Dec 2014 15:07:06 -0600
Subject: [PATCH 10/23] Fix timezone issue, update code to coding standards.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 58 ++++++++++++++++++++++-------------------
1 file changed, 31 insertions(+), 27 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 4a1a961448a9..f8bdf3563c16 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -169,6 +169,9 @@ def dst(self, dt):
def _get_rc_timezone():
+ """
+ Retrieve the preferred timeszone from the rcParams dictionary.
+ """
s = matplotlib.rcParams['timezone']
if s == 'UTC':
return UTC
@@ -247,7 +250,8 @@ def _from_ordinalf(x, tz=None):
dt = datetime.datetime.fromordinal(ix)
remainder = float(x) - ix
- dt += datetime.timedelta(seconds = remainder * SEC_PER_DAY)
+ dt += datetime.timedelta(seconds=remainder * SEC_PER_DAY)
+ dt = dt.astimezone(tz)
return dt
@@ -752,20 +756,20 @@ def _get_unit(self):
@staticmethod
def get_unit_generic(freq):
- if (freq == YEARLY):
+ if freq == YEARLY:
return DAYS_PER_YEAR
- elif (freq == MONTHLY):
+ elif freq == MONTHLY:
return DAYS_PER_MONTH
- elif (freq == WEEKLY):
+ elif freq == WEEKLY:
return DAYS_PER_WEEK
- elif (freq == DAILY):
+ elif freq == DAILY:
return 1.0
- elif (freq == HOURLY):
- return (1.0 / HOURS_PER_DAY)
- elif (freq == MINUTELY):
- return (1.0 / MINUTES_PER_DAY)
- elif (freq == SECONDLY):
- return (1.0 / SEC_PER_DAY)
+ elif freq == HOURLY:
+ return 1.0 / HOURS_PER_DAY
+ elif freq == MINUTELY:
+ return 1.0 / MINUTES_PER_DAY
+ elif freq == SECONDLY:
+ return 1.0 / SEC_PER_DAY
else:
# error
return -1 # or should this just return '1'?
@@ -1083,7 +1087,7 @@ class MonthLocator(RRuleLocator):
"""
Make ticks on occurances of each month month, eg 1, 3, 12.
"""
- def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None):
+ def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None):
"""
Mark every month in *bymonth*; *bymonth* can be an int or
sequence. Default is ``range(1,13)``, i.e. every month.
@@ -1103,7 +1107,7 @@ class WeekdayLocator(RRuleLocator):
Make ticks on occurances of each weekday.
"""
- def __init__(self, byweekday=1, interval=1, tz=None):
+ def __init__(self, byweekday=1, interval=1, tz=None):
"""
Mark every weekday in *byweekday*; *byweekday* can be a number or
sequence.
@@ -1125,7 +1129,7 @@ class DayLocator(RRuleLocator):
Make ticks on occurances of each day of the month. For example,
1, 15, 30.
"""
- def __init__(self, bymonthday=None, interval=1, tz=None):
+ def __init__(self, bymonthday=None, interval=1, tz=None):
"""
Mark every day in *bymonthday*; *bymonthday* can be an int or
sequence.
@@ -1143,7 +1147,7 @@ class HourLocator(RRuleLocator):
"""
Make ticks on occurances of each hour.
"""
- def __init__(self, byhour=None, interval=1, tz=None):
+ def __init__(self, byhour=None, interval=1, tz=None):
"""
Mark every hour in *byhour*; *byhour* can be an int or sequence.
Default is to tick every hour: ``byhour=range(24)``
@@ -1162,7 +1166,7 @@ class MinuteLocator(RRuleLocator):
"""
Make ticks on occurances of each minute.
"""
- def __init__(self, byminute=None, interval=1, tz=None):
+ def __init__(self, byminute=None, interval=1, tz=None):
"""
Mark every minute in *byminute*; *byminute* can be an int or
sequence. Default is to tick every minute: ``byminute=range(60)``
@@ -1181,7 +1185,7 @@ class SecondLocator(RRuleLocator):
"""
Make ticks on occurances of each second.
"""
- def __init__(self, bysecond=None, interval=1, tz=None):
+ def __init__(self, bysecond=None, interval=1, tz=None):
"""
Mark every second in *bysecond*; *bysecond* can be an int or
sequence. Default is to tick every second: ``bysecond = range(60)``
@@ -1252,7 +1256,7 @@ def _close_to_dt(d1, d2, epsilon=5):
delta = d2 - d1
mus = abs(delta.days * MUSECONDS_PER_DAY + delta.seconds * 1e6 +
delta.microseconds)
- assert(mus < epsilon)
+ assert mus < epsilon
def _close_to_num(o1, o2, epsilon=5):
@@ -1261,7 +1265,7 @@ def _close_to_num(o1, o2, epsilon=5):
microseconds.
"""
delta = abs((o2 - o1) * MUSECONDS_PER_DAY)
- assert(delta < epsilon)
+ assert delta < epsilon
def epoch2num(e):
@@ -1304,10 +1308,10 @@ def date_ticker_factory(span, tz=None, numticks=5):
if span == 0:
span = 1 / HOURS_PER_DAY
- minutes = span * MINUTES_PER_DAY
- hours = span * HOURS_PER_DAY
+ mins = span * MINUTES_PER_DAY
+ hrs = span * HOURS_PER_DAY
days = span
- weeks = span / DAYS_PER_WEEK
+ wks = span / DAYS_PER_WEEK
months = span / DAYS_PER_MONTH # Approx
years = span / DAYS_PER_YEAR # Approx
@@ -1317,17 +1321,17 @@ def date_ticker_factory(span, tz=None, numticks=5):
elif months > numticks:
locator = MonthLocator(tz=tz)
fmt = '%b %Y'
- elif weeks > numticks:
+ elif wks > numticks:
locator = WeekdayLocator(tz=tz)
fmt = '%a, %b %d'
elif days > numticks:
locator = DayLocator(interval=int(math.ceil(days / numticks)), tz=tz)
fmt = '%b %d'
- elif hours > numticks:
- locator = HourLocator(interval=int(math.ceil(hours / numticks)), tz=tz)
+ elif hrs > numticks:
+ locator = HourLocator(interval=int(math.ceil(hrs / numticks)), tz=tz)
fmt = '%H:%M\n%b %d'
- elif minutes > numticks:
- locator = MinuteLocator(interval=int(math.ceil(minutes / numticks)),
+ elif mins > numticks:
+ locator = MinuteLocator(interval=int(math.ceil(mins / numticks)),
tz=tz)
fmt = '%H:%M:%S'
else:
From 72ef748ad64aa449b4f185d8fb8dce33486266ca Mon Sep 17 00:00:00 2001
From: Paul G
Date: Fri, 26 Dec 2014 16:35:06 -0600
Subject: [PATCH 11/23] Fix timezone problem, clarify docstring for timezones.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index f8bdf3563c16..6fca9dfc1299 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -208,7 +208,7 @@ def _get_rc_timezone():
def _to_ordinalf(dt):
"""
- Convert :mod:`datetime` or :mod:`date` to the Gregorian date as UTC float
+ Convert :mod:`datetime` or :mod:`date` to the Gregorian date as UTC float
days, preserving hours, minutes, seconds and microseconds. Return value
is a :func:`float`.
"""
@@ -226,7 +226,7 @@ def _to_ordinalf(dt):
midnight_time = datetime.time(0, 0, 0, tzinfo=dt.tzinfo)
rdt = datetime.datetime.combine(cdate, midnight_time)
- td_remainder = (dt-rdt).total_seconds()
+ td_remainder = (dt - rdt).total_seconds()
base = float(dt.toordinal())
if td_remainder > 0:
@@ -243,15 +243,21 @@ def _from_ordinalf(x, tz=None):
"""
Convert Gregorian float of the date, preserving hours, minutes,
seconds and microseconds. Return value is a :class:`datetime`.
+
+ The input date `x` is a float in ordinal days at UTC, and the output will
+ be the specified :class:`datetime` object corresponding to that time in
+ timezone `tz`, or if `tz` is `None`, in the timezone specified in
+ `rcParams['timezone']`.
"""
if tz is None:
tz = _get_rc_timezone()
+
ix = int(x)
- dt = datetime.datetime.fromordinal(ix)
+ dt = datetime.datetime.fromordinal(ix).replace(tzinfo=UTC)
+
remainder = float(x) - ix
dt += datetime.timedelta(seconds=remainder * SEC_PER_DAY)
- dt = dt.astimezone(tz)
return dt
From 7fd2d36615e7d23b74e9e1c5303cdd991aa884de Mon Sep 17 00:00:00 2001
From: Paul G
Date: Fri, 26 Dec 2014 17:43:15 -0600
Subject: [PATCH 12/23] Fixed issue with `_to_ordinalf()`, should work fine
now. Build will still fail, but that's fine for now.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 6fca9dfc1299..ce061c20c33c 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -213,24 +213,22 @@ def _to_ordinalf(dt):
is a :func:`float`.
"""
- if isinstance(dt, datetime.date):
- return float(datetime.datetime.toordinal(dt))
-
if hasattr(dt, 'tzinfo') and dt.tzinfo is not None:
delta = dt.tzinfo.utcoffset(dt)
if delta is not None:
dt -= delta
- # Get a datetime object at midnight in the same time zone as dt.
- cdate = dt.date()
- midnight_time = datetime.time(0, 0, 0, tzinfo=dt.tzinfo)
+ base = float(dt.toordinal())
+ if isinstance(dt, datetime.datetime):
+ # Get a datetime object at midnight in the same time zone as dt.
+ cdate = dt.date()
+ midnight_time = datetime.time(0, 0, 0, tzinfo=dt.tzinfo)
- rdt = datetime.datetime.combine(cdate, midnight_time)
- td_remainder = (dt - rdt).total_seconds()
+ rdt = datetime.datetime.combine(cdate, midnight_time)
+ td_remainder = (dt - rdt).total_seconds()
- base = float(dt.toordinal())
- if td_remainder > 0:
- base += td_remainder / SEC_PER_DAY
+ if td_remainder > 0:
+ base += td_remainder / SEC_PER_DAY
return base
@@ -382,10 +380,9 @@ def drange(dstart, dend, delta):
*dend* are :class:`datetime` instances. *delta* is a
:class:`datetime.timedelta` instance.
"""
- step = (delta.days + delta.seconds / SEC_PER_DAY +
- delta.microseconds / MUSECONDS_PER_DAY)
f1 = _to_ordinalf(dstart)
f2 = _to_ordinalf(dend)
+ step = delta.total_seconds() / SEC_PER_DAY
# calculate the difference between dend and dstart in times of delta
num = int(np.ceil((f2 - f1) / step))
From 2f809168fb601ff9b89f07d9700c0073248d64b1 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Fri, 26 Dec 2014 18:46:03 -0600
Subject: [PATCH 13/23] Change behavior of `get_locator` to accurately
calculate number of days between two points.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index ce061c20c33c..e8e223e43b6c 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -257,6 +257,12 @@ def _from_ordinalf(x, tz=None):
dt += datetime.timedelta(seconds=remainder * SEC_PER_DAY)
+ # Compensate for rounding errors
+ if dt.microsecond < 10:
+ dt = dt.replace(microsecond=0)
+ elif dt.microsecond > 999990:
+ dt += datetime.timedelta(microseconds=1e6 - dt.microsecond)
+
return dt
@@ -944,14 +950,15 @@ def autoscale(self):
def get_locator(self, dmin, dmax):
'Pick the best locator based on a distance.'
delta = relativedelta(dmax, dmin)
+ tdelta = dmax - dmin
# take absolute difference
if dmin > dmax:
delta = -delta
- numYears = (delta.years * 1.0)
+ numYears = delta.years * 1.0
numMonths = (numYears * MONTHS_PER_YEAR) + delta.months
- numDays = (numMonths * DAYS_PER_MONTH) + delta.days
+ numDays = tdelta.days # Avoid estimates of days/month, days/year
numHours = (numDays * HOURS_PER_DAY) + delta.hours
numMinutes = (numHours * MIN_PER_HOUR) + delta.minutes
numSeconds = (numMinutes * SEC_PER_MIN) + delta.seconds
From ca284d12f8055585966b9c03c1be49f4fc55a4c5 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Fri, 26 Dec 2014 18:59:35 -0600
Subject: [PATCH 14/23] Absolute value must apply to timedelta object as well
as reslative delta object.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index e8e223e43b6c..36b63f204180 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -955,6 +955,7 @@ def get_locator(self, dmin, dmax):
# take absolute difference
if dmin > dmax:
delta = -delta
+ tdelta = -tdelta
numYears = delta.years * 1.0
numMonths = (numYears * MONTHS_PER_YEAR) + delta.months
From 68f3018df966f2b3f5f255220b765f25651d65e5 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Fri, 26 Dec 2014 19:58:21 -0600
Subject: [PATCH 15/23] Adjust calculation of `numSeconds` and
`numMicroseconds`, since the `timedelta` object actually calculates those for
us as is.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 36b63f204180..10252107a06a 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -957,13 +957,17 @@ def get_locator(self, dmin, dmax):
delta = -delta
tdelta = -tdelta
- numYears = delta.years * 1.0
+ # The following uses a mix of calls to relativedelta and timedelta
+ # methods because there is incomplete overlap in the functionality of
+ # these similar functions, and it's best to avoid doing our own math
+ # whenever possible.
+ numYears = float(delta.years)
numMonths = (numYears * MONTHS_PER_YEAR) + delta.months
- numDays = tdelta.days # Avoid estimates of days/month, days/year
+ numDays = tdelta.days # Avoids estimates of days/month, days/year
numHours = (numDays * HOURS_PER_DAY) + delta.hours
numMinutes = (numHours * MIN_PER_HOUR) + delta.minutes
- numSeconds = (numMinutes * SEC_PER_MIN) + delta.seconds
- numMicroseconds = (numSeconds * 1e6) + delta.microseconds
+ numSeconds = np.floor(tdelta.total_seconds())
+ numMicroseconds = np.floor(tdelta.total_seconds() * 1e6)
nums = [numYears, numMonths, numDays, numHours, numMinutes,
numSeconds, numMicroseconds]
From 88e6e1e52b67057243f5bc2c379bc6ceec9d7cce Mon Sep 17 00:00:00 2001
From: Paul G
Date: Sat, 27 Dec 2014 12:57:48 -0600
Subject: [PATCH 16/23] Another adjustment to allow external libraries to do
the calcs for us.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 10252107a06a..d8a3e073b35d 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -632,6 +632,7 @@ class rrulewrapper(object):
def __init__(self, freq, **kwargs):
self._construct = kwargs.copy()
self._construct["freq"] = freq
+ print(self._construct)
self._rrule = rrule(**self._construct)
def set(self, **kwargs):
@@ -1153,9 +1154,9 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
"""
if bymonthday is None:
bymonthday = list(xrange(1, 32))
- o = rrulewrapper(DAILY, bymonthday=bymonthday,
+ rule = rrulewrapper(DAILY, bymonthday=bymonthday,
interval=interval, **self.hms0d)
- RRuleLocator.__init__(self, o, tz)
+ RRuleLocator.__init__(self, rule, tz)
class HourLocator(RRuleLocator):
From 0de1e848635a497b116e154742b647ae7fe8524a Mon Sep 17 00:00:00 2001
From: Paul G
Date: Sat, 27 Dec 2014 18:56:03 -0600
Subject: [PATCH 17/23] Adjusted test_dates to account for the minor change in
behavior of the date locator.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 4 +---
lib/matplotlib/tests/test_dates.py | 10 +++++-----
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index d8a3e073b35d..3d78f6a3a4b5 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -632,7 +632,6 @@ class rrulewrapper(object):
def __init__(self, freq, **kwargs):
self._construct = kwargs.copy()
self._construct["freq"] = freq
- print(self._construct)
self._rrule = rrule(**self._construct)
def set(self, **kwargs):
@@ -1270,8 +1269,7 @@ def _close_to_dt(d1, d2, epsilon=5):
Assert that datetimes *d1* and *d2* are within *epsilon* microseconds.
"""
delta = d2 - d1
- mus = abs(delta.days * MUSECONDS_PER_DAY + delta.seconds * 1e6 +
- delta.microseconds)
+ mus = abs(delta.total_seconds() * 1e6)
assert mus < epsilon
diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py
index 7b847bb0df6d..79c20a85a07d 100644
--- a/lib/matplotlib/tests/test_dates.py
+++ b/lib/matplotlib/tests/test_dates.py
@@ -243,11 +243,11 @@ def _create_auto_date_locator(date1, date2):
'1990-09-01 00:00:00+00:00', '1990-10-01 00:00:00+00:00',
'1990-11-01 00:00:00+00:00', '1990-12-01 00:00:00+00:00']
],
- [datetime.timedelta(days=140),
- ['1990-01-06 00:00:00+00:00', '1990-01-27 00:00:00+00:00',
- '1990-02-17 00:00:00+00:00', '1990-03-10 00:00:00+00:00',
- '1990-03-31 00:00:00+00:00', '1990-04-21 00:00:00+00:00',
- '1990-05-12 00:00:00+00:00']
+ [datetime.timedelta(days=141),
+ ['1990-01-05 00:00:00+00:00', '1990-01-26 00:00:00+00:00',
+ '1990-02-16 00:00:00+00:00', '1990-03-09 00:00:00+00:00',
+ '1990-03-30 00:00:00+00:00', '1990-04-20 00:00:00+00:00',
+ '1990-05-11 00:00:00+00:00']
],
[datetime.timedelta(days=40),
['1990-01-03 00:00:00+00:00', '1990-01-10 00:00:00+00:00',
From f585a172e950de2fa581e90790ea3e169de83b9b Mon Sep 17 00:00:00 2001
From: Paul G
Date: Sun, 28 Dec 2014 14:38:59 -0600
Subject: [PATCH 18/23] Adjusted rounding logic in `_from_ordinalf` to be
consistent with previous versions.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 3d78f6a3a4b5..c3514f509069 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -255,7 +255,8 @@ def _from_ordinalf(x, tz=None):
remainder = float(x) - ix
- dt += datetime.timedelta(seconds=remainder * SEC_PER_DAY)
+ # Round down to the nearest microsecond.
+ dt += datetime.timedelta(microseconds=int(remainder * MUSECONDS_PER_DAY))
# Compensate for rounding errors
if dt.microsecond < 10:
From 2a0865b4b92a56e6b55ac15f4eb931b8815f0369 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Sun, 28 Dec 2014 17:10:48 -0600
Subject: [PATCH 19/23] Add alias for total_seconds() to support Python 2.6
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index c3514f509069..c8d4a41f62ae 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -225,7 +225,7 @@ def _to_ordinalf(dt):
midnight_time = datetime.time(0, 0, 0, tzinfo=dt.tzinfo)
rdt = datetime.datetime.combine(cdate, midnight_time)
- td_remainder = (dt - rdt).total_seconds()
+ td_remainder = _total_seconds(dt - rdt)
if td_remainder > 0:
base += td_remainder / SEC_PER_DAY
@@ -236,6 +236,27 @@ def _to_ordinalf(dt):
# a version of _to_ordinalf that can operate on numpy arrays
_to_ordinalf_np_vectorized = np.vectorize(_to_ordinalf)
+try:
+ datetime.timedelta(datetime.datetime(1970, 1, 1),
+ datetime.datetime(1970, 1, 2)).total_seconds()
+
+ def _total_seconds(tdelta):
+ """
+ Alias providing support for datetime.timedelta.total_seconds() function
+ calls even in Python < 2.7.
+
+ The input `tdelta` is a datetime.timedelta object, and returns a float
+ containing the total number of seconds representing the `tdelta`
+ duration. For large durations (> 270 on most platforms), this loses
+ microsecond accuracy.
+ """
+
+ return tdelta.total_seconds()
+except AttributeError:
+ def _total_seconds(tdelta):
+ return (tdelta.microseconds +
+ (tdelta.seconds + tdelta.days * SEC_PER_DAY) * 1e6) * 1e-6
+
def _from_ordinalf(x, tz=None):
"""
@@ -389,7 +410,7 @@ def drange(dstart, dend, delta):
"""
f1 = _to_ordinalf(dstart)
f2 = _to_ordinalf(dend)
- step = delta.total_seconds() / SEC_PER_DAY
+ step = _total_seconds(delta) / SEC_PER_DAY
# calculate the difference between dend and dstart in times of delta
num = int(np.ceil((f2 - f1) / step))
@@ -967,8 +988,8 @@ def get_locator(self, dmin, dmax):
numDays = tdelta.days # Avoids estimates of days/month, days/year
numHours = (numDays * HOURS_PER_DAY) + delta.hours
numMinutes = (numHours * MIN_PER_HOUR) + delta.minutes
- numSeconds = np.floor(tdelta.total_seconds())
- numMicroseconds = np.floor(tdelta.total_seconds() * 1e6)
+ numSeconds = np.floor(_total_seconds(tdelta))
+ numMicroseconds = np.floor(_total_seconds(tdelta) * 1e6)
nums = [numYears, numMonths, numDays, numHours, numMinutes,
numSeconds, numMicroseconds]
@@ -1270,7 +1291,7 @@ def _close_to_dt(d1, d2, epsilon=5):
Assert that datetimes *d1* and *d2* are within *epsilon* microseconds.
"""
delta = d2 - d1
- mus = abs(delta.total_seconds() * 1e6)
+ mus = abs(_total_seconds(delta) * 1e6)
assert mus < epsilon
From f1f6d8f234d9f77b5b9509d7b4956500c3b7f733 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Sun, 28 Dec 2014 17:13:25 -0600
Subject: [PATCH 20/23] Cleaner way to test for existence of `total_seconds()`.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index c8d4a41f62ae..e26f4c8759ef 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -237,8 +237,7 @@ def _to_ordinalf(dt):
_to_ordinalf_np_vectorized = np.vectorize(_to_ordinalf)
try:
- datetime.timedelta(datetime.datetime(1970, 1, 1),
- datetime.datetime(1970, 1, 2)).total_seconds()
+ datetime.timedelta(0).total_seconds() # Fails if method doesn't exist
def _total_seconds(tdelta):
"""
From 46a4a0a7fa1d9b0b0f5629582b5a6155a17e96a4 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Mon, 29 Dec 2014 01:36:23 -0600
Subject: [PATCH 21/23] Tighten up `_total_seconds()` alias.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index e26f4c8759ef..79e2b6086ee8 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -237,8 +237,9 @@ def _to_ordinalf(dt):
_to_ordinalf_np_vectorized = np.vectorize(_to_ordinalf)
try:
- datetime.timedelta(0).total_seconds() # Fails if method doesn't exist
-
+ # Available as a native method in Python >= 2.7.
+ _total_seconds = datetime.timedelta.total_seconds
+except AttributeError:
def _total_seconds(tdelta):
"""
Alias providing support for datetime.timedelta.total_seconds() function
@@ -249,10 +250,6 @@ def _total_seconds(tdelta):
duration. For large durations (> 270 on most platforms), this loses
microsecond accuracy.
"""
-
- return tdelta.total_seconds()
-except AttributeError:
- def _total_seconds(tdelta):
return (tdelta.microseconds +
(tdelta.seconds + tdelta.days * SEC_PER_DAY) * 1e6) * 1e-6
From 35b93d268ddd12a144b6c7d45410521995b38676 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Tue, 30 Dec 2014 17:53:39 -0600
Subject: [PATCH 22/23] Support numpy arrays in DayLocator, WeekdayLocator and
MonthLocator when dateutil <= 2.3
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 48 +++++++++++++++++++++++++++++------------
1 file changed, 34 insertions(+), 14 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 79e2b6086ee8..1a55bc8672a1 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -927,9 +927,8 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
MICROSECONDLY: [1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000,
5000, 10000, 20000, 50000, 100000, 200000, 500000,
1000000]}
- self._byranges = [None, list(xrange(1, 13)), list(xrange(1, 32)),
- list(xrange(0, 24)), list(xrange(0, 60)),
- list(xrange(0, 60)), None]
+ self._byranges = [None, range(1, 13), range(1, 32),
+ range(0, 24), range(0, 60), range(0, 60), None]
def __call__(self):
'Return the locations of the ticks'
@@ -1129,10 +1128,16 @@ def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None):
example, if ``interval=2``, mark every second occurance.
"""
if bymonth is None:
- bymonth = list(xrange(1, 13))
- o = rrulewrapper(MONTHLY, bymonth=bymonth, bymonthday=bymonthday,
+ bymonth = range(1, 13)
+ elif isinstance(bymonth, np.ndarray):
+ # This fixes a bug in dateutil <= 2.3 which prevents the use of
+ # numpy arrays in (among other things) the bymonthday, byweekday
+ # and bymonth parameters.
+ bymonth = [x.item() for x in bymonth.astype(int)]
+
+ rule = rrulewrapper(MONTHLY, bymonth=bymonth, bymonthday=bymonthday,
interval=interval, **self.hms0d)
- RRuleLocator.__init__(self, o, tz)
+ RRuleLocator.__init__(self, rule, tz)
class WeekdayLocator(RRuleLocator):
@@ -1152,9 +1157,15 @@ def __init__(self, byweekday=1, interval=1, tz=None):
*interval* specifies the number of weeks to skip. For example,
``interval=2`` plots every second week.
"""
- o = rrulewrapper(DAILY, byweekday=byweekday,
- interval=interval, **self.hms0d)
- RRuleLocator.__init__(self, o, tz)
+ if isinstance(byweekday, np.ndarray):
+ # This fixes a bug in dateutil <= 2.3 which prevents the use of
+ # numpy arrays in (among other things) the bymonthday, byweekday
+ # and bymonth parameters.
+ [x.item() for x in byweekday.astype(int)]
+
+ rule = rrulewrapper(DAILY, byweekday=byweekday,
+ interval=interval, **self.hms0d)
+ RRuleLocator.__init__(self, rule, tz)
class DayLocator(RRuleLocator):
@@ -1170,9 +1181,15 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
Default is to tick every day of the month: ``bymonthday=range(1,32)``
"""
if bymonthday is None:
- bymonthday = list(xrange(1, 32))
+ bymonthday = range(1, 32)
+ elif isinstance(bymonthday, np.ndarray):
+ # This fixes a bug in dateutil <= 2.3 which prevents the use of
+ # numpy arrays in (among other things) the bymonthday, byweekday
+ # and bymonth parameters.
+ bymonthday = [x.item() for x in bymonthday.astype(int)]
+
rule = rrulewrapper(DAILY, bymonthday=bymonthday,
- interval=interval, **self.hms0d)
+ interval=interval, **self.hms0d)
RRuleLocator.__init__(self, rule, tz)
@@ -1189,7 +1206,8 @@ def __init__(self, byhour=None, interval=1, tz=None):
example, if ``interval=2``, mark every second occurrence.
"""
if byhour is None:
- byhour = list(xrange(24))
+ byhour = range(24)
+
rule = rrulewrapper(HOURLY, byhour=byhour, interval=interval,
byminute=0, bysecond=0)
RRuleLocator.__init__(self, rule, tz)
@@ -1208,7 +1226,8 @@ def __init__(self, byminute=None, interval=1, tz=None):
example, if ``interval=2``, mark every second occurrence.
"""
if byminute is None:
- byminute = list(xrange(60))
+ byminute = range(60)
+
rule = rrulewrapper(MINUTELY, byminute=byminute, interval=interval,
bysecond=0)
RRuleLocator.__init__(self, rule, tz)
@@ -1228,7 +1247,8 @@ def __init__(self, bysecond=None, interval=1, tz=None):
"""
if bysecond is None:
- bysecond = list(xrange(60))
+ bysecond = range(60)
+
rule = rrulewrapper(SECONDLY, bysecond=bysecond, interval=interval)
RRuleLocator.__init__(self, rule, tz)
From ad552564d25059e283d488e014e857e8ab1cb7b1 Mon Sep 17 00:00:00 2001
From: Paul G
Date: Wed, 7 Jan 2015 15:40:03 -0600
Subject: [PATCH 23/23] Modified strftime code so it only falls back to this
other routine when necessary.
Signed-off-by: Paul G
---
lib/matplotlib/dates.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py
index 1a55bc8672a1..22fc3aa99a5a 100755
--- a/lib/matplotlib/dates.py
+++ b/lib/matplotlib/dates.py
@@ -491,9 +491,11 @@ def strftime(self, dt, fmt):
fmt = fmt.replace("%s", "s")
# strftime is not supported on datetime for years <= 1900 in Python 2.x
- # or years <= 1000 in Python 3.x
- if dt.year > 1900:
+ # or years <= 1000 in Python 3.3. Raises ValueError on failure.
+ try:
return cbook.unicode_safe(dt.strftime(fmt))
+ except ValueError:
+ pass
year = dt.year
# For every non-leap year century, advance by