matplotlib / matplotlib

matplotlib: plotting with Python
https://matplotlib.org/stable/
20.17k stars 7.61k forks source link

Enable plotting of timedeltas #8869

Open dstansby opened 7 years ago

dstansby commented 7 years ago

This is a general issue to track progress in enabling the plotting of timedelta objects. The eventual aim is for code like this to work:

import matplotlib.pyplot as plt
from datetime import timedelta

x = [1, 2]
y = [timedelta(seconds=1), timedelta(seconds=2)]
fig, ax = plt.subplots()
ax.scatter(x, y)
plt.show()

TODO

anntzer commented 7 years ago

Quick question from the peanut gallery: could datetime/timedelta support be folded into unit support? (I have no idea.)

dstansby commented 7 years ago

(disclaimer: I don't really know what I'm doing with all this and am just copying datetime support and learning as I go along)

I think datetime is registered in the unit framework. The last line of dates.py is units.registry[datetime.datetime] = DateConverter() which means a datetime passed to plot automatically uses all the converter/ticker stuff in dates.py. Is that what you meant?

anntzer commented 7 years ago

I don't know anything about datetime plotting either, but the general idea was indeed whether we could end up with something like units.registry[timedelta] = TimeDeltaConverter.

has2k1 commented 7 years ago

I dealt with timedelta breaks and formats in mizani. The implementation is not the cleanest but I have been satisfied with the results.

pganssle commented 7 years ago

Is there something somewhere that details how unit support is handled? Folding timedelta directly into datetime seems weird - it seems like it would enable you to do things like plt.plot([timedelta(days=200), datetime(1970, 11, 14)], [0, 1])? Seems like you'd want to be kinda explicit about when you can use timedelta and when you can use datetime.

That said, we're essentially never explicit about when you can use "meters" vs. "delta-meters", so maybe my concerns are a bit overblown? I guess it feels weirder because numbers are mostly unitless and these have explicit, non-interchangeable units.

dstansby commented 7 years ago

Thanks for all your comments @pganssle!

I think there are two cases that I've probably accidentally folded into one here:

  1. Plotting timedelta objects
  2. Plotting datetime objects that need some sort of offsetting with timedelta (ie. plotting a square

In case number 2., offsetting should be done before any conversion to internal representations, such that only datetime coordinates are ever plotted, and none of the converting timedelta machinery is needed.

Case 1. is what should be tackled by this issue, and as is said above, we need to be very careful to keep the two cases distinct, and error when a code snippet like above (https://github.com/matplotlib/matplotlib/issues/8869#issuecomment-323498027) is run.

pganssle commented 7 years ago

@dstansby Yes, I think with these concerns cleanly separated, implementing timedelta handling becomes much easier, too. Other than the question of formatting (and if you have any references on timedelta formatting I'd like to implement that in dateutil, so I'm interested in what's the "best way"), so long as the units are being enforced, it's just timedelta.total_seconds(), none of the complicated nonsense about time zones and the like, since timedelta() by its nature represents a duration.

dstansby commented 7 years ago

Great, will put a comment on that issue about timedelta formatting. Would be much better to have it somewhere in dateutil than for us to roll our own version.

dstansby commented 7 years ago

Was easier to just open a new PR at #9120

dstansby commented 7 years ago

Woops, that comment was meant for the PR!

github-actions[bot] commented 1 year ago

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

jklymak commented 1 year ago

We've tried this a few times - but after thinking about it for a few years I'm not sure we want or need this.

timedelta are just integers or floats with a unit attached.

dt = np.array([1, 20, 30], dtype='timedelta64[s]')
ax.plot(dt)

works fine as-is.

For datetime.timedelta we would need to convert to float:

dt0 = [datetime.timedelta(seconds=i) for i in [1, 20, 30]]
dt = [d.total_seconds() for d in dt0]
ax.plot(dt)

Personally I'm OK with datetime.timedelta being a second-class citizen. If we wanted to have a really light converter for it that just converted the values to float for the user, but otherwise didn't change the Locators and Formatters, that would probably be OK too.

The ideas in #19236 were that we would use datetime-like Formatters and Locators to the timedeltas, but I'm no longer convinced that this is a good idea. If someone really wants time, they can add an origin datetime to each timedelta, either when their experiment started, or a nominal date and pass to our datetime converter.

github-actions[bot] commented 5 months ago

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!