marEx.detect.compute_normalised_anomaly
- marEx.detect.compute_normalised_anomaly(da, method_anomaly='shifting_baseline', dimensions=None, coordinates=None, window_year_baseline=15, smooth_days_baseline=21, std_normalise=False, detrend_orders=None, force_zero_mean=True, reference_period=None, use_temp_checkpoints=False, verbose=None, quiet=None)[source]
Generate normalised anomalies using specified methodology.
- Parameters:
da (xarray.DataArray) – Input data with dimensions matching the ‘dimensions’ parameter
method_anomaly (str, default='shifting_baseline') –
Anomaly computation method. Options: - ‘detrend_harmonic’: Detrending with harmonics and polynomials (efficient, biased) - ‘shifting_baseline’: Rolling climatology (accurate, shortens time series) - ‘fixed_baseline’: Daily climatology using full time series (keeps long-term trends in the anomaly) - ‘detrend_fixed_baseline’: Polynomial detrending + fixed climatology (does not shorten time series,
keeps trends in seasonal timing in the anomaly)
dimensions (dict, optional) – Mapping of conceptual dimensions to actual dimension names in the data
coordinates (dict, optional) – Mapping of conceptual coordinates to actual coordinate names in the data
window_year_baseline (int, default=15) – Number of years for rolling climatology (shifting_baseline only)
smooth_days_baseline (int, default=21) – Days for smoothing rolling climatology (shifting_baseline only)
std_normalise (bool, default=False) – Whether to normalise by 30-day rolling standard deviation (detrend_harmonic only)
detrend_orders (list, default=[1]) – Polynomial orders for trend removal (detrend_harmonic and detrend_fixed_baseline only)
force_zero_mean (bool, default=True) – Explicitly enforce zero mean in final anomalies (detrend_harmonic and detrend_fixed_baseline only)
reference_period (tuple of (int, int), optional) – Year range (start_year, end_year) inclusive for computing the daily climatology (fixed_baseline and detrend_fixed_baseline only). If None (default), uses all available years. Anomalies are computed for the full time series regardless.
use_temp_checkpoints (bool)
verbose (bool | None)
quiet (bool | None)
- Returns:
Dataset containing anomalies, mask, and metadata
- Return type:
Examples
Basic detrended baseline anomaly computation:
>>> import xarray as xr >>> import marEx >>> >>> # Load chunked SST data >>> sst = xr.open_dataset('sst_data.nc', chunks={}).sst.chunk({'time': 30}) >>> >>> # Compute anomalies using shifting baseline (default) >>> result = marEx.compute_normalised_anomaly(sst) >>> print(result.data_vars) Data variables: dat_anomaly (time, lat, lon) float32 dask.array<chunksize=(30, 180, 360)> mask (lat, lon) bool dask.array<chunksize=(180, 360)>
>>> # Check that anomalies have approximately zero mean >>> print(f"Mean anomaly: {result.dat_anomaly.mean().compute():.6f}") Mean anomaly: 0.000023
Previous configuration (marEx v2.0 default) of detrended baseline with higher-order polynomials and standardisation. Note: marEx v3.0+ uses shifting_baseline as the default method:
>>> result_advanced = marEx.compute_normalised_anomaly( ... sst, ... method_anomaly="detrend_harmonic", ... detrend_orders=[1, 2, 3], # Linear, quadratic, cubic trends ... std_normalise=True, # Add standardised anomalies ... force_zero_mean=True ... ) >>> print(result_advanced.data_vars) Data variables: dat_anomaly (time, lat, lon) float32 dask.array<chunksize=(30, 180, 360)> mask (lat, lon) bool dask.array<chunksize=(180, 360)> dat_stn (time, lat, lon) float32 dask.array<chunksize=(30, 180, 360)> STD (dayofyear, lat, lon) float32 dask.array<chunksize=(366, 180, 360)>
>>> # Standardised anomalies have unit variance >>> print(f"STD of standardised anomalies: {result_advanced.dat_stn.std().compute():.3f}")
Accurate shifting baseline method for climate-aware anomalies:
>>> result_shifting = marEx.compute_normalised_anomaly( ... sst, ... method_anomaly="shifting_baseline", ... window_year_baseline=10, # Use 10-year rolling climatology ... smooth_days_baseline=31 # 31-day smoothing window ... ) >>> # Anomalies computed relative to recent past climatology
Processing unstructured data:
>>> # ICON ocean model with ncells dimension >>> icon_data = xr.open_dataset('icon_sst.nc', chunks={}).to.chunk({'time': 25}) >>> result_unstructured = marEx.compute_normalised_anomaly( ... icon_data, ... dimensions={"time": "time", "x": "ncells"} ... coordinates={"time": "time", "x": "lon", "y": "lat"}, ... ) >>> print(result_unstructured.dims) Frozen({'time': 1461, 'ncells': 83886})
Comparison of methods - detrended vs shifting baseline:
>>> # Detrended baseline - faster, slight bias >>> detrended = marEx.compute_normalised_anomaly( ... sst, method_anomaly="detrend_harmonic" ... ) >>> >>> # Shifting baseline - slower, more accurate >>> shifting = marEx.compute_normalised_anomaly( ... sst, method_anomaly="shifting_baseline", ... window_year_baseline=15 ... ) >>> >>> # Compare anomaly magnitudes >>> print(f"Detrended RMS: {detrended.dat_anomaly.std().compute():.3f}") >>> print(f"Shifting RMS: {shifting.dat_anomaly.std().compute():.3f}")
Fixed baseline climatology:
>>> # Use full time series for daily climatology >>> result_fixed = marEx.compute_normalised_anomaly( ... sst, ... method_anomaly="fixed_baseline" ... ) >>> # Climatology computed from all available years
Fixed baseline with a restricted reference period:
>>> # Compute climatology from 1990-2020 only, but output anomalies for all years >>> result_ref = marEx.compute_normalised_anomaly( ... sst, ... method_anomaly="fixed_baseline", ... reference_period=(1990, 2020) ... )
Fixed detrended baseline:
>>> # Remove long-term trends then compute fixed climatology >>> result_fixed_detrended = marEx.compute_normalised_anomaly( ... sst, ... method_anomaly="detrend_fixed_baseline", ... detrend_orders=[1], # Remove linear trend ... force_zero_mean=True ... ) >>> # Combines trend removal with fixed climatology