Skip to content

Commit

Permalink
Merge branch 'fix_spi_attrs' of https://github.com/Ouranosinc/xclim i…
Browse files Browse the repository at this point in the history
…nto fix_spi_attrs
  • Loading branch information
coxipi committed Nov 30, 2023
2 parents 0ec03b4 + 70abdc8 commit 7fcce92
Show file tree
Hide file tree
Showing 33 changed files with 449 additions and 317 deletions.
8 changes: 8 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,11 @@ python:
path: .
extra_requirements:
- dev

search:
ranking:

notebooks/*: 2
api_indicators.html: 1
indices.html: -1
_modules/*: -3
19 changes: 15 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,32 @@ Changelog

v0.47.0 (unreleased)
--------------------
Contributors to this version: Juliette Lavoie (:user:`juliettelavoie`), Pascal Bourgault (:user:`aulemahal`), Trevor James Smith (:user:`Zeitsperre`), Éric Dupuis (:user:`coxipi`)
Contributors to this version: Juliette Lavoie (:user:`juliettelavoie`), Pascal Bourgault (:user:`aulemahal`), Trevor James Smith (:user:`Zeitsperre`), David Huard (:user:`huard`), Éric Dupuis (:user:`coxipi`).

Announcements
^^^^^^^^^^^^^
* To circumvent issues stemming from changes to the frequency code convention in `pandas` v2.2, we have pinned `xarray` (< 2023.11.0) and `pandas` (< 2.2) for this release. This change will be reverted in `xclim` v0.48.0 to support the newer versions (`xarray>= 2023.11.0` and `pandas>= 2.2`).
* `xclim` v0.47.0 will be the last release supporting Python3.8.

New features and enhancements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* New functions ``xclim.ensembles.robustness_fractions`` and ``xclim.ensembles.robustness_categories``. The former will replace ``xclim.ensembles.change_significance`` which is now deprecated and will be removed in xclim 0.49 (:pull:`1514`).
* New functions ``xclim.ensembles.robustness_fractions`` and ``xclim.ensembles.robustness_categories``. The former will replace ``xclim.ensembles.change_significance`` which is now deprecated and will be removed in xclim 0.49. (:pull:`1514`).
* Add indicator ID to searched terms in the indicator search documentation page. (:issue:`1525`, :pull:`1528`).

Bug fixes
^^^^^^^^^
* Fixed a bug with ``n_escore=-1`` in ``xclim.sdba.adjustment.NpdfTransform`` (:issue:`1515`, :pull:`1516`).
* Fix wrong attributes in `xclim.indices.standardized_precipitation_index``, `xclim.indices.standardized_precipitation_evapotranspiration_index`` (:issue:`1537`, :pull:`1538`).
* Fixed a bug with ``n_escore=-1`` in ``xclim.sdba.adjustment.NpdfTransform``. (:issue:`1515`, :pull:`1516`).
* In the documentation, fixed the tooltips in the indicator search results. (:issue:`1524`, :pull:`1527`).
* If chunked inputs are passed to indicators ``mean_radiant_temperature`` and ``potential_evapotranspiration``, sub-calculations of the solar angle will also use the same chunks, instead of a single one of the same size as the data. (:issue:`1536`, :pull:`1542`).
* Fix wrong attributes in ``xclim.indices.standardized_precipitation_index``, ``xclim.indices.standardized_precipitation_evapotranspiration_index``. (:issue:`1537`, :pull:`1538`).

Internal changes
^^^^^^^^^^^^^^^^
* Pinned `cf-xarray` below v0.8.5 in Python3.8 installation to further extend legacy support. (:pull:`1519`).
* `pip check` in conda builds in GitHub workflows have been temporarily set to always pass. (:pull:`1531`).
* Configure RtD search rankings to emphasize notebooks and indicators over indices and raw source code. (:pull:`1526`).
* Addressed around 100 very basic `mypy` typing errors and call signature errors. (:pull:`1532`).
* Use the intermediate step ``_cumsum_reset_on_zero`` instead of ``rle`` which is sufficient in ``_boundary_run``. (:issue:`1405`, :pull:`1530`).

v0.46.0 (2023-10-24)
--------------------
Expand Down
32 changes: 19 additions & 13 deletions docs/_static/indsearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ let indicators = [];

/* MiniSearch object defining search mechanism */
let miniSearch = new MiniSearch({
fields: ['title', 'abstract', 'variables', 'keywords'], // fields to index for full-text search
fields: ['title', 'abstract', 'variables', 'keywords', 'id'], // fields to index for full-text search
storeFields: ['title', 'abstract', 'vars', 'realm', 'module', 'name', 'keywords'], // fields to return with search results
searchOptions: {
boost: {'title': 3, 'variables': 2},
Expand All @@ -30,15 +30,18 @@ fetch('indicators.json')
});


// Populate list of variables
//function getVariables() {
// fetch('variables.json')
// .then((res) => {
// return res.json();
// })
//}
//const variables = getVariables();

function escapeHTML(str){
/* Escape HTML characters in a string. */
var map =
{
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return str.replace(/[&<>"']/g, function(m) {return map[m];});
}

function makeKeywordLabel(ind) {
/* Print list of keywords only if there is at least one. */
Expand All @@ -55,7 +58,10 @@ function makeKeywordLabel(ind) {
function makeVariableList(ind) {
/* Print list of variables and include mouse-hover tooltip with variable description. */
return Object.entries(ind.vars).map((kv) => {
const tooltip = `<button class="indVarname" title="${kv[1]}" alt="${kv[1]}">${kv[0]}</button>`;
/* kv[0] is the variable name, kv[1] is the variable description. */
/* Convert kv[1] to a string literal */
const text = escapeHTML(kv[1]);
const tooltip = `<button class="indVarname" title="${text}" alt="${text}">${kv[0]}</button>`;
return tooltip
}).join('');
}
Expand All @@ -66,13 +72,13 @@ function indTemplate(ind) {
return `
<div class="indElem" id="${ind.id}">
<div class="indHeader">
<b class="indTitle">${ind.title}</b>
<b class="indTitle">${escapeHTML(ind.title)}</b>
<a class="reference_internal indName" href="api_indicators.html#xclim.indicators.${ind.module}.${ind.name}" title="${ind.name}">
<code>${ind.module}.${ind.name}</code>
</a>
</div>
<div class="indVars">Uses: ${varlist}</div>
<div class="indDesc"><p>${ind.abstract}</p></div>
<div class="indDesc"><p>${escapeHTML(ind.abstract)}</p></div>
${makeKeywordLabel(ind)}
<div class="indID">Yaml ID: <code>${ind.id}</code></div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ dependencies:
- lmoments3
- numba
- numpy >=1.16
- pandas >=0.23
- pandas >=0.23,<2.2
- pint >=0.9
- poppler >=0.67
- pyyaml
- scikit-learn >=0.21.3
- scipy >=1.2
- statsmodels
- xarray >=2022.06.0
- xarray >=2022.06.0,<2023.11.0
# Extras
- eofs
- flox
Expand Down
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ dependencies = [
"numba",
"numpy>=1.16",
"pandas>=0.23,<2.0; python_version == '3.8'",
"pandas>=0.23; python_version >= '3.9'",
"pandas>=0.23,<2.2; python_version >= '3.9'",
"pint>=0.10",
"pyyaml",
"scikit-learn>=0.21.3",
"scipy>=1.2",
"statsmodels",
"xarray>=2022.06.0"
"xarray>=2022.06.0,<2023.11.0"
]

[project.optional-dependencies]
Expand Down Expand Up @@ -183,13 +183,16 @@ module = [
"clisops.core.subset.*",
"dask.*",
"lmoments3.*",
"matplotlib.*",
"numba.*",
"numpy.*",
"pandas.*",
"pint.*",
"SBCK.*",
"scipy.*",
"sklearn.cluster.*",
"xarray.*"
"xarray.*",
"yaml.*"
]
ignore_missing_imports = true

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.46.4-beta
current_version = 0.46.10-beta
commit = True
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+).(?P<patch>\d+)(\-(?P<release>[a-z]+))?
Expand Down
6 changes: 4 additions & 2 deletions tests/test_ensembles.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,9 @@ def test_robustness_fractions_empty():


def test_robustness_categories():
changed = xr.DataArray([0.5, 0.8, 1, 1])
agree = xr.DataArray([1, 0.5, 0.5, 1])
lat = xr.DataArray([1, 2, 3, 4], dims=("lat",), attrs={"axis": "Y"}, name="lat")
changed = xr.DataArray([0.5, 0.8, 1, 1], dims=("lat",), coords={"lat": lat})
agree = xr.DataArray([1, 0.5, 0.5, 1], dims=("lat",), coords={"lat": lat})

categories = ensembles.robustness_categories(changed, agree)
np.testing.assert_array_equal(categories, [2, 3, 3, 1])
Expand All @@ -753,6 +754,7 @@ def test_robustness_categories():
categories.flag_meanings
== "robust_signal no_change_or_no_signal conflicting_signal"
)
assert categories.lat.attrs["axis"] == "Y"


def test_robustness_coefficient():
Expand Down
17 changes: 17 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import xarray as xr

from xclim.core.utils import (
_chunk_like,
ensure_chunk_size,
nan_calc_percentiles,
walk_map,
wrapped_partial,
)
from xclim.testing.helpers import test_timeseries as _test_timeseries


def test_walk_map():
Expand Down Expand Up @@ -110,3 +112,18 @@ def test_calc_perc_partial_nan(self):
# The expected is from R `quantile(arr, 0.5, type=8, na.rm = TRUE)`
# Note that scipy mquantiles would give a different result here
assert res[()] == 42.0


def test_chunk_like():
da = _test_timeseries(
np.zeros(
100,
),
"tas",
)
da = xr.concat([da] * 10, xr.DataArray(np.arange(10), dims=("lat",), name="lat"))

assert isinstance(da.lat.variable, xr.core.variable.IndexVariable)
t, la = _chunk_like(da.time, da.lat, chunks={"time": 10, "lat": 1})
assert t.chunks[0] == tuple([10] * 10)
assert la.chunks[0] == tuple([1] * 10)
2 changes: 1 addition & 1 deletion xclim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

__author__ = """Travis Logan"""
__email__ = "[email protected]"
__version__ = "0.46.4-beta"
__version__ = "0.46.10-beta"


_module_data = _files("xclim.data")
Expand Down
14 changes: 7 additions & 7 deletions xclim/analog.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Code adapted from flyingpigeon.dissimilarity, Nov 2020.
from __future__ import annotations

from typing import Sequence
from typing import Any, Sequence

import numpy as np
import pandas as pd
Expand All @@ -16,7 +16,7 @@
from scipy import spatial
from scipy.spatial import cKDTree as KDTree

metrics = {}
metrics: dict[str, Any] = {}


def spatial_analogs(
Expand Down Expand Up @@ -61,7 +61,7 @@ def spatial_analogs(
raise RuntimeError(f"Spatial analogue method ({method}) requires scipy>=1.6.0.")

# Create the target DataArray:
target = target.to_array("_indices", "target")
target_array = target.to_array("_indices", "target")

# Create the target DataArray
# drop any (sub-)index along "dist_dim" that could conflict with target, and rename it.
Expand All @@ -86,13 +86,13 @@ def spatial_analogs(

if candidates.chunks is not None:
candidates = candidates.chunk({"_indices": -1})
if target.chunks is not None:
target = target.chunk({"_indices": -1})
if target_array.chunks is not None:
target_array = target_array.chunk({"_indices": -1})

# Compute dissimilarity
diss = xr.apply_ufunc(
metric_func,
target,
target_array,
candidates,
input_core_dims=[(dist_dim, "_indices"), ("_dist_dim", "_indices")],
output_core_dims=[()],
Expand All @@ -104,7 +104,7 @@ def spatial_analogs(
diss.name = "dissimilarity"
diss.attrs.update(
long_name=f"Dissimilarity between target and candidates, using metric {method}.",
indices=",".join(target._indices.values), # noqa
indices=",".join(target_array._indices.values), # noqa
metric=method,
)

Expand Down
Loading

0 comments on commit 7fcce92

Please sign in to comment.