From e4c1905fe0543a57b02d7da9189c495176217e98 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 16:21:23 -0400 Subject: [PATCH 01/13] fix docstrings --- xscen/aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index dc168fb0..8cd1b559 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -697,7 +697,7 @@ def produce_horizon( indicators: Union[str, Path, Sequence[Indicator], Sequence[Tuple[str, Indicator]]] Indicators to compute. It will be passed to the `indicators` argument of `xs.compute_indicators`. periods: list - Either [start, end] or list of [start_year, end_year] for the period(s) to be evaluated. + List of periods to be evaluated. Each period should be a list of [start, end] or an int/float for the warming level. If both periods and warminglevels are None, the full time series will be used. warminglevels: dict Dictionary of arguments to pass to `py:func:xscen.subset_warming_level`. From e2c8f49b96620208ba093583162fb3bacdead3de Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 16:35:07 -0400 Subject: [PATCH 02/13] fix singular period --- xscen/aggregate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 8cd1b559..11bac985 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -727,7 +727,12 @@ def produce_horizon( all_periods = [] if periods is not None: - all_periods.extend(periods) + if len(periods) == 2 and isinstance(periods[0], str): + all_periods.append(standardize_periods(periods)) + else: + all_periods.extend( + [standardize_periods(p) if isinstance(p, list) else p for p in periods] + ) if warminglevels is not None: if isinstance(warminglevels["wl"], (int, float)): all_periods.append(warminglevels) From f7882acc5a2cdd621b14e0ab710412ae79f02d0d Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 16:35:27 -0400 Subject: [PATCH 03/13] fix singular period --- xscen/aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 11bac985..949fad1d 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -728,7 +728,7 @@ def produce_horizon( all_periods = [] if periods is not None: if len(periods) == 2 and isinstance(periods[0], str): - all_periods.append(standardize_periods(periods)) + all_periods.append(standardize_periods(periods, multiple=False)) else: all_periods.extend( [standardize_periods(p) if isinstance(p, list) else p for p in periods] From bce84fcac01562d3479482b56e5d6fd5f8289648 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 16:49:39 -0400 Subject: [PATCH 04/13] support singular periods with int --- xscen/aggregate.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 949fad1d..08855f57 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -697,7 +697,8 @@ def produce_horizon( indicators: Union[str, Path, Sequence[Indicator], Sequence[Tuple[str, Indicator]]] Indicators to compute. It will be passed to the `indicators` argument of `xs.compute_indicators`. periods: list - List of periods to be evaluated. Each period should be a list of [start, end] or an int/float for the warming level. + Either ['start', 'end'], or list of periods to be evaluated. + Each period should be a list of [start, end] or an int/float for the warming level. If both periods and warminglevels are None, the full time series will be used. warminglevels: dict Dictionary of arguments to pass to `py:func:xscen.subset_warming_level`. @@ -727,11 +728,18 @@ def produce_horizon( all_periods = [] if periods is not None: - if len(periods) == 2 and isinstance(periods[0], str): + if ( + len(periods) == 2 + and isinstance(periods[0], (int, float, str)) + and float(periods[0]) > 100 + ): all_periods.append(standardize_periods(periods, multiple=False)) else: all_periods.extend( - [standardize_periods(p) if isinstance(p, list) else p for p in periods] + [ + standardize_periods(p, multiple=False) if isinstance(p, list) else p + for p in periods + ] ) if warminglevels is not None: if isinstance(warminglevels["wl"], (int, float)): From c510f9f73ef560d46290f4bcba7ee14324fbe0bd Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:02:32 -0400 Subject: [PATCH 05/13] add test for single horizon --- tests/test_aggregate.py | 9 +++++++++ xscen/aggregate.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_aggregate.py b/tests/test_aggregate.py index 3bb792be..d99ecb38 100644 --- a/tests/test_aggregate.py +++ b/tests/test_aggregate.py @@ -455,6 +455,15 @@ def test_combine(self): out.horizon, ["1982-1988", "+0.8Cvs1850-1900", "+0.85Cvs1850-1900"] ) + def test_single(self): + out = xs.produce_horizon( + self.ds, + indicators=self.yaml_file, + periods=[1982, 1988], + ) + assert len(out.horizon) == 1 + np.testing.assert_array_equal(out.horizon, ["1982-1988"]) + def test_warminglevel_in_ds(self): ds = self.ds.copy().expand_dims({"warminglevel": ["+1Cvs1850-1900"]}) out = xs.produce_horizon( diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 08855f57..0ea60afb 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -730,7 +730,7 @@ def produce_horizon( if periods is not None: if ( len(periods) == 2 - and isinstance(periods[0], (int, float, str)) + and (not isinstance(periods[0], list)) and float(periods[0]) > 100 ): all_periods.append(standardize_periods(periods, multiple=False)) From a0377545a23e9b5afe817a0c26b5a8db832c94fc Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:04:33 -0400 Subject: [PATCH 06/13] upd history --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 70da5d4c..ace00086 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -23,7 +23,7 @@ New features and enhancements * Add more comments in the template. (:pull:`233`, :issue:`232`). * ``generate_weights`` now allows to split weights between experiments, and make them vary along the time/horizon axis. (:issue:`108`, :pull:`231`). * New independence_level, `institution`, added to ``generate_weights``. (:pull:`231`). -* Updated ``produce_horizon`` so it can accept multiple periods or warming levels. (:pull:`231`). +* Updated ``produce_horizon`` so it can accept multiple periods or warming levels. (:pull:`231`, :pull:`240`). * Add more comments in the template. (:pull:`233`,:pull:`235`, :issue:`232`). * New function ``diagnostics.health_checks`` that can perform multiple checkups on a dataset. (:pull:`238`). From f724fa540b53b18fe5c49766769de18d2f4a9807 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:15:34 -0400 Subject: [PATCH 07/13] remove bad fix --- xscen/aggregate.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 0ea60afb..8241868c 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -697,8 +697,7 @@ def produce_horizon( indicators: Union[str, Path, Sequence[Indicator], Sequence[Tuple[str, Indicator]]] Indicators to compute. It will be passed to the `indicators` argument of `xs.compute_indicators`. periods: list - Either ['start', 'end'], or list of periods to be evaluated. - Each period should be a list of [start, end] or an int/float for the warming level. + Either [start, end] or list of [start_year, end_year] for the period(s) to be evaluated. If both periods and warminglevels are None, the full time series will be used. warminglevels: dict Dictionary of arguments to pass to `py:func:xscen.subset_warming_level`. @@ -728,11 +727,7 @@ def produce_horizon( all_periods = [] if periods is not None: - if ( - len(periods) == 2 - and (not isinstance(periods[0], list)) - and float(periods[0]) > 100 - ): + if len(periods) == 2 and (not isinstance(periods[0], list)): all_periods.append(standardize_periods(periods, multiple=False)) else: all_periods.extend( @@ -770,7 +765,7 @@ def produce_horizon( ) ds_sub = None else: - ds_sub = subset_warming_level(ds, **period) + ds_sub = subset_warming_level(ds, wl=period) if ds_sub is not None: # compute indicators From afde4840e1c494eb2a51c5c71474aaf4f22cfca2 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:16:37 -0400 Subject: [PATCH 08/13] remove bad fix --- xscen/aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 8241868c..e902d597 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -765,7 +765,7 @@ def produce_horizon( ) ds_sub = None else: - ds_sub = subset_warming_level(ds, wl=period) + ds_sub = subset_warming_level(ds, **period) if ds_sub is not None: # compute indicators From 64531344e7a7152376eec0556d71a4c2cf3c0468 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:21:23 -0400 Subject: [PATCH 09/13] simplify --- xscen/aggregate.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index e902d597..bd538c8e 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -727,15 +727,7 @@ def produce_horizon( all_periods = [] if periods is not None: - if len(periods) == 2 and (not isinstance(periods[0], list)): - all_periods.append(standardize_periods(periods, multiple=False)) - else: - all_periods.extend( - [ - standardize_periods(p, multiple=False) if isinstance(p, list) else p - for p in periods - ] - ) + all_periods.extend(standardize_periods(periods)) if warminglevels is not None: if isinstance(warminglevels["wl"], (int, float)): all_periods.append(warminglevels) From 165702ffaac5e89fcf5c8b5af3f5719ad700b698 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:46:42 -0400 Subject: [PATCH 10/13] better dask support --- xscen/aggregate.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index bd538c8e..0ab39804 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -713,11 +713,13 @@ def produce_horizon( xr.Dataset Horizon dataset. """ - if "warminglevel" in ds and len(ds.warminglevel) != 1: - raise ValueError( - "Input dataset should only have `warminglevel` dimension of length 1. If you want to use produce_horizon for multiple warming levels, " - "extract the full time series and use the `warminglevels` argument instead." - ) + if "warminglevel" in ds: + if len(ds.warminglevel) != 1: + raise ValueError( + "Input dataset should only have `warminglevel` dimension of length 1. If you want to use produce_horizon for multiple warming levels, " + "extract the full time series and use the `warminglevels` argument instead." + ) + ds = ds.squeeze(dim="warminglevel") if period is not None: warnings.warn( "The 'period' argument is deprecated and will be removed in a future version. Use 'periods' instead.", @@ -757,7 +759,7 @@ def produce_horizon( ) ds_sub = None else: - ds_sub = subset_warming_level(ds, **period) + ds_sub = subset_warming_level(ds, **period).squeeze(dim="warminglevel") if ds_sub is not None: # compute indicators @@ -807,10 +809,10 @@ def produce_horizon( ) ds_mean["horizon"] = ds_mean["horizon"].astype(str) - if "warminglevel" in ds_mean.dims: - wl = ds_mean["warminglevel"].values + if "warminglevel" in ds_mean.coords: + wl = np.array([ds_mean["warminglevel"].item()]) wl_attrs = ds_mean["warminglevel"].attrs - ds_mean = ds_mean.squeeze(dim="warminglevel", drop=True) + ds_mean = ds_mean.drop_vars("warminglevel") ds_mean["horizon"] = wl ds_mean["horizon"].attrs.update(wl_attrs) From 95c4b5d6c20436e88c0e62369ddc0eea54146ff0 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 17:50:48 -0400 Subject: [PATCH 11/13] better dask support --- xscen/aggregate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 0ab39804..0d3e874a 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -759,7 +759,9 @@ def produce_horizon( ) ds_sub = None else: - ds_sub = subset_warming_level(ds, **period).squeeze(dim="warminglevel") + ds_sub = subset_warming_level(ds, **period) + if ds_sub is not None: + ds_sub = ds_sub.squeeze(dim="warminglevel") if ds_sub is not None: # compute indicators From 60a97608eef686154786e877f0954ac086727653 Mon Sep 17 00:00:00 2001 From: RondeauG Date: Mon, 21 Aug 2023 18:01:18 -0400 Subject: [PATCH 12/13] to_level fix --- xscen/aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 0d3e874a..3c4fd47e 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -854,7 +854,7 @@ def produce_horizon( "warminglevel" in ds.dims and warminglevels is None ): to_level = to_level.format( - wl=ds_sub.warminglevel.values[0] + wl=ds_sub.horizon.values[0] if isinstance(all_periods[0], dict) else ds.warminglevel.values[0] ) From e0b6e5b7108d74210dcc8887b30ef434096bf57c Mon Sep 17 00:00:00 2001 From: RondeauG Date: Tue, 22 Aug 2023 09:17:28 -0400 Subject: [PATCH 13/13] fix bad changes --- xscen/aggregate.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/xscen/aggregate.py b/xscen/aggregate.py index 3c4fd47e..2a4a096d 100644 --- a/xscen/aggregate.py +++ b/xscen/aggregate.py @@ -713,13 +713,11 @@ def produce_horizon( xr.Dataset Horizon dataset. """ - if "warminglevel" in ds: - if len(ds.warminglevel) != 1: - raise ValueError( - "Input dataset should only have `warminglevel` dimension of length 1. If you want to use produce_horizon for multiple warming levels, " - "extract the full time series and use the `warminglevels` argument instead." - ) - ds = ds.squeeze(dim="warminglevel") + if "warminglevel" in ds and len(ds.warminglevel) != 1: + raise ValueError( + "Input dataset should only have `warminglevel` dimension of length 1. If you want to use produce_horizon for multiple warming levels, " + "extract the full time series and use the `warminglevels` argument instead." + ) if period is not None: warnings.warn( "The 'period' argument is deprecated and will be removed in a future version. Use 'periods' instead.", @@ -760,12 +758,15 @@ def produce_horizon( ds_sub = None else: ds_sub = subset_warming_level(ds, **period) - if ds_sub is not None: - ds_sub = ds_sub.squeeze(dim="warminglevel") if ds_sub is not None: # compute indicators - ind_dict = compute_indicators(ds=ds_sub, indicators=indicators) + ind_dict = compute_indicators( + ds=ds_sub.squeeze(dim="warminglevel") + if "warminglevel" in ds_sub.dims + else ds_sub, + indicators=indicators, + ) # Compute the window-year mean ds_merge = xr.Dataset() @@ -854,7 +855,7 @@ def produce_horizon( "warminglevel" in ds.dims and warminglevels is None ): to_level = to_level.format( - wl=ds_sub.horizon.values[0] + wl=ds_sub.warminglevel.values[0] if isinstance(all_periods[0], dict) else ds.warminglevel.values[0] )