-
Notifications
You must be signed in to change notification settings - Fork 416
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
Systematic Coordinate Identification #871
Conversation
metpy/xarray.py
Outdated
@staticmethod | ||
def _check_vertical(var): | ||
# Check for standard name (CF option) | ||
if var.attrs.get('standard_name') in {'air_pressure', 'height', 'geopotential_height', |
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.
level
is pretty common too I 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.
Is that part of CF?
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 wasn't able to find level
in the standard name table, but I did find model_level_number
, which could be good to add.
Also, there's an appendix in the CF conventions with a number of additional vertical coordinate standard names...should I include those as well?
metpy/xarray.py
Outdated
def _fixup_coordinate_map(coord_map, var): | ||
"""Ensure sure we have coordinate variables in map, not coordinate names.""" | ||
for axis in coord_map: | ||
if type(coord_map[axis]) == str: |
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 more standard to use if isinstance(coord_map[axis], str):
One thing I've been thinking about as I work through applications of this...right now, using this (for example, to iterate over levels) would look something like temperature = data.parse_cf('Temperature_isobaric')
for level in temperature.metpy.vertical:
temperature_at_level = temperature[temperature.metpy.vertical == level] This could get verbose rather quickly with lots of calls to the coordinate variables. Would it be worth replacing and/or supplementing it with something like this? temperature = data.parse_cf('Temperature_isobaric')
x, y, vertical = rh.coordinate_map('x', 'y', 'vertical')
for level in vertical:
temperature_at_level = temperature[vertical == level] (this should be fairly straightforward to implement as a wrapper for what I now have as |
I'm in favor of that - maybe spell it as just |
@jrleeman I've added it in addition to the properties for now, but let me know if it is better as a replacement. |
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.
A few minor things - a more in-depth review is next
metpy/xarray.py
Outdated
@xr.register_dataarray_accessor('metpy') | ||
class MetPyAccessor(object): | ||
"""Provide custom attributes and methods on XArray DataArray for MetPy functionality.""" | ||
|
||
nice_to_cf_axis_map = {'time': 'T', 'vertical': 'Z', 'y': 'Y', 'x': '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.
A nit, but I'd probably call this something like readable_to_cf_names
or similar. I've started trying to avoid map
as part of variable names as it sometimes is redundant or even confusing in some contexts.
metpy/xarray.py
Outdated
for coord_var in self._data_array.coords.values(): | ||
if coord_var.attrs.get('axis') == self.nice_to_cf_axis_map[axis]: | ||
return coord_var | ||
raise AttributeError(axis + ' attribute is not available due to lack of ' + |
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.
Could probably stop after not available.
metpy/xarray.py
Outdated
@staticmethod | ||
def _check_vertical(var): | ||
# Check for standard name (CF option) | ||
if var.attrs.get('standard_name') in {'air_pressure', 'height', 'geopotential_height', |
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.
Is that part of CF?
@jrleeman Some notes about the changes I've made based on our discussions:
|
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'm happy after this refactor - I think we're in good shape now, but let's get @dopplershift to weigh in today and then test time!
Unless @dopplershift has issues, I'd say lets get this in ASAP. |
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.
In general, I'm ready for this to go in. Just a couple minor things. This xarray tutorial will be an especially nice addition.
metpy/tests/test_xarray.py
Outdated
def test_bad_coordinate_type(test_var): | ||
"""Test that an AttributeError is raised when a bad axis/coordinate type is given.""" | ||
with pytest.raises(AttributeError) as exc: | ||
axis, = test_var.metpy.coordinates('bad_axis_type') |
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.
You can just call the function here, no need to do anything with the return value, so just:
test_var.metpy.coordinates('bad_axis_type')
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 had tried that, but because the coordinates
method is a generator function, I needed to assign it in order for the underlying function to run and raise the error. Is there a better way around this?
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.
Ah, generator. You could wrap the call in next(...)
.
tutorials/xarray_tutorial.py
Outdated
# | ||
# Additionally, we take a few optional steps to clean up our dataset for later use: | ||
# | ||
# - Drop the extra grid mapping variable since we have already parsed that information |
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'm not clear on why we're going to the effort of dropping a variable. Does it help with printing or something?
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.
Good point...I was being over-zealous in my clean up of the Dataset.
Adds coordinate mapping utilities to the Dataset accessor, and uses them in `parse_cf` to relabel the `axis` attributes appropriately. Then, adds in methods to the DataArray accessor so that the spatiotemporal coordinates can be easily accessed.
This commit adds a new tutorial to demonstrate the extent of MetPy's xarray integration, and how to perform basic operations. This tutorial should be kept up to date as integration with xarray improves.
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.
Pending CI.
Just after this was merged, I discovered a cleaner way of checking the equality of |
If it's not terribly time-consuming I'd say a follow-on PR would be good. |
A first cut at implementing #860, this implements systematic coordinate mapping utilities to the
Dataset
accessor according to CF standards/recommendations/options and uses those to assign appropriateaxis
attributes to the coordinates inparse_cf
. This also adds some properties to theDataArray
accessor to obtain easy access to the coordinates corresponding to a particular axis.This PR is a work is progress, but I wanted to get it out there to run it by the checks, and to get some initial feedback. Once the initial implementation of everything (roughly) looks good, I plan on working on tests.
(Also, @dopplershift and @jrleeman, for now, I decided to go with
vertical
instead oflevel
orlevels
, andtime
instead oftimes
, as those seemed more natural as I was working through it.)