Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 70ebfcd

Browse files
committed
Add timedelta formatter
Fix whitespace
1 parent 0e104e5 commit 70ebfcd

File tree

2 files changed

+95
-1
lines changed

2 files changed

+95
-1
lines changed

lib/matplotlib/dates.py

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@
118118
import time
119119
import math
120120
import datetime
121+
import string
121122

122123
import warnings
123124

124-
125125
from dateutil.rrule import (rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY,
126126
MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY,
127127
SECONDLY)
@@ -217,6 +217,9 @@ def _to_ordinalf(dt):
217217
dt = dt.astimezone(UTC)
218218
tzi = UTC
219219

220+
if isinstance(dt, datetime.timedelta):
221+
return dt.total_seconds() / SEC_PER_DAY
222+
220223
base = float(dt.toordinal())
221224

222225
# If it's sufficiently datetime-like, it will have a `date()` method
@@ -605,6 +608,82 @@ def strftime(self, dt, fmt=None):
605608
return self.strftime_pre_1900(dt, fmt)
606609

607610

611+
class TimedeltaFormatter(ticker.Formatter):
612+
613+
def __init__(self, fmt):
614+
r"""
615+
*fmt* is a format string, with accepted format arguments given in the
616+
table below. For more information on format strings see
617+
https://docs.python.org/3/library/string.html#format-string-syntax
618+
619+
.. table:: Accepted format arguments
620+
:widths: auto
621+
622+
======== =======
623+
Argument Meaning
624+
======== =======
625+
{D} Days
626+
{H} Hours
627+
{M} Minutes
628+
{S} Seconds
629+
{f} Microseconds
630+
========= =======
631+
632+
Examples
633+
--------
634+
>>> from datetime import timedelta
635+
>>> from matplotlib.dates import TimedeltaFormatter
636+
>>>
637+
>>> dt = timedelta(hours=1, minutes=0, seconds=3)
638+
>>> fmt = '{H:02}:{M:02}:{S:02}'
639+
>>> formatter = TimedeltaFormatter(fmt)
640+
>>> formatter(dt)
641+
01:00:03
642+
>>>
643+
>>> fmt = '{S}'
644+
>>> formatter = TimedeltaFormatter(fmt)
645+
>>> formatter(dt)
646+
3603
647+
>>>
648+
>>> fmt = '{S}'
649+
>>> dt = timedelta(microseconds=1e5)
650+
>>> formatter(dt)
651+
0.1
652+
"""
653+
self.fmt = fmt
654+
655+
def __call__(self, x):
656+
dt = num2timedelta(x)
657+
return self._strfdelta(dt)
658+
659+
def _strfdelta(self, dt):
660+
# A custom method to format timedelta objects. See above for examples
661+
formatter = string.Formatter()
662+
d = {}
663+
allkeys = ['D', 'H', 'M', 'S', 'f']
664+
secs = [SEC_PER_DAY, SEC_PER_HOUR, SEC_PER_MIN, 1, 1 / 1e6]
665+
# Get list of all keys in the format string
666+
keys = list(map(lambda x: x[1], list(formatter.parse(self.fmt))))
667+
668+
rem = dt.total_seconds()
669+
# Cycle through all keys, and if key present in format calculate value
670+
# of that key
671+
for key, seconds in zip(allkeys, secs):
672+
if key in keys:
673+
d[key] = rem / seconds
674+
_, rem = divmod(rem, seconds)
675+
676+
# Cycle through and round every entry down to an int APART from the
677+
# smallest unit present in format
678+
foundlast = False
679+
for key in allkeys[::-1]:
680+
if key in keys:
681+
if foundlast or key == 'f':
682+
d[key] = int(np.floor(d[key]))
683+
foundlast = True
684+
return formatter.format(self.fmt, **d)
685+
686+
608687
class IndexDateFormatter(ticker.Formatter):
609688
"""
610689
Use with :class:`~matplotlib.ticker.IndexLocator` to cycle format

lib/matplotlib/tests/test_dates.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,3 +466,18 @@ def test_tz_utc():
466466
def test_num2timedelta(x, tdelta):
467467
dt = mdates.num2timedelta(x)
468468
assert dt == tdelta
469+
470+
471+
@pytest.mark.parametrize('dt, fmt, out',
472+
[(datetime.timedelta(days=8, hours=1, minutes=2,
473+
seconds=3, microseconds=4),
474+
'{D}d {H:02}:{M:02}:{S:02}.{f:06}',
475+
'8d 01:02:03.000004'),
476+
(datetime.timedelta(seconds=1), '{f}', '1000000'),
477+
(datetime.timedelta(microseconds=1e5), '{S}', '0.1'),
478+
])
479+
def test_TimedeltaFormatter(dt, fmt, out):
480+
formatter = mdates.TimedeltaFormatter(fmt)
481+
x = mdates.date2num(dt)
482+
formatted = formatter(x)
483+
assert formatted == out

0 commit comments

Comments
 (0)