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

Add better support for using custom time coordinates in temporal APIs #415

Merged
merged 4 commits into from
Feb 13, 2023

Conversation

tomvothecoder
Copy link
Collaborator

@tomvothecoder tomvothecoder commented Feb 8, 2023

Description

Summary of Changes

  • Update check for decoded time and calendar attr in TemporalAccessor
    • We determine if time is decoded by checking the type of the first time coordinate
    • If no calendar attr is set, calendar is defaulted to "standard" and a logger warning is raised (instead of a KeyError). Calendar is required for determining the cftime.datetime object type and checking if leap days should be dropped for high freq climatology/departures calculations.
  • Update tests
  • Update docstring for dropping leap days with high freq
  • Update KeyError when bounds are not found for an axis

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
  • 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)

- Update tests
- Update docstring for dropping leap days with high freq
- Update `KeyError` when bounds are not found for an axis
@github-actions github-actions bot added the type: enhancement New enhancement request label Feb 8, 2023
@codecov-commenter
Copy link

codecov-commenter commented Feb 8, 2023

Codecov Report

Base: 100.00% // Head: 100.00% // No change to project coverage 👍

Coverage data is based on head (3dc1929) compared to base (c1989c9).
Patch coverage: 100.00% of modified lines in pull request are covered.

📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #415   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           14        14           
  Lines         1260      1266    +6     
=========================================
+ Hits          1260      1266    +6     
Impacted Files Coverage Δ
xcdat/bounds.py 100.00% <ø> (ø)
xcdat/temporal.py 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@tomvothecoder tomvothecoder marked this pull request as ready for review February 8, 2023 21:55
Copy link
Collaborator Author

@tomvothecoder tomvothecoder left a comment

Choose a reason for hiding this comment

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

Hey @pochedls, this PR is review. It is a pretty small change related to using custom time coordinates in temporal APIs (#391 (comment)).

Comment on lines +743 to +752
first_time_coord = dv[self.dim].values[0]
is_decoded = isinstance(first_time_coord, cftime.datetime) or isinstance(
first_time_coord, np.datetime64
)
if not is_decoded:
raise ValueError(
f"The time coordinates type is {type(first_time_coord)}, not "
"'cftime.datetime' or 'np.datetime64'. Time coordinates must be "
"decoded as datetime before using TemporalAccessor methods. "
)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We determine if time is decoded by checking the type of the first time coordinate.

Comment on lines +754 to +769
# Get the `cftime` date type based on the CF calendar attribute.
# The date type is used to get the correct cftime.datetime sub-class
# type for creating new grouped time coordinates for averaging.
try:
self.calendar = dv[self.dim].encoding["calendar"]
self.date_type = get_date_type(self.calendar)
except KeyError:
raise KeyError(
f"The 'calendar' encoding attribute is not set on the '{data_var}' "
f"time coordinate variable ({self.dim}). This might indicate that the "
"time coordinates were not decoded, which is required for temporal "
"averaging operations. "
self.calendar = "standard"
logger.warning(
f"'{self.dim}' does not have a calendar encoding attribute set, "
"which is used to determine the `cftime.datetime` object type for the "
"output time coordinates. Defaulting to CF 'standard' calendar. "
"Otherwise, set the calendar type (e.g., "
"ds['time'].encoding['calendar'] = 'noleap') and try again."
)

self.date_type = get_date_type(self.calendar)
Copy link
Collaborator Author

@tomvothecoder tomvothecoder Feb 8, 2023

Choose a reason for hiding this comment

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

If no calendar attr is set, calendar is defaulted to "standard" and a logger warning is raised (instead of a KeyError). Calendar is required for determining the cftime.datetime object type and checking if leap days should be dropped for high freq climatology/departures calculations.

Comment on lines +521 to +526
* "day": groups by (month, day) for the daily cycle departures.
If the CF calendar type is ``"gregorian"``,
``"proleptic_gregorian"``, or ``"standard"``, leap days (if
present) are dropped to avoid inconsistencies when calculating
climatologies. Refer to [2]_ for more details on this
implementation decision.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Add more information about dropping leap days with high freq climos/departs.

Comment on lines +219 to 224
f"No bounds data variables were found for the '{axis}' axis. Make sure "
"the dataset has bound data vars and their names match the 'bounds' "
"attributes found on their related time coordinate variables. "
"Alternatively, you can add bounds with `xcdat.add_missing_bounds` "
"or `xcdat.add_bounds`."
)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated KeyError message when bounds are not found for an axis.

@tomvothecoder tomvothecoder self-assigned this Feb 8, 2023
Copy link
Collaborator

@pochedls pochedls left a 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 (and solves the initial issue / discussion item).

The only thing I got caught up on was the changes to _set_data_var_attrs(). Do you think the top line documentation for this function should be augmented, e.g.,

Set data variable metadata as object attributes and checks whether the time axis is decoded.

It seems like this function is partially used to enforce this (prior to calling key temporal methods).

@tomvothecoder
Copy link
Collaborator Author

This looks good to me (and solves the initial issue / discussion item).

The only thing I got caught up on was the changes to _set_data_var_attrs(). Do you think the top line documentation for this function should be augmented, e.g.,

Set data variable metadata as object attributes and checks whether the time axis is decoded.

It seems like this function is partially used to enforce this (prior to calling key temporal methods).

Thanks for that catch. I just updated the docstring based on your feedback.

I was considering splitting out the check for decoded time as a separate method to keep the implementation cleaner. However, it requires looking at the data variable values which means it's not a big deal to keep it inside _set_data_var_attrs().

@tomvothecoder tomvothecoder merged commit 1efb807 into main Feb 13, 2023
@tomvothecoder tomvothecoder deleted the feature/414-custom-time branch February 13, 2023 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement New enhancement request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature]: Improve support for user generated time coordinates and temporal operations
3 participants