-
Notifications
You must be signed in to change notification settings - Fork 16
Description
What happened?
I am testing dependency changes for PMP related to Pandas (<3.0) and Xarray(<2025.01.2). When running climatology metrics, I encountered the following error with xcdat's dataset.temporal.climatology(): KeyError: "No bounds data variables were found for the 'T' axis. Make sure the dataset has bound data vars and their names match the 'bounds' attributes found on their related coordinate variables. Alternatively, you can add bounds with ds.bounds.add_missing_bounds() or ds.bounds.add_bounds()."
What did you expect to happen? Are there are possible answers you came across?
I confirmed that the function runs successfully with Pandas<3.0, Xarray<2025.01.2, and xCDAT=0.11.1. Additionally, I found that the line runs successfully with xCDAT v0.11.2 when frequency is 'month' instead of 'season'.
Minimal Complete Verifiable Example (MVCE)
# Download dataset here: https://pcmdiweb.llnl.gov/pss/pmpdata/obs4MIPs_PCMDI_monthly/NASA-LaRC/CERES-EBAF-4-1/mon/rlut/gn/v20210727/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc
import xcdat as xc
data_file = "/REPLACE/WITH/YOUR/PATH/TO/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc"
ds = xc.open_dataset(data_file)
ds.temporal.climatology('rlut', freq='season')Relevant log output
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[10], line 4
2 data_file = "/Users/chang61/Documents/PCMDI/pmp_local/doc/Jupyter/demo/demo_data/obs4MIPs_PCMDI_monthly/NASA-LaRC/CERES-EBAF-4-1/mon/rlut/gn/v20210727/rlut_mon_CERES-EBAF-4-1_PCMDI_gn_200301-201812.nc"
3 ds = xc.open_dataset(data_file)
----> 4 ds.temporal.climatology('rlut', freq='season')
File ~/miniforge3/envs/pcmdi_metrics_dev_20260210-2/lib/python3.13/site-packages/xcdat/temporal.py:657, in TemporalAccessor.climatology(self, data_var, freq, weighted, keep_weights, reference_period, season_config, skipna, min_weight)
469 """Returns a Dataset with the climatology of a data variable.
470
471 Data is grouped into the labeled time point for the averaging operation.
(...) 653 }
654 """
655 self._set_data_var_attrs(data_var)
--> 657 return self._averager(
658 data_var,
659 "climatology",
660 freq,
661 weighted,
662 keep_weights,
663 reference_period,
664 season_config,
665 skipna,
666 min_weight=min_weight,
667 )
File ~/miniforge3/envs/pcmdi_metrics_dev_20260210-2/lib/python3.13/site-packages/xcdat/temporal.py:941, in TemporalAccessor._averager(self, data_var, mode, freq, weighted, keep_weights, reference_period, season_config, skipna, min_weight)
939 dv_avg = self._average(ds, data_var, skipna=skipna)
940 elif self._mode in ["group_average", "climatology", "departures"]:
--> 941 dv_avg = self._group_average(ds, data_var, skipna=skipna)
943 # The original time dimension is dropped from the dataset because
944 # it becomes obsolete after the data variable is averaged. When the
945 # averaged data variable is added to the dataset, the new time dimension
946 # and its associated coordinates are also added.
947 ds = ds.drop_dims(self.dim)
File ~/miniforge3/envs/pcmdi_metrics_dev_20260210-2/lib/python3.13/site-packages/xcdat/temporal.py:1631, in TemporalAccessor._group_average(self, ds, data_var, skipna)
1628 dv = dv.assign_coords({self.dim: self._labeled_time})
1630 if self._weighted:
-> 1631 dv_avg = self._weighted_group_average(ds, dv, skipna)
1632 else:
1633 dv_avg = self._group_data(dv).mean(skipna=skipna)
File ~/miniforge3/envs/pcmdi_metrics_dev_20260210-2/lib/python3.13/site-packages/xcdat/temporal.py:1688, in TemporalAccessor._weighted_group_average(self, ds, dv, skipna)
1652 """Compute the weighted group average of a data variable.
1653
1654 This method applies weights to the data variable, groups the weighted data,
(...) 1683 - The minimum weight threshold is controlled by `self._min_weight`.
1684 """
1685 with xr.set_options(keep_attrs=True):
1686 # Keep the original weights for other operations and make a copy
1687 # to avoid modifying the original weights.
-> 1688 self._weights = self._get_weights(ds, str(dv.name))
1689 weights = self._weights.copy()
1691 # For Dask-backed data variables, chunk the weights along the
1692 # time dimension before broadcasting to avoid eager evaluation
1693 # of the masking step.
File ~/miniforge3/envs/pcmdi_metrics_dev_20260210-2/lib/python3.13/site-packages/xcdat/temporal.py:1773, in TemporalAccessor._get_weights(self, ds, data_var)
1740 def _get_weights(self, ds: xr.Dataset, data_var: str) -> xr.DataArray:
1741 """Calculates weights for a data variable using time bounds.
1742
1743 This method gets the length of time for each coordinate point by using
(...) 1771 .. [4] https://cfconventions.org/cf-conventions/cf-conventions.html#calendar
1772 """
-> 1773 time_bounds = ds.bounds.get_bounds("T", var_key=data_var)
1774 time_coords = ds[data_var][self.dim]
1776 bounds_dim = bounds._get_bounds_dim(time_coords, time_bounds)
File ~/miniforge3/envs/pcmdi_metrics_dev_20260210-2/lib/python3.13/site-packages/xcdat/bounds.py:240, in BoundsAccessor.get_bounds(self, axis, var_key)
237 bounds_keys = self._get_bounds_from_attr(obj, axis)
239 if len(bounds_keys) == 0:
--> 240 raise KeyError(
241 f"No bounds data variables were found for the '{axis}' axis. Make sure "
242 "the dataset has bound data vars and their names match the 'bounds' "
243 "attributes found on their related coordinate variables. "
244 "Alternatively, you can add bounds with `ds.bounds.add_missing_bounds()` "
245 "or `ds.bounds.add_bounds()`."
246 )
248 bounds: xr.Dataset | xr.DataArray = self._dataset[
249 bounds_keys if len(bounds_keys) > 1 else bounds_keys[0]
250 ].copy()
252 return bounds
KeyError: "No bounds data variables were found for the 'T' axis. Make sure the dataset has bound data vars and their names match the 'bounds' attributes found on their related coordinate variables. Alternatively, you can add bounds with `ds.bounds.add_missing_bounds()` or `ds.bounds.add_bounds()`."Anything else we need to know?
No response
Environment
xCDAT v0.11.2
xr.show_versions()
INSTALLED VERSIONS
commit: None
python: 3.13.12 | packaged by conda-forge | (main, Feb 5 2026, 06:11:05) [Clang 19.1.7 ]
python-bits: 64
OS: Darwin
OS-release: 25.2.0
machine: arm64
processor: arm
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: ('en_US', 'UTF-8')
libhdf5: 1.14.6
libnetcdf: 4.9.3
xarray: 2025.1.1
pandas: 2.3.3
numpy: 2.3.5
scipy: 1.17.0
netCDF4: 1.7.4
pydap: None
h5netcdf: None
h5py: None
zarr: None
cftime: 1.6.5
nc_time_axis: 1.4.1
iris: None
bottleneck: 1.6.0
dask: 2026.1.2
distributed: 2026.1.2
matplotlib: 3.10.8
cartopy: 0.25.0
seaborn: 0.13.2
numbagg: None
fsspec: 2026.2.0
cupy: None
pint: 0.25.2
sparse: 0.17.0
flox: None
numpy_groupies: None
setuptools: 82.0.0
pip: 26.0.1
conda: None
pytest: 9.0.2
mypy: None
IPython: 9.10.0
sphinx: 8.2.3
Metadata
Metadata
Assignees
Labels
Type
Projects
Status