I am trying to plot data with a pandas time delta index with negative time delta values on the x-axis using hvplot or holoviews (bokeh backend).
The labels are just integers, and seem to be in milliseconds.
I want them to be formatted in a friendlier format such as HH:MM:SS
import pandas as pd
import numpy as np
import hvplot.pandas
x = pd.timedelta_range(start=0, freq='S', periods=11) - pd.Timedelta('5S')
y = np.arange(len(x))
df = pd.DataFrame({'y': y}, index=x)
df.hvplot.line(rot=20)
Output:
I expected the x axis to be -00:00:04 -00:00:04 00:00:00 00:00:02 00:00:04
or at least in seconds, this seems to be milliseconds.
using the df create above:
from bokeh.models.formatters import NumeralTickFormatter
df.hvplot.line(xformatter=NumeralTickFormatter(format="00:00:00"), rot=20)
Output: Idk what happened here with the xlabels but they dont really make any sense.
Using DatetimeTickFormatter:
from bokeh.models.formatters import DatetimeTickFormatter
df.hvplot.line(rot=20, xformatter=DatetimeTickFormatter())
Does not work unfortunatelt: No negative values: - 00:00:02 becomes 58s
I found a solution, it is not pretty but it works
(Using the earlier created dataframe):
def timedelta_formatter(x):
x/=1000 # ms -> seconds
# extract seconds, minutes, hours, days from time
m, s = divmod(abs(x), 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
# create output string with time format
out = f"{d}d. {h:02}:{m:02}:{s:02}"
if x < 0:
# add - if negative value
return "- " + out
else:
return out
df.hvplot.line(xformatter=timedelta_formatter, rot=20)
This looks better!
Lets try it with a timedelta range in days:
x = pd.timedelta_range(start=0, freq='D', periods=11) - pd.Timedelta('5D')
y = np.arange(len(x))
df = pd.DataFrame({'y': y}, index=x)
df.hvplot.line(xformatter=timedelta_formatter, rot=20)
Works too
I still think this is not the most elegant solution,
so open to hear better solutions