-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow for plotting dummy netCDF4.datetime objects. #1261
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
Allow for plotting dummy netCDF4.datetime objects. #1261
Conversation
Does matplotlib actually plot netcdftime datetimes correctly? It would be nice to have a unit test to verify this works. See xarray/tests/test_plot.py for examples. |
Failing tests:
All of these check strings as input to the plot functions and expect a
A possible way out would be to check for numeric types and datetime-like types separately. |
xarray/plot/plot.py
Outdated
@@ -32,7 +32,9 @@ def _ensure_plottable(*args): | |||
Raise exception if there is anything in args that can't be plotted on | |||
an axis. | |||
""" | |||
plottypes = [np.floating, np.integer, np.timedelta64, np.datetime64] | |||
from netCDF4 import datetime as nc4datetime |
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.
This needs to be guarded behind a try/except clause, because netCDF4 is not a required dependency of xarray. Use from netcdftime import datetime
instead of netCDF4 (@jhamman is moving netcdftime to its own package). Also, put import statements at the top of the file.
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.
What should I do to prevent netcdftime.datetime
to be understood as numpy.generic
? Rewrite xarray.plot._ensure_plottable
to handle Numpy types and netcdftime.datetime
separately?
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.
Yes, looks like we need a separate check for object dtype arrays (it's okay to loop over element).
Yes it does. They are just treated like |
|
I was wrong here: And matplotlib fails on the latter: https://gist.github.com/willirath/48c04db0481e986fac0e44549e164ab0 |
Allow for numeric and date-like numpy data types and for datetime objects.
|
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.
This looks good to me, though note that it's difficult to get datetime
objects into xarray objects -- normally they are converted into datetime64
.
xarray/plot/plot.py
Outdated
# Warn then. | ||
for t in numpy_types: | ||
if np.issubdtype(np.generic, t): | ||
warnings.warn('{} is treated as numpy.generic.'.format(t), |
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.
This is an internal, private function. Rather than warning let's issue a ValueError
to ensure it doesn't happen by accident. It would also be safe to just use an assert
here, since again it should never happen in user 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.
Thanks for the review! I've changed it using assert
.
xarray/tests/test_plot.py
Outdated
@@ -1208,3 +1213,25 @@ def test_default_labels(self): | |||
# Top row should be labeled | |||
for label, ax in zip(self.darray.coords['col'].values, g.axes[0, :]): | |||
self.assertTrue(substring_in_axes(label, ax)) | |||
|
|||
|
|||
@requires_netCDF4 |
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.
This test shouldn't be netCDF4 specific anymore.
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.
That's right. I've changed it to use datetime
and to not require netCDF4
.
xarray/tests/test_plot.py
Outdated
|
||
darray = DataArray(data, dims=['time']) | ||
darray.coords['time'] = \ | ||
np.array([nc4datetime(2017, m, 1) for m in month]) |
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.
Again, just use a normal datetime
instance now.
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.
Done.
xarray/tests/test_plot.py
Outdated
data = np.sin(2 * np.pi * month / 12.0) | ||
|
||
darray = DataArray(data, dims=['time']) | ||
darray.coords['time'] = \ |
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.
style: avoid \
in favor of implicit line continuation with parentheses: https://www.python.org/dev/peps/pep-0008/#maximum-line-length
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.
Done.
- Use datetime instead of netCDF4.datetime. - Do not warn but assert in private function.
Yes, I know that xarray usually doesn't use My last commit reflects what I'd consider ready to be pulled. Let me know what you think. |
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.
Oops -- meant to post this yesterday but didn't hit submit on the review. Two minor suggestions, otherwise looks good to me.
xarray/plot/plot.py
Outdated
""" | ||
plottypes = [np.floating, np.integer, np.timedelta64, np.datetime64] | ||
return all(any(isinstance(el, t) for t in types) | ||
for el in np.ravel(x)) |
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.
style: the line continuation here should start after the open parenthesis after all
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.
Done. (Line was 79 chars long anyway.)
|
||
for x in args: | ||
if not (_valid_numpy_subdtype(np.array(x), numpy_types) | ||
or _valid_other_type(np.array(x), other_types)): |
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.
Probably would be a good idea to ensure that x
has object dtype (either here or in _valid_other_type
) to avoid potential expensive loops, e.g., if dtype=complex
but x
is a very large.
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've added a check to _valid_other_type
which ensures np.issubdtype(np.generic, x.dtype)
before looping over x
. (See feb6afb)
Thanks! |
Currently, xarray/plot.py raises a
TypeError
if the data to be plotted are not among[np.floating, np.integer, np.timedelta64, np.datetime64]
.This PR adds
netCDF4.datetime
objects to the list of allowed data types. These occur, because xarray/conventions.py passes undecodednetCDF4.datetime
objects if decoding tonumpy.datetime64
fails.