You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I encountered a variety of issues/suggested improvements with .isel() when starting work on #1641. I believe the way I will want to solve 1641 will involve offloading the grid indexing to .isel(), and just applying xarray's sel() to the remaining, non-grid indexers. It took me longer than expected to figure out how to get that started because the .isel() logic was confusing, and I also found a bug along the way.
This issue tracks the bug, as well as some possible ways to clean up the .isel() internal logic and improve documentation. The issue looks somewhat long but the actual corresponding changes will likely be small enough to fit reasonably into a single PR.
Bug: UxDataset.isel(..., ignore_grid=True) crash:
UxDataset.isel(..., ignore_grid=True) crashes due to failing to provide a uxgrid object.
Similar code does not crash from UxDataArray.isel() instead, e.g. put ds['psi'].isel(...) in the examples above and there is no issue.
Cleanup: confusing logic and redundant error message handling
Right now the internal logic of UxDataArray.isel() and UxDataset.isel() looks something like this:
indexers, grid_dims=_validate_indexers(...) # grid_dims means "grid dims being indexed"try: # this try.. except error handling exists in UxDataArray.isel but not UxDataset.iselifnotignore_grid:
iflen(grid_dims) ==1:
applytheonegriddimindexertoboththegridandthedataapplyanyremainingindexerstothedataconstructresultusingsliceddataandslicedgrid# (P0)else:
constructresultusingsliceddataandoriginalgrid# (P1)else:
constructresultusingsliceddataandoriginalgrid# (P2)exceptValueErroraserr:
iferrlookslikeadimension-relatederror:
raiseDimensionError(str(err) +highly_redundant_addition_to_error_message) fromerrelse:
raise
I would suggest these improvements:
Restructure the if..else checks slightly to remove the need for repeating the P1 code at P2.
Clarify: at P1, why should we use the original, unsliced grid when len(grid_dims)>1 and not ignore_grid? (The answer is: it turns out the len(grid_dims)>1 case is actually handled by crashing in _validate_indexers. This wasn't obvious originally. I think there should be a comment and/or assert statement to clarify.)
Remove the error handling logic entirely from UxDataArray.isel(), making its behavior consistent with UxDataset.isel(). Allow xarray to raise its own messages; the addition to the message here was not adding anything, and the upcasting to DimensionError was introduced extremely recently (see Add custom error types in uxarray #1621). To clarify, the highly redundant addition was something like ". Available dimensions: ('n_face', 'time', 'lev')" being appended to an error message which already looked like "Dimensions {'badnonexistentdim'} do not exist. Expected one of ('n_face', 'time', 'lev')"
Docstring improvements
I would suggest these improvements to the docstrings of UxDataArray.isel() and UxDataset.isel() methods:
Improve consistency: both isel() docstrings should be more consistent with each other. E.g., use the same exact text for describing how missing_dims="ignore" behaves. Additionally, both isel() docstrings should be more consistent with their xarray.DataArray and xarray.Dataset counterparts, where appropriate.
Clarify a very cool feature which I didn't know about until digging into this: you can .isel() along any grid dimension, regardless of where the data is currently located. E.g., even if the data has "n_face" dim, you can .isel(n_edge=7) to get a result with "n_face" dim, containing only the two faces touching edge 7.
Further clarify the ignore_grid behavior and put a much clearer note/flag that using ignore_grid=True will cause the result's data to no longer live on the result's uxgrid; they will be desynched, if any grid dims were sliced.
I encountered a variety of issues/suggested improvements with
.isel()when starting work on #1641. I believe the way I will want to solve 1641 will involve offloading the grid indexing to.isel(), and just applying xarray's sel() to the remaining, non-grid indexers. It took me longer than expected to figure out how to get that started because the.isel()logic was confusing, and I also found a bug along the way.This issue tracks the bug, as well as some possible ways to clean up the
.isel()internal logic and improve documentation. The issue looks somewhat long but the actual corresponding changes will likely be small enough to fit reasonably into a single PR.Bug:
UxDataset.isel(..., ignore_grid=True)crash:UxDataset.isel(..., ignore_grid=True)crashes due to failing to provide a uxgrid object.Example:
Similar code does not crash from UxDataArray.isel() instead, e.g. put
ds['psi'].isel(...)in the examples above and there is no issue.Cleanup: confusing logic and redundant error message handling
Right now the internal logic of
UxDataArray.isel()andUxDataset.isel()looks something like this:I would suggest these improvements:
len(grid_dims)>1 and not ignore_grid? (The answer is: it turns out thelen(grid_dims)>1case is actually handled by crashing in_validate_indexers. This wasn't obvious originally. I think there should be a comment and/or assert statement to clarify.)". Available dimensions: ('n_face', 'time', 'lev')"being appended to an error message which already looked like"Dimensions {'badnonexistentdim'} do not exist. Expected one of ('n_face', 'time', 'lev')"Docstring improvements
I would suggest these improvements to the docstrings of
UxDataArray.isel()andUxDataset.isel()methods:missing_dims="ignore"behaves. Additionally, both isel() docstrings should be more consistent with their xarray.DataArray and xarray.Dataset counterparts, where appropriate..isel()along any grid dimension, regardless of where the data is currently located. E.g., even if the data has "n_face" dim, you can.isel(n_edge=7)to get a result with "n_face" dim, containing only the two faces touching edge 7.ignore_gridbehavior and put a much clearer note/flag that usingignore_grid=Truewill cause the result's data to no longer live on the result's uxgrid; they will be desynched, if any grid dims were sliced.