-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
ENH: support np.datenum64 in dates.py #9779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
lib/matplotlib/dates.py
Outdated
@@ -211,36 +211,58 @@ def _get_rc_timezone(): | |||
WEEKDAYS = (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) | |||
|
|||
|
|||
def _to_ordinalf(dt): | |||
def _to_ordinalf(dts): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably worth writing a new function called something like _dtime64_to_ordinalf(dts)
with the new code to handle np.datetime64
s. (for clarity)
xref #9610 |
The normal use case would be with an ndarray of dtype np.datetime64. The conversion of this to matplotlib float datenums should be direct and vectorized--no loop--otherwise the performance will be terrible. |
lib/matplotlib/dates.py
Outdated
@@ -1183,9 +1209,8 @@ def get_locator(self, dmin, dmax): | |||
|
|||
locator.set_axis(self.axis) | |||
|
|||
if self.axis is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooops, I guess I missed a rebase here. Will fix after
ec3ec37
to
a32aa1b
Compare
lib/matplotlib/dates.py
Outdated
zerod = False | ||
if isinstance(d, np.datetime64): | ||
zerod = True | ||
d = np.atleast_1d(d) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It runs for me without converting a single item into array and back. This is needed for some older numpy (mine is 1.13.3
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, I didn't even try! You're right..
lib/matplotlib/dates.py
Outdated
d = np.atleast_1d(d) | ||
extra = d - d.astype('datetime64[s]') | ||
extra = extra.astype('timedelta64[ns]') | ||
t0 = np.datetime64('0001-01-01T00:00:00').astype('datetime64[s]') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t0 = np.datetime64('0001-01-01T00:00:00', 's')
@@ -22,6 +23,52 @@ | |||
import matplotlib.dates as mdates | |||
|
|||
|
|||
def test_date_numpyx(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason this isn't done with base/time/timenp being pytest fixtures and the test parameterized or split into two?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I can understand this, and I have no idea what a pytest fixture is. Is there an advantage to doing something more obscure than a simple assert
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only cause you're repeating yourself a lot so it's hard to tell what the specific tests are. Factoring out common features into a fixture means you can make two tests that are uniquely named for the things they're testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into it. OTOH, I find some of the tests aren't very easy to follow. Sometime verbosity is a good thing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, happy to take suggestions, but I find the uses of fixtures in the existing tests makes for pretty obfuscated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shrugs can agree on that somewhat, either way it's not something I'd hold the PR up on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I didn't mean to say I wasn't willing to learn, just that I don't get it... More than happy if you wanted to push a change or give me some pseudo code to get it to work... Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for missing your reply (the embedded ones seem to not pop up as notifications), and will totally try to remember your suggestion for the future. I should have been way clearer on what I wanted and given you an example. :/
lib/matplotlib/tests/test_dates.py
Outdated
assert np.array_equal(h.get_ydata(orig=False), hnp.get_ydata(orig=False)) | ||
|
||
|
||
def test_date_date2num_numpy(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, could this be parameterized with ids?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sympathise with @jklymak re. pytest, (I still have no idea what a fixture is) but find paramaterising fairly easy to understand (https://docs.pytest.org/en/latest/parametrize.html)
Something like this should work:
@pytest.mark.parametrize('t0', [datetime.datetime(2017, 1, 1, 0, 1, 1),
[datetime.datetime(2017, 1, 1, 0, 1, 1),
datetime.datetime(2017, 1, 1, 1, 1, 1)],
[[datetime.datetime(2017, 1, 1, 0, 1, 1),
datetime.datetime(2017, 1, 1, 1, 1, 1)],
[datetime.datetime(2017, 1, 1, 2, 1, 1),
datetime.datetime(2017, 1, 1, 3, 1, 1)]]])
@pytest.mark.parameterize('dtype', ['datetime64[s]',
'datetime64[us]',
'datetime64[ms]'])
def test_date_numpyx(t0, dytpe):
time = mdates.date2num(t0)
tnp = np.array(t0, dtype=dtype)
nptime = mdates.date2num(tnp)
assert time == nptime
This will run through every possible combination of t0
and dtype
, and avoids copy/pasting the actual testing code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I agree that parametrize works well here (despite pytests odd way of spelling it) Thanks for the example!
3d18de8
to
7126295
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Looks good to me, thanks a lot for squashing this long running bug! I'm happy to tidy up the tests if you want @jklymak?
7126295
to
109acc1
Compare
That was easier than I expected... |
Could someone open up a follow-on PR to add a whats_new about this? |
Oops sorry I’ll do so tonight and prob add an example as well. |
PR Summary
This allows
numpy.datetime64
dates. New and improved!works fine.
PR Checklist