Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions pandas/plotting/_matplotlib/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
from matplotlib.axis import Axis

from pandas._libs.tslibs.offsets import BaseOffset
from pandas._typing import TimeUnit


_mpl_units: dict = {} # Cache for units overwritten by us
Expand Down Expand Up @@ -1099,18 +1100,22 @@ class TimeSeries_TimedeltaFormatter(mpl.ticker.Formatter): # pyright: ignore[re
Formats the ticks along an axis controlled by a :class:`TimedeltaIndex`.
"""

def __init__(self, unit: TimeUnit = "ns"):
self.unit = unit
super().__init__()

axis: Axis

@staticmethod
def format_timedelta_ticks(x, pos, n_decimals: int) -> str:
def format_timedelta_ticks(x, pos, n_decimals: int, exp: int) -> str:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def format_timedelta_ticks(x, pos, n_decimals: int, exp: int) -> str:
def format_timedelta_ticks(x, pos, n_decimals: int, exp: int = 9) -> str:

Just in case someone would be using this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, will update

"""
Convert seconds to 'D days HH:MM:SS.F'
"""
s, ns = divmod(x, 10**9) # TODO(non-nano): this looks like it assumes ns
s, ns = divmod(x, 10**exp)
m, s = divmod(s, 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
decimals = int(ns * 10 ** (n_decimals - 9))
decimals = int(ns * 10 ** (n_decimals - exp))
s = f"{int(h):02d}:{int(m):02d}:{int(s):02d}"
if n_decimals > 0:
s += f".{decimals:0{n_decimals}d}"
Expand All @@ -1119,6 +1124,7 @@ def format_timedelta_ticks(x, pos, n_decimals: int) -> str:
return s

def __call__(self, x, pos: int | None = 0) -> str:
exp = {"ns": 9, "us": 6, "ms": 3, "s": 0}[self.unit]
(vmin, vmax) = tuple(self.axis.get_view_interval())
n_decimals = min(int(np.ceil(np.log10(100 * 10**9 / abs(vmax - vmin)))), 9)
return self.format_timedelta_ticks(x, pos, n_decimals)
n_decimals = min(int(np.ceil(np.log10(100 * 10**exp / abs(vmax - vmin)))), exp)
return self.format_timedelta_ticks(x, pos, n_decimals, exp)
2 changes: 1 addition & 1 deletion pandas/plotting/_matplotlib/timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def format_dateaxis(
subplot.format_coord = functools.partial(_format_coord, freq)

elif isinstance(index, ABCTimedeltaIndex):
subplot.xaxis.set_major_formatter(TimeSeries_TimedeltaFormatter())
subplot.xaxis.set_major_formatter(TimeSeries_TimedeltaFormatter(index.unit))
else:
raise TypeError("index type not supported")

Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/plotting/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ class TestTimeDeltaConverter:
)
def test_format_timedelta_ticks(self, x, decimal, format_expected):
tdc = converter.TimeSeries_TimedeltaFormatter
result = tdc.format_timedelta_ticks(x, pos=None, n_decimals=decimal)
result = tdc.format_timedelta_ticks(x, pos=None, n_decimals=decimal, exp=9)
assert result == format_expected

@pytest.mark.parametrize("view_interval", [(1, 2), (2, 1)])
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/plotting/test_datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -1531,7 +1531,7 @@ def test_format_timedelta_ticks_narrow(self):
assert len(result_labels) == len(expected_labels)
assert result_labels == expected_labels

def test_format_timedelta_ticks_wide(self):
def test_format_timedelta_ticks_wide(self, unit):
expected_labels = [
"00:00:00",
"1 days 03:46:40",
Expand All @@ -1544,7 +1544,7 @@ def test_format_timedelta_ticks_wide(self):
"9 days 06:13:20",
]

rng = timedelta_range("0", periods=10, freq="1 D")
rng = timedelta_range("0", periods=10, freq="1 D", unit=unit)
df = DataFrame(np.random.default_rng(2).standard_normal((len(rng), 3)), rng)
_, ax = mpl.pyplot.subplots()
ax = df.plot(fontsize=2, ax=ax)
Expand Down
Loading