Skip to content

Commit 9dfb3a1

Browse files
committed
Fixes for review comments from pandas-dev#15067.
Still need to improve unit testing.
1 parent 1f6cec8 commit 9dfb3a1

File tree

4 files changed

+36
-9
lines changed

4 files changed

+36
-9
lines changed

doc/source/visualization.rst

+10
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,16 @@ in ``pandas.plot_params`` can be used in a `with statement`:
12451245
12461246
plt.close('all')
12471247
1248+
Automatic Date Tick Adjustment
1249+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1250+
1251+
Especially for the ``TimedeltaIndex`` that uses native matplotlib
1252+
tick locator methods, it is useful to call the automatic
1253+
date tick adjustment from matplotlib for figures whose ticklabels overlap.
1254+
1255+
See the :meth:`autofmt_xdate <matplotlib.figure.autofmt_xdate>` method and the
1256+
`matplotlib documentation <http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure.autofmt_xdate>`__ for more.
1257+
12481258
Subplots
12491259
~~~~~~~~
12501260

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ Other enhancements
116116

117117
- ``.select_dtypes()`` now allows the string 'datetimetz' to generically select datetimes with tz (:issue:`14910`)
118118

119+
- ``pd.TimedeltaIndex`` now has a custom datetick formatter specifically designed for nanosecond level precision (:issue:`8711`)
119120

120121
.. _whatsnew_0200.api_breaking:
121122

pandas/tests/plotting/test_datetimelike.py

+17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pandas import Index, Series, DataFrame
88

99
from pandas.tseries.index import date_range, bdate_range
10+
from pandas.tseries.tdi import timedelta_range
1011
from pandas.tseries.offsets import DateOffset
1112
from pandas.tseries.period import period_range, Period, PeriodIndex
1213
from pandas.tseries.resample import DatetimeIndex
@@ -1271,6 +1272,22 @@ def test_plot_outofbounds_datetime(self):
12711272
values = [datetime(1677, 1, 1, 12), datetime(1677, 1, 2, 12)]
12721273
self.plt.plot(values)
12731274

1275+
def test_format_timedelta_ticks(self):
1276+
import matplotlib.pyplot as plt
1277+
rng = timedelta_range('0', periods=3, freq='ns')
1278+
df = DataFrame(np.random.randn(len(rng), 3), rng)
1279+
ax = df.plot()
1280+
plt.gcf().autofmt_xdate()
1281+
xaxis = ax.get_xaxis()
1282+
for l in xaxis.get_ticklabels():
1283+
if len(l.get_text()) > 0:
1284+
self.assertEqual(l.get_rotation(), 30)
1285+
1286+
def test_timedelta_plot(self):
1287+
# test issue #8711
1288+
s = Series(range(5), timedelta_range('1day', periods=5))
1289+
_check_plot_works(s.plot)
1290+
12741291

12751292
def _check_plot_works(f, freq=None, series=None, *args, **kwargs):
12761293
import matplotlib.pyplot as plt

pandas/tseries/plotting.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def _maybe_convert_index(ax, data):
280280
# Patch methods for subplot. Only format_dateaxis is currently used.
281281
# Do we need the rest for convenience?
282282

283-
def timeTicks(x, pos, n_decimals):
283+
def format_timedelta_ticks(x, pos, n_decimals):
284284
''' Convert seconds to 'D days HH:MM:SS.F' '''
285285
s, ns = divmod(x, 1e9)
286286
m, s = divmod(s, 60)
@@ -306,6 +306,8 @@ def format_dateaxis(subplot, freq, index):
306306
"""
307307

308308
# handle index specific formatting
309+
# Note: DatetimeIndex does not use this
310+
# interface. DatetimeIndex uses matplotlib.date directly
309311
if isinstance(index, PeriodIndex):
310312

311313
majlocator = TimeSeries_DateLocator(freq, dynamic_mode=True,
@@ -326,23 +328,20 @@ def format_dateaxis(subplot, freq, index):
326328
subplot.xaxis.set_major_formatter(majformatter)
327329
subplot.xaxis.set_minor_formatter(minformatter)
328330

331+
# x and y coord info
332+
subplot.format_coord = lambda t, y: (
333+
"t = {0} y = {1:8f}".format(Period(ordinal=int(t), freq=freq), y))
334+
329335
elif isinstance(index, TimedeltaIndex):
330336
from matplotlib import ticker
331337
(vmin, vmax) = tuple(subplot.xaxis.get_view_interval())
332338
n_decimals = int(np.ceil(np.log10(100 * 1e9 / (vmax - vmin))))
333339
if n_decimals > 9:
334340
n_decimals = 9
335341
formatter = ticker.FuncFormatter(
336-
lambda x, pos: timeTicks(x, pos, n_decimals))
342+
lambda x, pos: format_timedelta_ticks(x, pos, n_decimals))
337343
subplot.xaxis.set_major_formatter(formatter)
338344
else:
339345
raise IOError('index type not supported')
340346

341-
# Note, DatetimeIndex does not use this
342-
# interface. DatetimeIndex uses matplotlib.date directly
343-
344-
# x and y coord info
345-
subplot.format_coord = lambda t, y: (
346-
"t = {0} y = {1:8f}".format(Period(ordinal=int(t), freq=freq), y))
347-
348347
pylab.draw_if_interactive()

0 commit comments

Comments
 (0)