Skip to content
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

Fix add_bounds() breaking when time coords are cftime objects #241

Merged
merged 4 commits into from
May 27, 2022

Conversation

tomvothecoder
Copy link
Collaborator

@tomvothecoder tomvothecoder commented May 26, 2022

Description

Summary of Changes

  • Fix add_bounds() breaking when time coords are cftime objects
  • Remove ds as a keyword arg for TemporalAccessor.center_times() to allow for standalone usage
  • Update tests in test_temporal.py with masked data

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes generate no new warnings -- I added a warning filter for a pd.PerformanceWarning. There is a #FIXME comment to address this in the future.
  • Any dependent changes have been merged and published in downstream modules

If applicable:

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass with my changes (locally and CI/CD build)
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have noted that this is a breaking change for a major release (fix or feature that would cause existing functionality to not work as expected)

- Remove `dataset` param from  `TemporalAccessor.center_times()` to allow for standalone usage
- Update names of tests for private functions in `test_dataset.py`
@tomvothecoder tomvothecoder added type: bug Inconsistencies or issues which will cause an issue or problem for users or implementors. Priority: Critical labels May 26, 2022
@tomvothecoder tomvothecoder self-assigned this May 26, 2022
@tomvothecoder tomvothecoder added this to In progress in v0.3.0 via automation May 26, 2022
xcdat/bounds.py Outdated
Comment on lines 258 to 282
# Add beginning and end points to account for lower and upper bounds.
# np.array of string values with `dtype="timedelta64[ns]"`
diffs = np.insert(diffs, 0, diffs[0])
diffs = np.append(diffs, diffs[-1])

# Get lower and upper bounds by using the width relative to nearest point.
# Transpose both bound arrays into a 2D array.
lower_bounds = da_coord - diffs[:-1] * width
upper_bounds = da_coord + diffs[1:] * (1 - width)
# In xarray and xCDAT, time coordinates with non-CF compliant calendars
# (360-day, noleap) and/or units ("months", "years") are decoded using
# `cftime` objects instead of `datetime` objects. `cftime` objects only
# support arithmetic using `timedelta` objects, so the values of `diffs`
# must be casted from `dtype="timedelta64[ns]"` to `timedelta`.
if da_coord.name in ("T", "time") and issubclass(
type(da_coord.values[0]), cftime.datetime
):
diffs = pd.to_timedelta(diffs)

# FIXME: These lines produces the warning: `PerformanceWarning:
# Adding/subtracting object-dtype array to TimedeltaArray not
# vectorized` after converting diffs to `timedelta`. I (Tom) was not
# able to find an alternative, vectorized solution at the time of this
# implementation.
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=pd.errors.PerformanceWarning)
lower_bounds = da_coord - diffs[:-1] * width
upper_bounds = da_coord + diffs[1:] * (1 - width)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The primary code change

if hasattr(self, "_time_bounds") is False:
self._time_bounds = ds.bounds.get_bounds("time")
ds = self._dataset.copy()
time_bounds = ds.bounds.get_bounds("time")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This update to center_times() makes it callable as a standalone method, instead of having to pass a dataset object to it. (from ds.temporal.center_times(ds) to ds.temporal.center_times())

@tomvothecoder tomvothecoder marked this pull request as ready for review May 27, 2022 17:57
@codecov-commenter
Copy link

codecov-commenter commented May 27, 2022

Codecov Report

Merging #241 (ab5a986) into main (1fdc8a9) will not change coverage.
The diff coverage is 100.00%.

@@            Coverage Diff            @@
##              main      #241   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            9         8    -1     
  Lines          742       728   -14     
=========================================
- Hits           742       728   -14     
Impacted Files Coverage Δ
xcdat/axis.py 100.00% <ø> (ø)
xcdat/utils.py 100.00% <ø> (ø)
xcdat/__init__.py 100.00% <100.00%> (ø)
xcdat/bounds.py 100.00% <100.00%> (ø)
xcdat/dataset.py 100.00% <100.00%> (ø)
xcdat/spatial.py 100.00% <100.00%> (ø)
xcdat/temporal.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 112eb58...ab5a986. Read the comment docs.

@tomvothecoder tomvothecoder merged commit 6eb1bf2 into main May 27, 2022
v0.3.0 automation moved this from In progress to Done May 27, 2022
@tomvothecoder tomvothecoder deleted the bugfix/240-cftime-bounds branch May 27, 2022 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Inconsistencies or issues which will cause an issue or problem for users or implementors.
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

[Bug]: add_bounds() breaks when time coordinates are in cftime objects instead of datetime
2 participants