1

I don't understand how I use and format a timedelta axis properly in matplotlib.

For example, for the following code

import pandas as pd # for plot generation
import matplotlib.pyplot as plt

index = pd.timedelta_range(timedelta(days=0), timedelta(days=30), freq='H', closed='right')
s = pd.Series(range(0, 720), index=index)

fig, ax = plt.subplots(figsize=(5, 5))

s.plot(ax=ax)

I get the plot

enter image description here

But obviously, the tick positions and the labels are useless and not in a meaningful distance (e.g., one day). I could not find in documentation how to deal with timedelta. Related questions ([1] or [2]) describe how to format the string but don't seem to handle the ticks layout.

How can I specify the ticks and the labels? For example, major ticks to days, minor ticks to hours with a proper label?

I also wonder if there is a simple, clean, pythonic solution. I mean timedelta in plots isn't that rare, is it? :)

Stef
  • 28,728
  • 2
  • 24
  • 52
Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
  • Why is it square when the graph size is (15,5)? – r-beginners Nov 02 '22 at 13:40
  • Copy-paste mistake. Sorry, fixed. :) – Michael Dorner Nov 02 '22 at 13:44
  • 3
    Matplotlib has no specific support for timedelta formatters and locators (you examples uses *pandas'* TimedeltaFormatter). You might be interested in [Timple](https://github.com/theOehrly/Timple). – Stef Nov 02 '22 at 14:06
  • 1
    if you know in advance that your index comprises a range of say 30 days (as in the example), you could also just use `ax.plot(s.index/datetime.timedelta(days=1), s)` to plot over the number of days and label the axis as "time in days" or use a string formatter to put a "d" after each number. – Stef Nov 02 '22 at 14:38
  • From matplotlib documentation: [Date tick labels](https://matplotlib.org/stable/gallery/text_labels_and_annotations/date.html) – paime Nov 02 '22 at 15:01
  • @paime I don't think date tick labels work for timedeltas. I tried `"%H:%M"` in my case and it raised `OverflowError: int too big to convert`. – Bill Aug 22 '23 at 16:49
  • Looks to me like Pandas provides its own tick formatter for time deltas, [`TimeSeries_TimedeltaFormatter‎`](https://github.com/pandas-dev/pandas/blob/0fc36add581e6647e2cc89cf3a6db16480037dc9/pandas/plotting/_matplotlib/converter.py#L1080). I'm not an expert but looking at the code it seems to only support the standard format `'D days HH:MM:SS.F'`. (Pandas 2.0.3). – Bill Aug 22 '23 at 17:01

1 Answers1

1

Here is a workaround. It doesn't change the label formatting but reduces the number of ticks and labels so at least you can see them.

I figured out that the pandas TimeSeries_TimedeltaFormatter‎ is based on integers representing 1e-9 seconds.

You can figure this out using the following:

x_ticks = ax.get_xticks()
print(x_ticks)

Output:

[0.0e+00 5.0e+14 1.0e+15 1.5e+15 2.0e+15 2.5e+15 3.0e+15]

Big numbers!

So let's say you want to reduce the number of ticks and labels to show only one every 15 days.

Then use this:

index = pd.timedelta_range(
    pd.Timedelta(days=0), 
    pd.Timedelta(days=30),
    freq='H', closed='right'
)
s = pd.Series(range(0, 720), index=index)

fig, ax = plt.subplots(figsize=(5, 5))

s.plot(ax=ax)

one_day = 1e9 * 60 * 60 * 24
ax.set_xticks(one_day * np.linspace(0, 30, 3))

plt.tight_layout()
plt.show()

enter image description here

Bill
  • 10,323
  • 10
  • 62
  • 85