From 032befd13184af2e7c2508a86a2d163a80dbde46 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:30:22 +0100 Subject: [PATCH 01/75] add plotter 4 places --- docs/api/model/point.md | 4 +++- docs/api/model/track.md | 4 +++- docs/api/observation/point.md | 4 +++- docs/api/observation/track.md | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/api/model/point.md b/docs/api/model/point.md index e9c9eb2bd..06a8843b0 100644 --- a/docs/api/model/point.md +++ b/docs/api/model/point.md @@ -1,3 +1,5 @@ # PointModelResult -::: modelskill.PointModelResult \ No newline at end of file +::: modelskill.PointModelResult + +::: modelskill.timeseries._plotter.MatplotlibTimeSeriesPlotter diff --git a/docs/api/model/track.md b/docs/api/model/track.md index 6d3f05043..443820275 100644 --- a/docs/api/model/track.md +++ b/docs/api/model/track.md @@ -1,3 +1,5 @@ # TrackModelResult -::: modelskill.TrackModelResult \ No newline at end of file +::: modelskill.TrackModelResult + +::: modelskill.timeseries._plotter.MatplotlibTimeSeriesPlotter diff --git a/docs/api/observation/point.md b/docs/api/observation/point.md index 51f92143f..c67ee5419 100644 --- a/docs/api/observation/point.md +++ b/docs/api/observation/point.md @@ -1,3 +1,5 @@ # PointObservation -::: modelskill.PointObservation \ No newline at end of file +::: modelskill.PointObservation + +::: modelskill.timeseries._plotter.MatplotlibTimeSeriesPlotter diff --git a/docs/api/observation/track.md b/docs/api/observation/track.md index 77a4bc772..27a305eb4 100644 --- a/docs/api/observation/track.md +++ b/docs/api/observation/track.md @@ -1,3 +1,5 @@ # TrackObservation -::: modelskill.TrackObservation \ No newline at end of file +::: modelskill.TrackObservation + +::: modelskill.timeseries._plotter.MatplotlibTimeSeriesPlotter From 7473b9ecf89a626373cb447eca3af5f8e424034f Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:30:51 +0100 Subject: [PATCH 02/75] move factory methods to their own pages --- docs/api/model/index.md | 6 ------ docs/api/model/model_result.md | 3 +++ docs/api/observation/index.md | 4 ---- docs/api/observation/observation.md | 3 +++ 4 files changed, 6 insertions(+), 10 deletions(-) create mode 100644 docs/api/model/model_result.md create mode 100644 docs/api/observation/observation.md diff --git a/docs/api/model/index.md b/docs/api/model/index.md index b0ab434d1..54aafe9d0 100644 --- a/docs/api/model/index.md +++ b/docs/api/model/index.md @@ -1,7 +1,5 @@ # Model Result -## Types of model results - A model result can either be a simple point/track, or spatial field (e.g. 2d dfsu file) from which data can be *extracted* at the observation positions by spatial interpolation. The following types are available: * Timeseries @@ -13,7 +11,3 @@ A model result can either be a simple point/track, or spatial field (e.g. 2d dfs A model result can be created by explicitly invoking one of the above classes or using the `model_result()` function which will return the appropriate type based on the input data (if possible). - -## model_result() - -::: modelskill.model_result diff --git a/docs/api/model/model_result.md b/docs/api/model/model_result.md new file mode 100644 index 000000000..42996a8a6 --- /dev/null +++ b/docs/api/model/model_result.md @@ -0,0 +1,3 @@ +# model_result() + +::: modelskill.model_result diff --git a/docs/api/observation/index.md b/docs/api/observation/index.md index bb8ef65d1..b9d476ae3 100644 --- a/docs/api/observation/index.md +++ b/docs/api/observation/index.md @@ -7,7 +7,3 @@ ModelSkill supports two types of observations: An observation can be created by explicitly invoking one of the above classes or using the `observation()` function which will return the appropriate type based on the input data (if possible). - -## observation() - -::: modelskill.observation diff --git a/docs/api/observation/observation.md b/docs/api/observation/observation.md new file mode 100644 index 000000000..4072e4725 --- /dev/null +++ b/docs/api/observation/observation.md @@ -0,0 +1,3 @@ +# observation() + +::: modelskill.observation From ee41533e3bd1f594bbdde6e5f9ab9171d76ac11c Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:31:34 +0100 Subject: [PATCH 03/75] user-guide group; move terminology to group --- docs/user-guide/index.md | 3 +++ docs/{ => user-guide}/terminology.md | 18 +++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 docs/user-guide/index.md rename docs/{ => user-guide}/terminology.md (68%) diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md new file mode 100644 index 000000000..0d30babb8 --- /dev/null +++ b/docs/user-guide/index.md @@ -0,0 +1,3 @@ +# User Guide + +xx \ No newline at end of file diff --git a/docs/terminology.md b/docs/user-guide/terminology.md similarity index 68% rename from docs/terminology.md rename to docs/user-guide/terminology.md index 7b14844d0..03bea3795 100644 --- a/docs/terminology.md +++ b/docs/user-guide/terminology.md @@ -6,7 +6,7 @@ ## General terminology ### Skill -**Skill** refers to the ability of a numerical model to accurately represent the real-world phenomenon it aims to simulate. It is a measure of how well the model performs in reproducing the observed system. Skill can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In `ModelSkill`, [`skill`](api/skill.md) is also a specific method on [Comparer](#comparer) objects that returns a skill table with aggregated skill scores per observation and model for a list of selected [metrics](#metric). +**Skill** refers to the ability of a numerical model to accurately represent the real-world phenomenon it aims to simulate. It is a measure of how well the model performs in reproducing the observed system. Skill can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In `ModelSkill`, [`skill`](../api/skill.md) is also a specific method on [Comparer](#comparer) objects that returns a skill table with aggregated skill scores per observation and model for a list of selected [metrics](#metric). ### Validation @@ -26,7 +26,7 @@ A **timeseries** is a sequence of data points in time. In `ModelSkill`, The data ### Observation -An **observation** refers to real-world data or measurements collected from the system you are modeling. Observations serve as a reference for assessing the model's performance. These data points are used to compare with the model's predictions during validation and calibration. Observations are usually based on field measurements or laboratory experiments, but for the purposes of model validation, they can also be derived from other models (e.g. a reference model). `ModelSkill` supports [point](api/observation/point.md) and [track](api/observation/track.md) observation types. +An **observation** refers to real-world data or measurements collected from the system you are modeling. Observations serve as a reference for assessing the model's performance. These data points are used to compare with the model's predictions during validation and calibration. Observations are usually based on field measurements or laboratory experiments, but for the purposes of model validation, they can also be derived from other models (e.g. a reference model). `ModelSkill` supports [point](../api/observation/point.md) and [track](../api/observation/track.md) observation types. ### Measurement @@ -34,33 +34,33 @@ A **measurement** is called [observation](#observation) in `ModelSkill`. ### Model result -A **model result** is the output of any type of numerical model. It is the data generated by the model during a simulation. Model results can be compared with observations to assess the model's performance. In the context of validation, the term "model result" is often used interchangeably with "model output" or "model prediction". `ModelSkill` supports [point](api/model/point.md), [track](api/model/track.md), [dfsu](api/model/dfsu.md) and [grid](api/model/grid.md) model result types. +A **model result** is the output of any type of numerical model. It is the data generated by the model during a simulation. Model results can be compared with observations to assess the model's performance. In the context of validation, the term "model result" is often used interchangeably with "model output" or "model prediction". `ModelSkill` supports [point](../api/model/point.md), [track](../api/model/track.md), [dfsu](../api/model/dfsu.md) and [grid](../api/model/grid.md) model result types. ### Metric -A **metric** is a quantitative measure (a mathematical expression) used to evaluate the performance of a numerical model. Metrics provide a standardized way to assess the model's accuracy, precision, and other attributes. A metric aggregates the skill of a model into a single number. See list of [metrics](api/metrics.md#modelskill.metrics) supported by `ModelSkill`. +A **metric** is a quantitative measure (a mathematical expression) used to evaluate the performance of a numerical model. Metrics provide a standardized way to assess the model's accuracy, precision, and other attributes. A metric aggregates the skill of a model into a single number. See list of [metrics](../api/metrics.md#modelskill.metrics) supported by `ModelSkill`. ### Score -A **score** is a numerical value that summarizes the model's performance based on chosen metrics. Scores can be used to rank or compare different models or model configurations. In the context of validation, the "skill score" or "validation score" often quantifies the model's overall performance. The score of a model is a single number, calculated as a weighted average for all time-steps, observations and variables. If you want to perform automated calibration, you can use the score as the objective function. In `ModelSkill`, [`score`](api/comparercollection.md/#modelskill.ComparerCollection.score) is also a specific method on [Comparer](#comparer) objects that returns a single number aggregated score using a specific [metric](#metric). +A **score** is a numerical value that summarizes the model's performance based on chosen metrics. Scores can be used to rank or compare different models or model configurations. In the context of validation, the "skill score" or "validation score" often quantifies the model's overall performance. The score of a model is a single number, calculated as a weighted average for all time-steps, observations and variables. If you want to perform automated calibration, you can use the score as the objective function. In `ModelSkill`, [`score`](../api/comparercollection.md/#modelskill.ComparerCollection.score) is also a specific method on [Comparer](#comparer) objects that returns a single number aggregated score using a specific [metric](#metric). ## ModelSkill-specific terminology ### matched data -In ModelSkill, observations and model results are *matched* when they refer to the same positions in space and time. If the [observations](#observation) and [model results](#model-result) are already matched, the [`from_matched`](api/matching.md/#modelskill.from_matched) function can be used to create a [Comparer](#comparer) directly. Otherwise, the [compare](#compare) function can be used to match the observations and model results in space and time. +In ModelSkill, observations and model results are *matched* when they refer to the same positions in space and time. If the [observations](#observation) and [model results](#model-result) are already matched, the [`from_matched`](../api/matching.md/#modelskill.from_matched) function can be used to create a [Comparer](#comparer) directly. Otherwise, the [compare](#compare) function can be used to match the observations and model results in space and time. ### match -The function [`match`](api/matching.md/#modelskill.match) is used to match a model result with observations. It returns a [`Comparer`](api/comparer.md) object or a [`ComparerCollection`](api/comparercollection.md) object. +The function [`match`](../api/matching.md/#modelskill.match) is used to match a model result with observations. It returns a [`Comparer`](../api/comparer.md) object or a [`ComparerCollection`](../api/comparercollection.md) object. ### Comparer -A [**Comparer**](api/comparer.md) is an object that compares a model result with observations. It is used to calculate validation metrics and generate plots. A Comparer can be created using the [`compare`](api/matching.md/#modelskill.match) function (will return a [ComparerCollection](api/comparercollection.md)). +A [**Comparer**](../api/comparer.md) is an object that compares a model result with observations. It is used to calculate validation metrics and generate plots. A Comparer can be created using the [`compare`](../api/matching.md/#modelskill.match) function (will return a [ComparerCollection](../api/comparercollection.md)). ### ComparerCollection -A [**ComparerCollection**](api/comparercollection.md) is a collection of Comparers. It is used to compare multiple model results with multiple observations. A ComparerCollection can be created using the [`compare`](api/matching.md/#modelskill.match) function. +A [**ComparerCollection**](../api/comparercollection.md) is a collection of Comparers. It is used to compare multiple model results with multiple observations. A ComparerCollection can be created using the [`compare`](../api/matching.md/#modelskill.match) function. ### Connector From 4ace2767baf5790e6d55e45d512be18f0c191395 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:31:48 +0100 Subject: [PATCH 04/75] tabs and new organization --- mkdocs.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 4922bf8d5..337f40101 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,7 @@ site_url: https://dhi.github.io/modelskill/ theme: name: material features: - # - navigation.tabs + - navigation.tabs # - navigation.instant - navigation.expand - navigation.sections @@ -12,18 +12,21 @@ theme: nav: - 'index.md' - - 'getting-started.md' - - 'overview.md' - - 'vision.md' - - 'terminology.md' - - API: + - User Guide: + - 'user-guide/index.md' + - 'getting-started.md' + - 'overview.md' + - 'user-guide/terminology.md' + - API Reference: - 'api/index.md' - Observation: - 'api/observation/index.md' + - observation(): 'api/observation/observation.md' - PointObservation: 'api/observation/point.md' - TrackObservation: 'api/observation/track.md' - Model Result: - 'api/model/index.md' + - model_result(): 'api/model/model_result.md' - PointModelResult: 'api/model/point.md' - TrackModelResult: 'api/model/track.md' - DfsuModelResult: 'api/model/dfsu.md' From ef6c607c5445663a96daf2267a5664458b4125e0 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 08:21:39 +0100 Subject: [PATCH 05/75] Data Structures page --- docs/user-guide/data-structures.md | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/user-guide/data-structures.md diff --git a/docs/user-guide/data-structures.md b/docs/user-guide/data-structures.md new file mode 100644 index 000000000..83de83638 --- /dev/null +++ b/docs/user-guide/data-structures.md @@ -0,0 +1,43 @@ +# Data Structures + +The main data structures in ModelSkill can be grouped into three categories: + +* **Primary** data (observations and model results) +* **Comparer** objects +* **Skill** objects + +All objects share some common principles: + +* The data container is accesssible via the `data` attribute. +* The data container is a `xarray` object (except for the `SkillTable` object, which is a `pandas` object). +* The main data selection method is `sel`, which is a wrapper around `xarray.Dataset.sel`. +* All plotting are accessible via the `plot` accessor of the object. + + +## Observations and model results + +The primary data of ModelSkill are the data that needs to be compared: observations and model results. The underlying data structures are very similar and can be grouped according to the spatial dimensionality (`gtype`) of the data: + +* `point`: 0D time series data +* `track`: 0D time series data at moving locations (trajectories) +* `grid`: gridded 2D data +* `dfsu`: flexible mesh 2D data + +Point and track data are both `TimeSeries` objects, while grid and dfsu data are both `SpatialField` objects. `TimeSeries` objects are ready to be compared whereas data from `SpatialField` object needs to be *extracted* first (the extracted object will be of the `TimeSeries` type). + +`TimeSeries` objects contains its data in an `xarray.Dataset` with the actual data in the first DataArray and optional auxilliary data in the following DataArrays. The DataArrays have a `kind` attribute with either `observation` or `model`. + + +## Comparer objects + +Comparer objects are results of a matching procedure (between observations and model results) or constructed directly from already matched data. A comparison of a *single* observation and one or more model results are stored in a `Comparer` object. A comparison of *multiple* observations and one or more model results are stored in a `ComparerCollection` object which is a collection of `Comparer` objects. + +The matched data in a `Comparer` is stored in an `xarray.Dataset` which can be accessed via the `data` attribute. The first DataArray in the Dataset is the observation data, the next DataArrays are model result data and optionally additional DataArrays are auxilliarye data. Each of the DataArrays have a `kind` attribute with either `observation`, `model` or `aux` as value and + +which is a string describing the type of data (e.g. `point`, `track`, `grid`, `dfsu`). + +Both objects have a `plot` accessor for plotting the data. + + +## Skill objects + From 50d9595626e48a0e224c84c1ef2c36fa987aede4 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 08:21:46 +0100 Subject: [PATCH 06/75] Create selecting-data.md --- docs/user-guide/selecting-data.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/user-guide/selecting-data.md diff --git a/docs/user-guide/selecting-data.md b/docs/user-guide/selecting-data.md new file mode 100644 index 000000000..2bfe1d287 --- /dev/null +++ b/docs/user-guide/selecting-data.md @@ -0,0 +1,2 @@ +# Selecting/filtering data + From e3584d0900a6f3c414a0017eec6c265333e73c00 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 08:22:06 +0100 Subject: [PATCH 07/75] add new pages and new site name --- mkdocs.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 337f40101..c7e9f7c8a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: modelskill +site_name: ModelSkill documentation site_url: https://dhi.github.io/modelskill/ theme: name: material @@ -11,12 +11,13 @@ theme: # toc-depth: 1 nav: - - 'index.md' - User Guide: - 'user-guide/index.md' - 'getting-started.md' - - 'overview.md' - 'user-guide/terminology.md' + - 'user-guide/data-structures.md' + - 'user-guide/selecting-data.md' + - 'overview.md' - API Reference: - 'api/index.md' - Observation: From e2c633f3f05efb02635745f70b1f2cab0db359d2 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 08:38:02 +0100 Subject: [PATCH 08/75] sel method --- docs/user-guide/selecting-data.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/user-guide/selecting-data.md b/docs/user-guide/selecting-data.md index 2bfe1d287..e808024f2 100644 --- a/docs/user-guide/selecting-data.md +++ b/docs/user-guide/selecting-data.md @@ -1,2 +1,3 @@ # Selecting/filtering data +The primary data filtering method of ModelSkill is the `sel()` method which is accesible on most ModelSkill data structures. The `sel()` method is a wrapper around `xarray.Dataset.sel()` and can be used to select data based on time, location and/or variable. The `sel()` method returns a new data structure of the same type with the selected data. \ No newline at end of file From 10ddb87ee7a6a1aa190a77c15176aaa8ad7c0e0d Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 08:38:10 +0100 Subject: [PATCH 09/75] Skill objects --- docs/user-guide/data-structures.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/user-guide/data-structures.md b/docs/user-guide/data-structures.md index 83de83638..e273f39bf 100644 --- a/docs/user-guide/data-structures.md +++ b/docs/user-guide/data-structures.md @@ -39,5 +39,17 @@ which is a string describing the type of data (e.g. `point`, `track`, `grid`, `d Both objects have a `plot` accessor for plotting the data. + ## Skill objects +Calling a skill method on a comparer object will return a skill object with skill scores (statistics) from comparing observation and model result data using different metrics (e.g. root mean square error). Two skill objects are currently implemented: `SkillTable` and `SkillGrid`. The first is relevant for all ModelSkill users while the latter is relevant for users of the track data (e.g. MetOcean studies using satellite altimetry data). + +If `c` is a comparer object, then the following skill methods are available: + +* `c.skill()` -> `SkillTable` +* `c.mean_skill()` -> `SkillTable` +* `c.gridded_skill()` -> `SkillGrid` + + +### SkillTable + From 9c650cc6d6a8af5d722b55df7e743167697a5f18 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:47:18 +0100 Subject: [PATCH 10/75] selecting timeseries, comparer and skill data --- docs/user-guide/selecting-data.md | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/user-guide/selecting-data.md b/docs/user-guide/selecting-data.md index e808024f2..bdd26ade3 100644 --- a/docs/user-guide/selecting-data.md +++ b/docs/user-guide/selecting-data.md @@ -1,3 +1,37 @@ # Selecting/filtering data -The primary data filtering method of ModelSkill is the `sel()` method which is accesible on most ModelSkill data structures. The `sel()` method is a wrapper around `xarray.Dataset.sel()` and can be used to select data based on time, location and/or variable. The `sel()` method returns a new data structure of the same type with the selected data. \ No newline at end of file +The primary data filtering method of ModelSkill is the `sel()` method which is accesible on most ModelSkill data structures. The `sel()` method is a wrapper around `xarray.Dataset.sel()` and can be used to select data based on time, location and/or variable. The `sel()` method returns a new data structure of the same type with the selected data. + + +## TimeSeries data + +Point and track timeseries data of both observation and model result kinds are stored in `TimeSeries` objects which uses `xarray.Dataset` as data container. The `sel()` method can be used to select data based on time and returns a new `TimeSeries` object with the selected data. + +```python +>>> o = ms.observation('obs.nc', item='waterlevel') +>>> o_1month = o.sel(time=slice('2018-01-01', '2018-02-01')) +``` + + +## Comparer objects + +`Comparer` and `ComparerCollection` contain matched data from observations and model results. The `sel()` method can be used to select data based on time, model, quantity or other criteria and returns a new comparer object with the selected data. + +```python +>>> cmp = ms.match(o, [m1, m2]) +>>> cmp_1month = cmp.sel(time=slice('2018-01-01', '2018-02-01')) +>>> cmp_m1 = cmp.sel(model='m1') +``` + + + +## Skill objects + +The `skill()` and `mean_skill()` methods return a `SkillTable` object with skill scores from comparing observation and model result data using different metrics (e.g. root mean square error). The data of the `SkillTable` object is stored in a (MultiIndex) `pandas.DataFrame` which can be accessed via the `data` attribute. The `sel()` method can be used to select specific rows and returns a new `SkillTable` object with the selected data. + +```python +>>> sk = cmp.skill() +>>> sk_m1 = sk.sel(model='m1') +``` + + From 6ec65b2629216fb01e52714241034a3d1508f3b0 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:47:35 +0100 Subject: [PATCH 11/75] Improvements --- docs/user-guide/data-structures.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/user-guide/data-structures.md b/docs/user-guide/data-structures.md index e273f39bf..7f9001f22 100644 --- a/docs/user-guide/data-structures.md +++ b/docs/user-guide/data-structures.md @@ -9,7 +9,7 @@ The main data structures in ModelSkill can be grouped into three categories: All objects share some common principles: * The data container is accesssible via the `data` attribute. -* The data container is a `xarray` object (except for the `SkillTable` object, which is a `pandas` object). +* The data container is an `xarray` object (except for the `SkillTable` object, which is a `pandas` object). * The main data selection method is `sel`, which is a wrapper around `xarray.Dataset.sel`. * All plotting are accessible via the `plot` accessor of the object. @@ -32,11 +32,9 @@ Point and track data are both `TimeSeries` objects, while grid and dfsu data are Comparer objects are results of a matching procedure (between observations and model results) or constructed directly from already matched data. A comparison of a *single* observation and one or more model results are stored in a `Comparer` object. A comparison of *multiple* observations and one or more model results are stored in a `ComparerCollection` object which is a collection of `Comparer` objects. -The matched data in a `Comparer` is stored in an `xarray.Dataset` which can be accessed via the `data` attribute. The first DataArray in the Dataset is the observation data, the next DataArrays are model result data and optionally additional DataArrays are auxilliarye data. Each of the DataArrays have a `kind` attribute with either `observation`, `model` or `aux` as value and +The matched data in a `Comparer` is stored in an `xarray.Dataset` which can be accessed via the `data` attribute. The Dataset has an attribute `gtype` which is a string describing the type of data (e.g. `point`, `track`). The first DataArray in the Dataset is the observation data, the next DataArrays are model result data and optionally additional DataArrays are auxilliarye data. Each of the DataArrays have a `kind` attribute with either `observation`, `model` or `aux`. -which is a string describing the type of data (e.g. `point`, `track`, `grid`, `dfsu`). - -Both objects have a `plot` accessor for plotting the data. +Both `Comparer` and `ComparerCollection` have a `plot` accessor for plotting the data (e.g. `cmp.plot.timeseries()` or `cmp.plot.scatter()`). From 9d0f8c7ae1f53dfbdf9eaa746150389b229edfe9 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:21:37 +0100 Subject: [PATCH 12/75] re-organize workflow a bit --- docs/getting-started.md | 60 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index e9c885514..f1624caeb 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -8,30 +8,18 @@ results and observations. ## Workflow -The typical ModelSkill workflow consists of these five steps: +The typical ModelSkill workflow consists of these four steps: -1. Define **ModelResults** -2. Define **Observations** +1. Define **Observations** +2. Define **ModelResults** 3. **Match** observations and ModelResults in space and time 4. Do analysis, plotting, etc with a **Comparer** -### 1. Define ModelResults -The result of a simulation is stored in one or more result files, e.g. dfsu, dfs0, nc, csv. - -The name is used to identify the model result in the plots and tables. +### Define Observations -```python hl_lines="4" -import modelskill as ms -mr = ms.DfsuModelResult("SW/HKZN_local_2017_DutchCoast.dfsu", - item="Sign. Wave Height", - name='HKZN_local') -``` - -### 2. Define Observations - -The next step is to define the measurements to be used for the skill +The first step is to define the measurements to be used for the skill assessment. Two types of observation are available: - [PointObservation](api/observation/point.md) @@ -57,18 +45,34 @@ file, the item number (or item name) and a name. A PointObservation further needs to be initialized with it\'s x-, y-position. -### 3. Match observations and ModelResults +### Define ModelResults + +The result of a simulation is stored in one or more result files, e.g. dfsu, dfs0, nc, csv. + +The name is used to identify the model result in the plots and tables. + +```python hl_lines="4" +import modelskill as ms +mr = ms.DfsuModelResult("SW/HKZN_local_2017_DutchCoast.dfsu", + item="Sign. Wave Height", + name='HKZN_local') +``` + + + +### Match observations and ModelResults + +This [match()](api/matching.md/#modelskill.match) method returns a [Comparer](api/comparer.md#modelskill.Comparer) (a single observation) or a +[ComparerCollection](api/comparercollection.md#modelskill.ComparerCollection) (multiple observations) +for further analysis and plotting. ```python cc = ms.match([hkna, c2], mr) ``` -This method returns a -[ComparerCollection](api/comparercollection.md#modelskill.ComparerCollection) -for further analysis and plotting. -### 4. Do analysis, plotting, etc with a Comparer +### Do analysis, plotting, etc with a Comparer The object returned by the `match()` method is a *Comparer*/*ComparerCollection*. It holds the matched observation and model data and has methods for plotting and skill assessment. @@ -76,14 +80,10 @@ skill assessment. The primary comparer methods are: - [skill()](api/comparercollection.md#modelskill.ComparerCollection.skill) - which returns a table with the skill scores -- various plot methods of the comparer objects - * `plot.scatter()` - * `plot.timeseries()` - * `plot.kde()` - * `plot.qq()` - * `plot.hist()` - + which returns a [SkillTable](api/skill.md) with the skill scores +- various [plot](api/comparercollection.md/#modelskill.comparison._collection_plotter.ComparerCollectionPlotter) methods of the comparer objects (e.g. `plot.scatter()`, `plot.timeseries()`) +- [sel()](api/comparercollection.md/#modelskill.ComparerCollection.sel) method for selecting data + ### Save / load the ComparerCollection From f41b7391b6e76f6ad6691840ed5c21d0c2d931d2 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:21:49 +0100 Subject: [PATCH 13/75] Abbreviations and more --- docs/user-guide/terminology.md | 36 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/docs/user-guide/terminology.md b/docs/user-guide/terminology.md index 03bea3795..00573ed70 100644 --- a/docs/user-guide/terminology.md +++ b/docs/user-guide/terminology.md @@ -1,12 +1,12 @@ # Terminology -`ModelSkill` is a library for assessing the skill of numerical models. It provides tools for comparing model results with observations, plotting the results and calculating validation metrics. This page defines some of the key terms used in the documentation. +ModelSkill is a library for assessing the skill of numerical models. It provides tools for comparing model results with observations, plotting the results and calculating validation metrics. This page defines some of the key terms used in the documentation. ## General terminology ### Skill -**Skill** refers to the ability of a numerical model to accurately represent the real-world phenomenon it aims to simulate. It is a measure of how well the model performs in reproducing the observed system. Skill can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In `ModelSkill`, [`skill`](../api/skill.md) is also a specific method on [Comparer](#comparer) objects that returns a skill table with aggregated skill scores per observation and model for a list of selected [metrics](#metric). +**Skill** refers to the ability of a numerical model to accurately represent the real-world phenomenon it aims to simulate. It is a measure of how well the model performs in reproducing the observed system. Skill can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In ModelSkill, [`skill`](../api/skill.md) is also a specific method on [Comparer](#comparer) objects that returns a skill table with aggregated skill scores per observation and model for a list of selected [metrics](#metric). ### Validation @@ -22,33 +22,33 @@ ### Timeseries -A **timeseries** is a sequence of data points in time. In `ModelSkill`, The data can either be from [observations](#observation) or [model results](#model-result). Timeseries can univariate or multivariate; ModelSkill primarily supports univariate timeseries. Multivariate timeseries can be assessed one variable at a time. Timeseries can also have different spatial dimensions, such as point, track, line, or area. +A **timeseries** is a sequence of data points in time. In ModelSkill, The data can either be from [observations](#observation) or [model results](#model-result). Timeseries can univariate or multivariate; ModelSkill primarily supports univariate timeseries. Multivariate timeseries can be assessed one variable at a time. Timeseries can also have different spatial dimensions, such as point, track, line, or area. ### Observation -An **observation** refers to real-world data or measurements collected from the system you are modeling. Observations serve as a reference for assessing the model's performance. These data points are used to compare with the model's predictions during validation and calibration. Observations are usually based on field measurements or laboratory experiments, but for the purposes of model validation, they can also be derived from other models (e.g. a reference model). `ModelSkill` supports [point](../api/observation/point.md) and [track](../api/observation/track.md) observation types. +An **observation** refers to real-world data or measurements collected from the system you are modeling. Observations serve as a reference for assessing the model's performance. These data points are used to compare with the model's predictions during validation and calibration. Observations are usually based on field measurements or laboratory experiments, but for the purposes of model validation, they can also be derived from other models (e.g. a reference model). ModelSkill supports [point](../api/observation/point.md) and [track](../api/observation/track.md) observation types. ### Measurement -A **measurement** is called [observation](#observation) in `ModelSkill`. +A **measurement** is called [observation](#observation) in ModelSkill. ### Model result -A **model result** is the output of any type of numerical model. It is the data generated by the model during a simulation. Model results can be compared with observations to assess the model's performance. In the context of validation, the term "model result" is often used interchangeably with "model output" or "model prediction". `ModelSkill` supports [point](../api/model/point.md), [track](../api/model/track.md), [dfsu](../api/model/dfsu.md) and [grid](../api/model/grid.md) model result types. +A **model result** is the output of any type of numerical model. It is the data generated by the model during a simulation. Model results can be compared with observations to assess the model's performance. In the context of validation, the term "model result" is often used interchangeably with "model output" or "model prediction". ModelSkill supports [point](../api/model/point.md), [track](../api/model/track.md), [dfsu](../api/model/dfsu.md) and [grid](../api/model/grid.md) model result types. ### Metric -A **metric** is a quantitative measure (a mathematical expression) used to evaluate the performance of a numerical model. Metrics provide a standardized way to assess the model's accuracy, precision, and other attributes. A metric aggregates the skill of a model into a single number. See list of [metrics](../api/metrics.md#modelskill.metrics) supported by `ModelSkill`. +A **metric** is a quantitative measure (a mathematical expression) used to evaluate the performance of a numerical model. Metrics provide a standardized way to assess the model's accuracy, precision, and other attributes. A metric aggregates the skill of a model into a single number. See list of [metrics](../api/metrics.md#modelskill.metrics) supported by ModelSkill. ### Score -A **score** is a numerical value that summarizes the model's performance based on chosen metrics. Scores can be used to rank or compare different models or model configurations. In the context of validation, the "skill score" or "validation score" often quantifies the model's overall performance. The score of a model is a single number, calculated as a weighted average for all time-steps, observations and variables. If you want to perform automated calibration, you can use the score as the objective function. In `ModelSkill`, [`score`](../api/comparercollection.md/#modelskill.ComparerCollection.score) is also a specific method on [Comparer](#comparer) objects that returns a single number aggregated score using a specific [metric](#metric). +A **score** is a numerical value that summarizes the model's performance based on chosen metrics. Scores can be used to rank or compare different models or model configurations. In the context of validation, the "skill score" or "validation score" often quantifies the model's overall performance. The score of a model is a single number, calculated as a weighted average for all time-steps, observations and variables. If you want to perform automated calibration, you can use the score as the objective function. In ModelSkill, [`score`](../api/comparercollection.md/#modelskill.ComparerCollection.score) is also a specific method on [Comparer](#comparer) objects that returns a single number aggregated score using a specific [metric](#metric). ## ModelSkill-specific terminology ### matched data -In ModelSkill, observations and model results are *matched* when they refer to the same positions in space and time. If the [observations](#observation) and [model results](#model-result) are already matched, the [`from_matched`](../api/matching.md/#modelskill.from_matched) function can be used to create a [Comparer](#comparer) directly. Otherwise, the [compare](#compare) function can be used to match the observations and model results in space and time. +In ModelSkill, observations and model results are *matched* when they refer to the same positions in space and time. If the [observations](#observation) and [model results](#model-result) are already matched, the [`from_matched`](../api/matching.md/#modelskill.from_matched) function can be used to create a [Comparer](#comparer) directly. Otherwise, the [match](#match) function can be used to match the observations and model results in space and time. ### match @@ -56,13 +56,27 @@ The function [`match`](../api/matching.md/#modelskill.match) is used to match a ### Comparer -A [**Comparer**](../api/comparer.md) is an object that compares a model result with observations. It is used to calculate validation metrics and generate plots. A Comparer can be created using the [`compare`](../api/matching.md/#modelskill.match) function (will return a [ComparerCollection](../api/comparercollection.md)). +A [**Comparer**](../api/comparer.md) is an object that stores the matched observation and model result data for a *single* observation. It is used to calculate validation metrics and generate plots. A Comparer can be created using the [`match`](../api/matching.md/#modelskill.match) function. ### ComparerCollection -A [**ComparerCollection**](../api/comparercollection.md) is a collection of Comparers. It is used to compare multiple model results with multiple observations. A ComparerCollection can be created using the [`compare`](../api/matching.md/#modelskill.match) function. +A [**ComparerCollection**](../api/comparercollection.md) is a collection of [Comparer](#comparer)s. It is used to compare *multiple* observations with one or more model results. A ComparerCollection can be created using the [`match`](../api/matching.md/#modelskill.match) function or by passing a list of Comparers to the [`ComparerCollection`](../api/comparercollection.md/#modelskill.ComparerCollection) constructor. ### Connector In past versions of FMSkill/ModelSkill, the Connector class was used to connect observations and model results. This class has been deprecated and is no longer in use. + +### Abbreviations + +| Abbreviation | Meaning | +| --- | --- | +| `ms` | ModelSkill | +| `o` or `obs` | Observation | +| `mr` or `mod` | Model result | +| `cmp` | `Comparer` | +| `cc` | `ComparerCollection` | +| `sk` | `SkillTable` | +| `mtr` | Metric | +| `q` | `Quantity` | + From 3c13146f2130afbb1532b8c1581ca5578a066c6a Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 3 Jan 2024 15:08:14 +0100 Subject: [PATCH 14/75] Better reprs --- modelskill/comparison/_collection.py | 7 ++++--- modelskill/comparison/_comparison.py | 7 ++++--- modelskill/model/dfsu.py | 6 +++++- modelskill/model/grid.py | 2 +- modelskill/obs.py | 4 ++-- modelskill/timeseries/_timeseries.py | 4 ++-- tests/test_pointcompare.py | 16 ++++++++-------- 7 files changed, 26 insertions(+), 20 deletions(-) diff --git a/modelskill/comparison/_collection.py b/modelskill/comparison/_collection.py index a20bbbd5f..5b6646496 100644 --- a/modelskill/comparison/_collection.py +++ b/modelskill/comparison/_collection.py @@ -222,9 +222,10 @@ def n_quantities(self) -> int: def __repr__(self): out = [] - out.append(f"<{type(self).__name__}>") - for key, value in self._comparers.items(): - out.append(f"{type(value).__name__}: {key}") + out.append("") + out.append("Comparers:") + for index, (key, value) in enumerate(self._comparers.items()): + out.append(f"{index}: {key} - {value.quantity}") return str.join("\n", out) def rename(self, mapping: Dict[str, str]) -> "ComparerCollection": diff --git a/modelskill/comparison/_comparison.py b/modelskill/comparison/_comparison.py index f438d5345..9496d9f0f 100644 --- a/modelskill/comparison/_comparison.py +++ b/modelskill/comparison/_comparison.py @@ -513,12 +513,13 @@ def from_matched_data( def __repr__(self): out = [ - f"<{type(self).__name__}>", + "", f"Quantity: {self.quantity}", f"Observation: {self.name}, n_points={self.n_points}", + "Model(s):", ] - for model in self.mod_names: - out.append(f" Model: {model}, rmse={self.score()[model]:.3f}") + for index, model in enumerate(self.mod_names): + out.append(f"{index}: {model}") for var in self.aux_names: out.append(f" Auxiliary: {var}") diff --git a/modelskill/model/dfsu.py b/modelskill/model/dfsu.py index e5a986378..3e89c8a1e 100644 --- a/modelskill/model/dfsu.py +++ b/modelskill/model/dfsu.py @@ -89,7 +89,11 @@ def __init__( def __repr__(self) -> str: # TODO add item name - return f"<{self.__class__.__name__}> '{self.name}'" + out = [ + f"<{self.__class__.__name__}>: {self.name}", + f"Quantity: {self.quantity}", + ] + return "\n".join(out) @property def time(self) -> pd.DatetimeIndex: diff --git a/modelskill/model/grid.py b/modelskill/model/grid.py index 2f79092c3..f1533ff78 100644 --- a/modelskill/model/grid.py +++ b/modelskill/model/grid.py @@ -93,7 +93,7 @@ def __init__( def __repr__(self) -> str: # TODO add item name - return f" '{self.name}'" + return f": {self.name}" @property def time(self) -> pd.DatetimeIndex: diff --git a/modelskill/obs.py b/modelskill/obs.py index 73a41fc40..0c28b928a 100644 --- a/modelskill/obs.py +++ b/modelskill/obs.py @@ -218,7 +218,7 @@ def z(self, value): self.data["z"] = value def __repr__(self): - out = f"PointObservation: {self.name}, x={self.x}, y={self.y}" + out = f": {self.name}, x={self.x}, y={self.y}" if len(self._aux_vars) > 0: out += f", aux={self._aux_vars}" return out @@ -355,7 +355,7 @@ def __init__( super().__init__(data=data, weight=weight) def __repr__(self): - out = f"TrackObservation: {self.name}, n={self.n_points}" + out = f": {self.name}, n={self.n_points}" if len(self._aux_vars) > 0: out += f", aux={self._aux_vars}" return out diff --git a/modelskill/timeseries/_timeseries.py b/modelskill/timeseries/_timeseries.py index a15ad4047..e25464bd8 100644 --- a/modelskill/timeseries/_timeseries.py +++ b/modelskill/timeseries/_timeseries.py @@ -178,7 +178,7 @@ def quantity(self, quantity: Quantity) -> None: # TODO: """Color of time series"""; Hide until used @property - def _color(self) -> str: + def _color(self) -> str: return str(self.data[self.name].attrs["color"]) @_color.setter @@ -232,7 +232,7 @@ def _values_as_series(self) -> pd.Series: return self.data[self.name].to_series() def __repr__(self) -> str: - return f"<{self.__class__.__name__}> '{self.name}' (n_points: {self.n_points})" + return f"<{self.__class__.__name__}>: {self.name} (n_points: {self.n_points})" # len() of a DataFrame returns the number of rows, # len() of xr.Dataset returns the number of variables diff --git a/tests/test_pointcompare.py b/tests/test_pointcompare.py index 99f617446..54c642b1d 100644 --- a/tests/test_pointcompare.py +++ b/tests/test_pointcompare.py @@ -67,17 +67,17 @@ def test_subset_cc_for_named_comparers(cc): ccs = cc[("Klagshamn", "dmi_30357_Drogden_Fyr")] assert len(ccs) == 2 - assert ( - repr(ccs) - == "\nComparer: Klagshamn\nComparer: dmi_30357_Drogden_Fyr" - ) + repr_text = repr(ccs) + assert "" in repr_text + assert "Klagshamn" in repr_text + assert "dmi_30357_Drogden_Fyr" in repr_text ccs2 = cc[["dmi_30357_Drogden_Fyr", "Klagshamn"]] + repr_text = repr(ccs2) assert len(ccs2) - assert ( - repr(ccs2) - == "\nComparer: dmi_30357_Drogden_Fyr\nComparer: Klagshamn" - ) + assert "" in repr_text + assert "Klagshamn" in repr_text + assert "dmi_30357_Drogden_Fyr" in repr_text def test_iterate_over_comparers(cc): From f9c649757e2d96ebc9b6ccb3515502042b24d098 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 3 Jan 2024 15:08:37 +0100 Subject: [PATCH 15/75] Try to improve repr_html --- modelskill/skill.py | 3 ++- tests/test_aggregated_skill.py | 17 +++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/modelskill/skill.py b/modelskill/skill.py index 56d310c80..19f9f3d7e 100644 --- a/modelskill/skill.py +++ b/modelskill/skill.py @@ -435,7 +435,8 @@ def __repr__(self): return repr(self._df) def _repr_html_(self): - return self._df._repr_html_() + pd_repr_html = self._df._repr_html_() + return pd_repr_html.replace("<SkillTable>

\n SkillArray: diff --git a/tests/test_aggregated_skill.py b/tests/test_aggregated_skill.py index 8b69796e6..f8eaed965 100644 --- a/tests/test_aggregated_skill.py +++ b/tests/test_aggregated_skill.py @@ -86,18 +86,15 @@ def test_skill_table(sk_df1): assert sk.metrics == ["n", "bias", "rmse", "corr", "si", "r2"] -def test_skill_table_odd_index(sk_df2): - # having a different index name works - sk_df2.index.name = "odd" - sk = ms.SkillTable(sk_df2) - assert sk.obs_names == [] - assert sk.mod_names == [] - assert sk.quantity_names == [] - assert sk.metrics == ["n", "bias", "rmse", "corr"] +def test_skill_repr_html(sk_df1): + sk = ms.SkillTable(sk_df1) + repr_html = sk._repr_html_() + assert "SkillTable" in repr_html + assert "obs1" in repr_html -def test_skill_table_2rows(sk_df2): - sk = ms.SkillTable(sk_df2) +def test_skill_table_odd_index(sk_df2): + # having a different index name worksprint assert sk.obs_names[0] == "obs1" assert sk.obs_names[1] == "obs2" assert sk.mod_names == [] From c214d7e8ec7e5f2a1e83a31fcc241a2e03e1e77b Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 3 Jan 2024 15:39:25 +0100 Subject: [PATCH 16/75] Oops --- tests/test_aggregated_skill.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_aggregated_skill.py b/tests/test_aggregated_skill.py index f8eaed965..8e0e8e5cb 100644 --- a/tests/test_aggregated_skill.py +++ b/tests/test_aggregated_skill.py @@ -94,7 +94,8 @@ def test_skill_repr_html(sk_df1): def test_skill_table_odd_index(sk_df2): - # having a different index name worksprint + # having a different index name works + sk = ms.SkillTable(sk_df2) assert sk.obs_names[0] == "obs1" assert sk.obs_names[1] == "obs2" assert sk.mod_names == [] From 84072ca1e196ada969d5e5a22fc651a87bfd775f Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Thu, 4 Jan 2024 08:22:47 +0100 Subject: [PATCH 17/75] index instead of id --- docs/getting-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index f1624caeb..16e362e2f 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -106,9 +106,9 @@ In order to select only a subset of the data for analysis, the comparer has a `s This method allow filtering of the data in several ways: -- on `observation` by specifying name or id of one or more +- on `observation` by specifying name or index of one or more observations -- on `model` (if more than one is compared) by giving name or id +- on `model` (if more than one is compared) by giving name or index - temporal using the `time` (or `start` and `end`) arguments - spatial using the `area` argument given as a bounding box or a polygon From 007adf2a1a3990f4d1947369d62f8469b8130c3d Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:14:41 +0100 Subject: [PATCH 18/75] Matching page --- docs/user-guide/matching.md | 75 +++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 76 insertions(+) create mode 100644 docs/user-guide/matching.md diff --git a/docs/user-guide/matching.md b/docs/user-guide/matching.md new file mode 100644 index 000000000..50efb60b8 --- /dev/null +++ b/docs/user-guide/matching.md @@ -0,0 +1,75 @@ +# Matching + +Once observations and model results have been defined, the next step is to match them. This is done using the `match()` function which handles the allignment of the observation and model result data in space and time. Note that if the data is already matched, the `from_matched()` function can be used to create a `Comparer` directly from the matched data and the matching described here is not needed. + +The observation is considered the *truth* and the model result data is therefore interpolated to the observation data positions. + +The matching process will be different depending on the geometry of observation and model result: + +* Geometries are the *same* (e.g. both are point time series): only temporal matching is needed +* Geometries are *different* (e.g. observation is a point time series and model result is a grid): data is first spatially *extracted* from the model result and *then* matched in time. + + +## Temporal matching + +Temporal matching is done by interpolating the model result data to the observation data time points; it is carried out after spatial matching when applicable. The interpolation is *linear* in time and done inside the `match()` function. + + + +## Matching of time series + +If observation and model result are of the same geometry, the matching is done *one* observation at a time. Several model results can be matched to the same observation. The result of the matching process is a `Comparer` object which contains the matched data. + +```python +>>> o = ms.observation('obs.dfs0', item='waterlevel') +>>> mr1 = ms.model_result('model1.dfs0', item='WL1') +>>> mr2 = ms.model_result('model2.dfs0', item='WL2') +>>> cmp = ms.match(o, [mr1, mr2]) +``` + +In most cases, *several* observations needs to matched with several model results. This can be done by constructing a list of `Comparer` objects and then combining them into a `ComparerCollection`: + +```python +>>> cmps = [] +>>> for o in observations: +>>> mr1 = ... +>>> mr2 = ... +>>> cmps.append(ms.match(o, [mr1, mr2])) +>>> cc = ms.ComparerCollection(cmps) +``` + + +## Matching with dfsu or grid model result + +If the model result is a SpatialField, i.e., either a `GridModelResult` or a `DfsuModelResult`, and the observation is of lower dimension (e.g. point), then the model result needs to be *extracted* before matching can be done. This can be done "offline" before using ModelSkill, e.g., using [MIKE](https://www.mikepoweredbydhi.com/) tools or [MIKE IO](https://github.com/DHI/mikeio), or as part of the matching process using ModelSkill. We will here focus on the latter. + +In this situation, *multiple* observations can be matched to the same model result, in which case the `match` function returns a `ComparerCollection` instead of a `Comparer` which is the returned object for single observation matching. + +```python +>>> o1 = ms.observation('obs1.dfs0', item='waterlevel') +>>> o2 = ms.observation('obs2.dfs0', item='waterlevel') +>>> mr = ms.model_result('model.dfsu', item='WaterLevel') +>>> cc = ms.match([o1, o2], mr) # returns a ComparerCollection +``` + +Matching `PointObservation`s with `SpatialField` model results consists of two steps: + +1. Extracting data from the model result at the spatial position of the observation, which returns a PointModelResult +2. Matching the extracted data with the observation data in time + +Matching `TrackObservation`s with `SpatialField` model results is for technical reasons handled in *one* step, i.e., the data is extracted in both space and time. + + + +### Extracting data from a DfsuModelResult + + + +### Extracting data from a GridModelResult + + + + +## Event-based matching and handling of gaps + +If the model result data contains gaps either because only events are stored or because of missing data, the `max_model_gap` argument of the `match()` function can be used to specify the maximum allowed gap (in seconds) in the model result data. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index c7e9f7c8a..557baaa71 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,6 +16,7 @@ nav: - 'getting-started.md' - 'user-guide/terminology.md' - 'user-guide/data-structures.md' + - 'user-guide/matching.md' - 'user-guide/selecting-data.md' - 'overview.md' - API Reference: From 3f67b6268f1a337f0da64ceb6c43b8521d1c6a43 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:14:54 +0100 Subject: [PATCH 19/75] docstring detail --- modelskill/model/point.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modelskill/model/point.py b/modelskill/model/point.py index 955ca1e49..10fc27c51 100644 --- a/modelskill/model/point.py +++ b/modelskill/model/point.py @@ -81,6 +81,8 @@ def interp_time( ) -> PointModelResult: """Interpolate time series to new time index + wrapper around xarray.Dataset.interp() + Parameters ---------- new_time : pd.DatetimeIndex @@ -88,7 +90,7 @@ def interp_time( dropna : bool, optional drop nan values, by default True **kwargs - keyword arguments passed to xarray.interp() + keyword arguments passed to xarray.Dataset.interp() Returns ------- From b354ccaf81a163b7dc01630150435e1409f6155a Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:29:25 +0100 Subject: [PATCH 20/75] add dummy --- docs/api/model/dummy.md | 3 +++ mkdocs.yml | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 docs/api/model/dummy.md diff --git a/docs/api/model/dummy.md b/docs/api/model/dummy.md new file mode 100644 index 000000000..3619e7ba0 --- /dev/null +++ b/docs/api/model/dummy.md @@ -0,0 +1,3 @@ +# DummyModelResult + +::: modelskill.DummyModelResult diff --git a/mkdocs.yml b/mkdocs.yml index 557baaa71..857ed3d77 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -32,7 +32,8 @@ nav: - PointModelResult: 'api/model/point.md' - TrackModelResult: 'api/model/track.md' - DfsuModelResult: 'api/model/dfsu.md' - - GridModelResult: 'api/model/grid.md' + - GridModelResult: 'api/model/grid.md' + - DummyModelResult: 'api/model/dummy.md' - 'api/matching.md' - 'api/comparer.md' - 'api/comparercollection.md' From cc9710376a56383730a69656796d39525821b7be Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:41:32 +0100 Subject: [PATCH 21/75] Extend --- docs/user-guide/matching.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/user-guide/matching.md b/docs/user-guide/matching.md index 50efb60b8..8d6beed3b 100644 --- a/docs/user-guide/matching.md +++ b/docs/user-guide/matching.md @@ -52,24 +52,43 @@ In this situation, *multiple* observations can be matched to the same model resu >>> cc = ms.match([o1, o2], mr) # returns a ComparerCollection ``` -Matching `PointObservation`s with `SpatialField` model results consists of two steps: +Matching `PointObservation` with `SpatialField` model results consists of two steps: 1. Extracting data from the model result at the spatial position of the observation, which returns a PointModelResult 2. Matching the extracted data with the observation data in time -Matching `TrackObservation`s with `SpatialField` model results is for technical reasons handled in *one* step, i.e., the data is extracted in both space and time. +Matching `TrackObservation` with `SpatialField` model results is for technical reasons handled in *one* step, i.e., the data is extracted in both space and time. + +The spatial matching method (selection or interpolation) can be specified using the `spatial_method` argument of the `match()` function. The default method depends on the type of observation and model result as specified in the sections below. ### Extracting data from a DfsuModelResult +Extracting data for a specific point position from the flexible mesh dfsu files can be done in several ways (specified by the `spatial_method` argument of the `match()` function): + +* Selection of the "contained" element +* Selection of the "nearest" element (often the same as the contained element, but not always) +* Interpolation with "inverse_distance" weighting (IDW) using the five nearest elements (default) + + +The default (inverse_distance) is not necessarily the best method in all cases. When the extracted position is close to the model boundary, "contained" may be a better choice. + +```python +>>> cc = ms.match([o1, o2], mr_dfsu, spatial_method='contained') +``` + +Note that extraction of *track* data does not currently support the "contained" method. + +Note that the extraction of point data from 3D dfsu files is not yet fully supported. It is recommended to extract the data "offline" prior to using ModelSkill. ### Extracting data from a GridModelResult +Extracting data from a GridModelResult is done through xarray's `interp()` function. The `spatial_method` argument of the `match()` function is passed on to the `interp()` function as the `method` argument. The default method is "linear" which is the recommended method for most cases. Close to land where the grid model result data is often missing, "nearest" may be a better choice. ## Event-based matching and handling of gaps -If the model result data contains gaps either because only events are stored or because of missing data, the `max_model_gap` argument of the `match()` function can be used to specify the maximum allowed gap (in seconds) in the model result data. \ No newline at end of file +If the model result data contains gaps either because only events are stored or because of missing data, the `max_model_gap` argument of the `match()` function can be used to specify the maximum allowed gap (in seconds) in the model result data. This will avoid interpolating model data over long gaps in the model result data! \ No newline at end of file From 625852ef3381901c0ba7ad7453f3749db948222d Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:55:35 +0100 Subject: [PATCH 22/75] cross ref links in api docs --- docs/api/comparer.md | 28 ++++++++++++++-------------- docs/api/matching.md | 4 ++-- docs/api/model/index.md | 10 +++++----- docs/api/observation/index.md | 6 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/api/comparer.md b/docs/api/comparer.md index 4e0ea41bb..163d97d9c 100644 --- a/docs/api/comparer.md +++ b/docs/api/comparer.md @@ -1,26 +1,26 @@ # Comparer -The `Comparer` class is the main class of the ModelSkill package. It holds the *matched* observation and model data for a *single* observation and has methods for plotting and skill assessment. +The `Comparer` class is the main class of the ModelSkill package. It is returned by [`match()`](matching.md/#modelskill.match), [`from_matched()`](matching.md/#modelskill.from_matched) or as an element in a [`ComparerCollection`](comparercollection.md). It holds the *matched* observation and model data for a *single* observation and has methods for plotting and skill assessment. Main functionality: * selecting/filtering data - - `sel()` - - `query()` + - [`sel()`](#modelskill.Comparer.sel) + - [`query()`](#modelskill.Comparer.query) * skill assessment - - `skill()` - - `gridded_skill()` (for track observations) + - [`skill()`](#modelskill.Comparer.skill) + - [`gridded_skill()`](#modelskill.Comparer.gridded_skill) (for track observations) * plotting - - `plot.timeseries()` - - `plot.scatter()` - - `plot.kde()` - - `plot.qq()` - - `plot.hist()` - - `plot.box()` + - [`plot.timeseries()`](#modelskill.comparison._comparer_plotter.ComparerPlotter.timeseries) + - [`plot.scatter()`](#modelskill.comparison._comparer_plotter.ComparerPlotter.scatter) + - [`plot.kde()`](#modelskill.comparison._comparer_plotter.ComparerPlotter.kde) + - [`plot.qq()`](#modelskill.comparison._comparer_plotter.ComparerPlotter.qq) + - [`plot.hist()`](#modelskill.comparison._comparer_plotter.ComparerPlotter.hist) + - [`plot.box()`](#modelskill.comparison._comparer_plotter.ComparerPlotter.box) * load/save/export data - - `load()` - - `save()` - - `to_dataframe()` + - [`load()`](#modelskill.Comparer.load) + - [`save()`](#modelskill.Comparer.save) + - [`to_dataframe()`](#modelskill.Comparer.to_dataframe) diff --git a/docs/api/matching.md b/docs/api/matching.md index 12683eab2..0b8ef9cdf 100644 --- a/docs/api/matching.md +++ b/docs/api/matching.md @@ -3,8 +3,8 @@ A Comparer/ComparerCollection can be created in one of the following ways: * [`match()`](#modelskill.match) - match observations and model results -* [`from_matched()`](#modelskill.from_matched) - create a Comparer/ComparerCollection from matched data -* [`from_config()`](#modelskill.from_config) - create a Comparer/ComparerCollection from a config file +* [`from_matched()`](#modelskill.from_matched) - create a Comparer from matched data +* [`from_config()`](#modelskill.from_config) - create a ComparerCollection from a config file ::: modelskill.match diff --git a/docs/api/model/index.md b/docs/api/model/index.md index 54aafe9d0..333d80219 100644 --- a/docs/api/model/index.md +++ b/docs/api/model/index.md @@ -3,11 +3,11 @@ A model result can either be a simple point/track, or spatial field (e.g. 2d dfsu file) from which data can be *extracted* at the observation positions by spatial interpolation. The following types are available: * Timeseries - - `PointModelResult` - a point result from a dfs0/nc file or a DataFrame - - `TrackModelResult` - a track (moving point) result from a dfs0/nc file or a DataFrame + - [`PointModelResult`](point.md) - a point result from a dfs0/nc file or a DataFrame + - [`TrackModelResult`](track.md) - a track (moving point) result from a dfs0/nc file or a DataFrame * SpatialField (extractable) - - `GridModelResult` - a spatial field from a dfs2/nc file or a Xarray Dataset - - `DfsuModelResult` - a spatial field from a dfsu file + - [`GridModelResult`](grid.md) - a spatial field from a dfs2/nc file or a Xarray Dataset + - [`DfsuModelResult`](dfsu.md) - a spatial field from a dfsu file -A model result can be created by explicitly invoking one of the above classes or using the `model_result()` function which will return the appropriate type based on the input data (if possible). +A model result can be created by explicitly invoking one of the above classes or using the [`model_result()`](model_result.md) function which will return the appropriate type based on the input data (if possible). diff --git a/docs/api/observation/index.md b/docs/api/observation/index.md index b9d476ae3..9ae8391c8 100644 --- a/docs/api/observation/index.md +++ b/docs/api/observation/index.md @@ -2,8 +2,8 @@ ModelSkill supports two types of observations: -* `PointObservation` - a point timeseries from a dfs0/nc file or a DataFrame -* `TrackObservation` - a track (moving point) timeseries from a dfs0/nc file or a DataFrame +* [`PointObservation`](point.md) - a point timeseries from a dfs0/nc file or a DataFrame +* [`TrackObservation`](track.md) - a track (moving point) timeseries from a dfs0/nc file or a DataFrame -An observation can be created by explicitly invoking one of the above classes or using the `observation()` function which will return the appropriate type based on the input data (if possible). +An observation can be created by explicitly invoking one of the above classes or using the [`observation()`](observation.md) function which will return the appropriate type based on the input data (if possible). From 76c36735ec7743fbb278a6113a00783dd81bffe8 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:55:51 +0100 Subject: [PATCH 23/75] Main functionality of ComparerCollection with links --- docs/api/comparercollection.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/api/comparercollection.md b/docs/api/comparercollection.md index 0941b1aa3..2ec69dc5d 100644 --- a/docs/api/comparercollection.md +++ b/docs/api/comparercollection.md @@ -1,6 +1,25 @@ # ComparerCollection -The `ComparerCollection` is one of the main objects of the `modelskill` package. It is collection of `Comparer` objects and is returned by the `match()` method of the `Model` class. +The `ComparerCollection` is one of the main objects of the `modelskill` package. It is a collection of [`Comparer`](comparer.md) objects and created either by the [`match()`](matching.md/#modelskill.match) method, by passing a list of Comparers to the [`ComparerCollection`](comparercollection.md/#modelskill.ComparerCollection) constructor, or by reading a config file using the [`from_config()`](matching.md/#modelskill.from_config) function. + +Main functionality: + +* selecting/filtering data + - `__get_item__()` - get a single Comparer, e.g., `cc[0]` or `cc['obs1']` + - [`sel()`](#modelskill.ComparerCollection.sel) + - [`query()`](#modelskill.ComparerCollection.query) +* skill assessment + - [`skill()`](#modelskill.ComparerCollection.skill) + - [`mean_skill()`](#modelskill.ComparerCollection.mean_skill) + - [`gridded_skill()`](#modelskill.ComparerCollection.gridded_skill) (for track observations) +* plotting + - [`plot.scatter()`](#modelskill.comparison._collection_plotter.ComparerCollectionPlotter.scatter) + - [`plot.kde()`](#modelskill.comparison._collection_plotter.ComparerCollectionPlotter.kde) + - [`plot.hist()`](#modelskill.comparison._collection_plotter.ComparerCollectionPlotter.hist) +* load/save/export data + - [`load()`](#modelskill.ComparerCollection.load) + - [`save()`](#modelskill.ComparerCollection.save) + ::: modelskill.ComparerCollection From 9ce779fbbaf5aff9ead832d7aa23a19bb52ddba9 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:56:00 +0100 Subject: [PATCH 24/75] example --- docs/user-guide/matching.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/user-guide/matching.md b/docs/user-guide/matching.md index 8d6beed3b..642450312 100644 --- a/docs/user-guide/matching.md +++ b/docs/user-guide/matching.md @@ -87,6 +87,9 @@ Note that the extraction of point data from 3D dfsu files is not yet fully suppo Extracting data from a GridModelResult is done through xarray's `interp()` function. The `spatial_method` argument of the `match()` function is passed on to the `interp()` function as the `method` argument. The default method is "linear" which is the recommended method for most cases. Close to land where the grid model result data is often missing, "nearest" may be a better choice. +```python +>>> cc = ms.match([o1, o2], mr_netcdf, spatial_method='nearest') +``` ## Event-based matching and handling of gaps From ef0292de05cf7d8e248a2a4ba1113c02e1de0f25 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:56:23 +0100 Subject: [PATCH 25/75] remove subsections in terminology --- docs/user-guide/terminology.md | 38 +++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/docs/user-guide/terminology.md b/docs/user-guide/terminology.md index 00573ed70..81db31c1a 100644 --- a/docs/user-guide/terminology.md +++ b/docs/user-guide/terminology.md @@ -3,71 +3,67 @@ ModelSkill is a library for assessing the skill of numerical models. It provides tools for comparing model results with observations, plotting the results and calculating validation metrics. This page defines some of the key terms used in the documentation. -## General terminology +## Skill +**Skill** refers to the ability of a numerical model to accurately represent the real-world phenomenon it aims to simulate. It is a measure of how well the model performs in reproducing the observed system. Skill can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In ModelSkill, [`skill`](../api/comparer.md/#modelskill.Comparer.skill) is also a specific method on [Comparer](#comparer) objects that returns a [`SkillTable`](../api/skill.md) with aggregated skill scores per observation and model for a list of selected [metrics](#metric). -### Skill -**Skill** refers to the ability of a numerical model to accurately represent the real-world phenomenon it aims to simulate. It is a measure of how well the model performs in reproducing the observed system. Skill can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In ModelSkill, [`skill`](../api/skill.md) is also a specific method on [Comparer](#comparer) objects that returns a skill table with aggregated skill scores per observation and model for a list of selected [metrics](#metric). - -### Validation +## Validation **Validation** is the process of assessing the model's performance by comparing its output to real-world observations or data collected from the system being modeled. It helps ensure that the model accurately represents the system it simulates. Validation is typically performed before the model is used for prediction or decision-making. -### Calibration +## Calibration **Calibration** is the process of adjusting the model's parameters or settings to improve its performance. It involves fine-tuning the model to better match observed data. Calibration aims to reduce discrepancies between model predictions and actual measurements. At the end of the calibration process, the calibrated model should be validated with independent data. -### Performance +## Performance **Performance** is a measure of how well a numerical model operates in reproducing the observed system. It can be assessed using various metrics, such as accuracy, precision, and reliability, depending on the specific goals of the model and the nature of the data. In this context, **performance** is synonymous with **skill**. -### Timeseries +## Timeseries A **timeseries** is a sequence of data points in time. In ModelSkill, The data can either be from [observations](#observation) or [model results](#model-result). Timeseries can univariate or multivariate; ModelSkill primarily supports univariate timeseries. Multivariate timeseries can be assessed one variable at a time. Timeseries can also have different spatial dimensions, such as point, track, line, or area. -### Observation +## Observation An **observation** refers to real-world data or measurements collected from the system you are modeling. Observations serve as a reference for assessing the model's performance. These data points are used to compare with the model's predictions during validation and calibration. Observations are usually based on field measurements or laboratory experiments, but for the purposes of model validation, they can also be derived from other models (e.g. a reference model). ModelSkill supports [point](../api/observation/point.md) and [track](../api/observation/track.md) observation types. -### Measurement +## Measurement A **measurement** is called [observation](#observation) in ModelSkill. -### Model result +## Model result A **model result** is the output of any type of numerical model. It is the data generated by the model during a simulation. Model results can be compared with observations to assess the model's performance. In the context of validation, the term "model result" is often used interchangeably with "model output" or "model prediction". ModelSkill supports [point](../api/model/point.md), [track](../api/model/track.md), [dfsu](../api/model/dfsu.md) and [grid](../api/model/grid.md) model result types. -### Metric +## Metric A **metric** is a quantitative measure (a mathematical expression) used to evaluate the performance of a numerical model. Metrics provide a standardized way to assess the model's accuracy, precision, and other attributes. A metric aggregates the skill of a model into a single number. See list of [metrics](../api/metrics.md#modelskill.metrics) supported by ModelSkill. -### Score +## Score A **score** is a numerical value that summarizes the model's performance based on chosen metrics. Scores can be used to rank or compare different models or model configurations. In the context of validation, the "skill score" or "validation score" often quantifies the model's overall performance. The score of a model is a single number, calculated as a weighted average for all time-steps, observations and variables. If you want to perform automated calibration, you can use the score as the objective function. In ModelSkill, [`score`](../api/comparercollection.md/#modelskill.ComparerCollection.score) is also a specific method on [Comparer](#comparer) objects that returns a single number aggregated score using a specific [metric](#metric). -## ModelSkill-specific terminology - -### matched data +## Matched data In ModelSkill, observations and model results are *matched* when they refer to the same positions in space and time. If the [observations](#observation) and [model results](#model-result) are already matched, the [`from_matched`](../api/matching.md/#modelskill.from_matched) function can be used to create a [Comparer](#comparer) directly. Otherwise, the [match](#match) function can be used to match the observations and model results in space and time. -### match +## match() The function [`match`](../api/matching.md/#modelskill.match) is used to match a model result with observations. It returns a [`Comparer`](../api/comparer.md) object or a [`ComparerCollection`](../api/comparercollection.md) object. -### Comparer +## Comparer A [**Comparer**](../api/comparer.md) is an object that stores the matched observation and model result data for a *single* observation. It is used to calculate validation metrics and generate plots. A Comparer can be created using the [`match`](../api/matching.md/#modelskill.match) function. -### ComparerCollection +## ComparerCollection A [**ComparerCollection**](../api/comparercollection.md) is a collection of [Comparer](#comparer)s. It is used to compare *multiple* observations with one or more model results. A ComparerCollection can be created using the [`match`](../api/matching.md/#modelskill.match) function or by passing a list of Comparers to the [`ComparerCollection`](../api/comparercollection.md/#modelskill.ComparerCollection) constructor. -### Connector +## Connector In past versions of FMSkill/ModelSkill, the Connector class was used to connect observations and model results. This class has been deprecated and is no longer in use. -### Abbreviations +## Abbreviations | Abbreviation | Meaning | | --- | --- | From a2a62dd52e5f870ac53dc2c3f3b11d113d1cde0b Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:49:35 +0100 Subject: [PATCH 26/75] plotting --- docs/images/obs_timeseries.png | Bin 0 -> 26885 bytes docs/images/plot_taylor.png | Bin 0 -> 112056 bytes docs/images/spatial_overview.png | Bin 0 -> 19780 bytes docs/images/temporal_coverage.png | Bin 0 -> 10426 bytes docs/images/wind_rose.png | Bin 0 -> 158158 bytes docs/user-guide/plotting.md | 78 +++++++++++++++++++ mkdocs.yml | 1 + modelskill/comparison/_collection_plotter.py | 10 +++ modelskill/comparison/_comparer_plotter.py | 12 ++- modelskill/skill.py | 10 +++ modelskill/timeseries/_timeseries.py | 8 ++ 11 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 docs/images/obs_timeseries.png create mode 100644 docs/images/plot_taylor.png create mode 100644 docs/images/spatial_overview.png create mode 100644 docs/images/temporal_coverage.png create mode 100644 docs/images/wind_rose.png create mode 100644 docs/user-guide/plotting.md diff --git a/docs/images/obs_timeseries.png b/docs/images/obs_timeseries.png new file mode 100644 index 0000000000000000000000000000000000000000..a7beeb39693039a5c5535f532c069a2cc95f1b41 GIT binary patch literal 26885 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 literal 0 HcmV?d00001 diff --git a/docs/images/plot_taylor.png b/docs/images/plot_taylor.png new file mode 100644 index 0000000000000000000000000000000000000000..f59f93c473ae3da955b98065b144c689f5c6404b GIT binary patch literal 112056 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

-@ohkWXGBDh6__U{C#l=> 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 literal 0 HcmV?d00001 diff --git a/docs/images/spatial_overview.png b/docs/images/spatial_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..9b53e5c967841b03aec036e8d6211993fa5e1f9b GIT binary patch literal 19780 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

NjpQ3RqI@ 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 oun5 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 QQt)S_^;qRWOZQd(2iGq>*8l(j literal 0 HcmV?d00001 diff --git a/docs/user-guide/plotting.md b/docs/user-guide/plotting.md new file mode 100644 index 000000000..afba8b6fa --- /dev/null +++ b/docs/user-guide/plotting.md @@ -0,0 +1,78 @@ +# Plotting + +## Plotting observations and model results + +PointObservations and PointModelResults can be plotted using their `plot` accessor: + +```python +>>> o.plot.timeseries() +>>> mr.plot.timeseries() +>>> mr.plot.hist() +``` + +Only the observation time series is shown here: + +![Timeseries plot](../images/obs_timeseries.png) + + +## Plotting temporal coverage + +The temporal coverage of observations and model results can be plotted using the [`temporal_coverage`](../api/plotting.md/#modelskill.plotting.temporal_coverage) function in the [`plotting`](../api/plotting.md) module: + +```python +>>> o1 = ms.PointObservation('HKNA.dfs0', item=0, x=4.2420, y=52.6887) +>>> o2 = ms.PointObservation('EPL.dfs0', item=0, x=3.2760, y=51.9990) +>>> o3 = ms.TrackObservation("Alti_c2.dfs0", item=3) +>>> mr = ms.DfsuModelResult('HKZN_local.dfsu', item=0) +>>> ms.plotting.temporal_coverage(obs=[o1, o2, o3], mod=mr) +``` + +![Temporal coverage](../images/temporal_coverage.png) + + +## Plotting spatial overview + +The spatial coverage of observations and model results can be plotted using the [`spatial_overview`](../api/plotting.md/#modelskill.plotting.spatial_overview) function in the [`plotting`](../api/plotting.md) module: + +```python +>>> ms.plotting.spatial_overview([o1, o2, o3], mr) +``` + +![Spatial overview](../images/spatial_overview.png) + + +## Plotting compared data + +The `plot` accessor on a Comparer or ComparerCollection object can be used to plot the compared data: + +```python +>>> cmp.plot.timeseries() +>>> cc.plot.timeseries() +>>> cc.plot.scatter() +``` + + +## Plotting Taylor diagrams + +A Taylor diagram shows how well a model result matches an observation in terms of correlation, standard deviation and root mean square error. The `taylor` plot can be accessed through the Comparer [`plot`](api/comparer.md/#modelskill.comparison._comparer_plotter.ComparerPlotter) accessor or the ComparerCollection [`plot`](../api/comparercollection.md/#modelskill.comparison._collection_plotter.ComparerCollectionPlotter) accessor: + +```python +>>> cc = ms.match([o1, o2, o3], [mr_CMEMS, mr_ERA5, mr_MIKE21SW]) +>>> cc.plot.taylor() +``` + +![Taylor diagram](../images/plot_taylor.png) + +The radial distance from the point to the observation point is the standard deviation ratio, the angle is the correlation coefficient and the distance from the observation point to the model point is the root mean square error ratio. The closer the model point is to the observation point, the better the model result matches the observation. The closer the model point is to the origin, the better the model result matches the observation in terms of standard deviation and root mean square error. The closer the model point is to the horizontal axis, the better the model result matches the observation in terms of correlation. + + +## Plotting directional data (e.g. wind or currents) + +Directional data can be plotted using the [`wind_rose`](../api/plotting.md/#modelskill.plotting.wind_rose) function in the [`plotting`](../api/plotting.md) module. The function takes an array-like structure with speed and direction as columns (from one or two sources) and plots a wind rose: + +```python +>>> df = pd.read_csv('wind.csv', index_col=0, parse_dates=True) +>>> ms.plotting.wind_rose(df) +``` + +![Wind rose](../images/wind_rose.png) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 857ed3d77..f12082e5d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,6 +17,7 @@ nav: - 'user-guide/terminology.md' - 'user-guide/data-structures.md' - 'user-guide/matching.md' + - 'user-guide/plotting.md' - 'user-guide/selecting-data.md' - 'overview.md' - API Reference: diff --git a/modelskill/comparison/_collection_plotter.py b/modelskill/comparison/_collection_plotter.py index 50c59fb42..53cde0a6e 100644 --- a/modelskill/comparison/_collection_plotter.py +++ b/modelskill/comparison/_collection_plotter.py @@ -20,6 +20,16 @@ def _default_univarate_title(kind: str, cc: ComparerCollection) -> str: class ComparerCollectionPlotter: + """Plotter for ComparerCollection + + Examples + -------- + >>> cc.plot.scatter() + >>> cc.plot.hist() + >>> cc.plot.kde() + >>> cc.plot.taylor() + """ + def __init__(self, cc: ComparerCollection) -> None: self.cc = cc self.is_directional = False diff --git a/modelskill/comparison/_comparer_plotter.py b/modelskill/comparison/_comparer_plotter.py index c28ac977f..398a74610 100644 --- a/modelskill/comparison/_comparer_plotter.py +++ b/modelskill/comparison/_comparer_plotter.py @@ -32,7 +32,17 @@ class ComparerPlotter: - """Plotter class for Comparer""" + """Plotter class for Comparer + + Examples + -------- + >>> cmp.plot.scatter() + >>> cmp.plot.timeseries() + >>> cmp.plot.hist() + >>> cmp.plot.kde() + >>> cmp.plot.qq() + >>> cmp.plot.box() + """ def __init__(self, comparer: Comparer) -> None: self.comparer = comparer diff --git a/modelskill/skill.py b/modelskill/skill.py index 49491eddd..571cb0d31 100644 --- a/modelskill/skill.py +++ b/modelskill/skill.py @@ -308,7 +308,17 @@ class SkillArray: def __init__(self, data: pd.DataFrame) -> None: self.data = data self._ser = data.iloc[:, -1] # last column is the metric + self.plot = SkillArrayPlotter(self) + """Plot using the SkillArrayPlotter + + Examples + -------- + >>> sk.rmse.plot.line() + >>> sk.rmse.plot.bar() + >>> sk.rmse.plot.barh() + >>> sk.rmse.plot.grid() + """ def to_dataframe(self, drop_xy=True) -> pd.DataFrame: """Convert SkillArray to pd.DataFrame diff --git a/modelskill/timeseries/_timeseries.py b/modelskill/timeseries/_timeseries.py index 86262c4c5..086978b2d 100644 --- a/modelskill/timeseries/_timeseries.py +++ b/modelskill/timeseries/_timeseries.py @@ -125,7 +125,15 @@ class TimeSeries: def __init__(self, data: xr.Dataset) -> None: self.data = data if self._is_input_validated(data) else _validate_dataset(data) + self.plot: TimeSeriesPlotter = TimeSeries.plotter(self) + """Plot using the ComparerPlotter + + Examples + -------- + >>> obj.plot.timeseries() + >>> obj.plot.hist() + """ def _is_input_validated(self, data: Any) -> bool: """Check if data is already a valid TimeSeries (contains the modelskill_version attribute)""" From 08c4d460013e063c1b2d2d9313ca4dd5deff95d6 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:55:57 +0100 Subject: [PATCH 27/75] index --- docs/user-guide/index.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md index 0d30babb8..6f7168df9 100644 --- a/docs/user-guide/index.md +++ b/docs/user-guide/index.md @@ -1,3 +1,10 @@ # User Guide -xx \ No newline at end of file +ModelSkill compares model results with observations. The workflow can be split in two phases: + +1. [Matching](matching.md) - making sure that observations and model results are in the same space and time +2. Analysis - [plots](plotting.md) and [statistics](skill.md) of the matched data + +If the observations and model results are already matched (i.e. are stored in the same data source), +the `from_matched()` function can be used to go directly to the analysis phase. +If not, the `match()` function can be used to match the observations and model results in space and time. From ad3925138f2c3fcf0fc39a2bea2837cdf8b62982 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:56:04 +0100 Subject: [PATCH 28/75] Update matching.md --- docs/user-guide/matching.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/matching.md b/docs/user-guide/matching.md index 642450312..951bcc4df 100644 --- a/docs/user-guide/matching.md +++ b/docs/user-guide/matching.md @@ -15,11 +15,18 @@ The matching process will be different depending on the geometry of observation Temporal matching is done by interpolating the model result data to the observation data time points; it is carried out after spatial matching when applicable. The interpolation is *linear* in time and done inside the `match()` function. - ## Matching of time series If observation and model result are of the same geometry, the matching is done *one* observation at a time. Several model results can be matched to the same observation. The result of the matching process is a `Comparer` object which contains the matched data. +In the most simple cases, one observation to one model result, the `match()` function can be used directly, without creating Observation and ModelResult objects first: + +```python +>>> cmp = ms.match('obs.dfs0', 'model.dfs0', obs_item='obs_WL', mod_item='WL') +``` + +In all other cases, the observations and model results needs to be defined first. + ```python >>> o = ms.observation('obs.dfs0', item='waterlevel') >>> mr1 = ms.model_result('model1.dfs0', item='WL1') @@ -39,6 +46,7 @@ In most cases, *several* observations needs to matched with several model result ``` + ## Matching with dfsu or grid model result If the model result is a SpatialField, i.e., either a `GridModelResult` or a `DfsuModelResult`, and the observation is of lower dimension (e.g. point), then the model result needs to be *extracted* before matching can be done. This can be done "offline" before using ModelSkill, e.g., using [MIKE](https://www.mikepoweredbydhi.com/) tools or [MIKE IO](https://github.com/DHI/mikeio), or as part of the matching process using ModelSkill. We will here focus on the latter. @@ -62,7 +70,6 @@ Matching `TrackObservation` with `SpatialField` model results is for technical r The spatial matching method (selection or interpolation) can be specified using the `spatial_method` argument of the `match()` function. The default method depends on the type of observation and model result as specified in the sections below. - ### Extracting data from a DfsuModelResult Extracting data for a specific point position from the flexible mesh dfsu files can be done in several ways (specified by the `spatial_method` argument of the `match()` function): @@ -71,7 +78,6 @@ Extracting data for a specific point position from the flexible mesh dfsu files * Selection of the "nearest" element (often the same as the contained element, but not always) * Interpolation with "inverse_distance" weighting (IDW) using the five nearest elements (default) - The default (inverse_distance) is not necessarily the best method in all cases. When the extracted position is close to the model boundary, "contained" may be a better choice. ```python @@ -94,4 +100,9 @@ Extracting data from a GridModelResult is done through xarray's `interp()` funct ## Event-based matching and handling of gaps -If the model result data contains gaps either because only events are stored or because of missing data, the `max_model_gap` argument of the `match()` function can be used to specify the maximum allowed gap (in seconds) in the model result data. This will avoid interpolating model data over long gaps in the model result data! \ No newline at end of file +If the model result data contains gaps either because only events are stored or because of missing data, the `max_model_gap` argument of the `match()` function can be used to specify the maximum allowed gap (in seconds) in the model result data. This will avoid interpolating model data over long gaps in the model result data! + + +## Multiple model results with different temporal coverage + +If the model results have different temporal coverage, the `match()` function will only match the overlapping time period to ensure that the model results are comparable. The `Comparer` object will contain the matched data for the overlapping period only. From 3f79be1037ee5fc6f42f6106384a5c40ade3432a Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:56:10 +0100 Subject: [PATCH 29/75] Create skill.md --- docs/user-guide/skill.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/user-guide/skill.md diff --git a/docs/user-guide/skill.md b/docs/user-guide/skill.md new file mode 100644 index 000000000..223ed1c37 --- /dev/null +++ b/docs/user-guide/skill.md @@ -0,0 +1,5 @@ +# Skill + +Matched data can be analysed statistically using the `skill()` function. The function returns a `Skill` object which contains the statistical results. The `Skill` object can be printed to the console or saved to a file using the `save()` function. + +```python \ No newline at end of file From fa404a321c549b2256b8a6d6b94b557e414649c2 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:50:28 +0100 Subject: [PATCH 30/75] fix link --- docs/user-guide/plotting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/plotting.md b/docs/user-guide/plotting.md index afba8b6fa..c3aed7314 100644 --- a/docs/user-guide/plotting.md +++ b/docs/user-guide/plotting.md @@ -54,7 +54,7 @@ The `plot` accessor on a Comparer or ComparerCollection object can be used to pl ## Plotting Taylor diagrams -A Taylor diagram shows how well a model result matches an observation in terms of correlation, standard deviation and root mean square error. The `taylor` plot can be accessed through the Comparer [`plot`](api/comparer.md/#modelskill.comparison._comparer_plotter.ComparerPlotter) accessor or the ComparerCollection [`plot`](../api/comparercollection.md/#modelskill.comparison._collection_plotter.ComparerCollectionPlotter) accessor: +A Taylor diagram shows how well a model result matches an observation in terms of correlation, standard deviation and root mean square error. The `taylor` plot can be accessed through the Comparer [`plot`](../api/comparer.md/#modelskill.comparison._comparer_plotter.ComparerPlotter) accessor or the ComparerCollection [`plot`](../api/comparercollection.md/#modelskill.comparison._collection_plotter.ComparerCollectionPlotter) accessor: ```python >>> cc = ms.match([o1, o2, o3], [mr_CMEMS, mr_ERA5, mr_MIKE21SW]) From 4364b3361ce06a2c375c02d29b347d95704231cf Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 30 Jan 2024 23:30:17 +0100 Subject: [PATCH 31/75] Icons --- mkdocs.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index 1d8b6fd90..15dac884d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,6 +56,11 @@ markdown_extensions: - pymdownx.inlinehilite - pymdownx.snippets - pymdownx.superfences + - attr_list + - md_in_html + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg extra_javascript: - javascripts/mathjax.js From ecb4677df567d5fa72cde13e4a3b8433bd4e6de9 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 30 Jan 2024 23:30:27 +0100 Subject: [PATCH 32/75] License --- docs/license.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs/license.md diff --git a/docs/license.md b/docs/license.md new file mode 100644 index 000000000..166acc7ef --- /dev/null +++ b/docs/license.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 DHI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 9dc9e12fd84268c7c262e1123bade46f9740f6c5 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 30 Jan 2024 23:30:41 +0100 Subject: [PATCH 33/75] Index page with grid cards --- docs/index.md | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/docs/index.md b/docs/index.md index a21db861e..481befb0f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,45 +10,39 @@ Compare results from MIKE simulations with observations. companion during the different phases of a MIKE modelling workflow. -## Installation +

-ModelSkill is available as open-source on PyPI and can be installed with pip: +- :material-clock-fast:{ .lg .middle } __Set up in 5 minutes__ -```bash -$ pip install modelskill -``` + --- -ModelSkill is compatible with Python 3.8 and later versions on Windows and Linux. + Install **ModelSkill** with [`pip`](https://pypi.org/project/modelskill/) and get up + and running in minutes + [:octicons-arrow-right-24: Getting started](getting_started.md) -## Getting started +- :fontawesome-brands-python:{ .lg .middle } __It's just Python__ -Are your observations and model results already matched? + --- -```python -import modelskill as ms -cmp = ms.from_matched("matched_data.dfs0", obs_item="obs_WL", mod_item="WL") -cmp.skill() -``` + Focus on your modelling and less on generate a validation report -Or do you need to match the observations and results first? + [:octicons-arrow-right-24: Reference](api/index.md) -```python -import modelskill as ms -o = ms.PointObservation("obs.dfs0", item="obs_WL") -mr = ms.PointModelResult("model.dfs0", item="WL") -cmp = ms.match(o, mr) -cmp.skill() -``` +- :fontawesome-solid-ruler:{ .lg .middle } __Made to measure__ -Read more in the [Getting started guide](getting-started.md) or in the [overview](overview.md) of the package. + --- + Choose between different skill metrics and customizable tables and charts -## Resources + [:octicons-arrow-right-24: Customization](api/metrics.md) -- [Documentation](https://dhi.github.io/modelskill/) (this site) -- [Getting started guide](getting-started.md) -- [Example notebooks](https://nbviewer.jupyter.org/github/DHI/modelskill/tree/main/notebooks/) -- [PyPI](https://pypi.org/project/modelskill/) -- [Source code](https://github.com/DHI/modelskill/) +- :material-scale-balance:{ .lg .middle } __Open Source, MIT__ + --- + + ModelSkill is licensed under MIT and available on [GitHub](https://github.com/DHI/modelskill) + + [:octicons-arrow-right-24: License](license.md) + +
From fe2d6b32882fecf881978e15601e12aa4c7bd169 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 30 Jan 2024 23:32:11 +0100 Subject: [PATCH 34/75] Update mkdocs-material to get cards feature --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e8646dcfb..e870e3b91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ classifiers = [ [project.optional-dependencies] dev = ["pytest", "mkdocs==1.5.3", - "mkdocs-material==9.4.14", + "mkdocs-material==9.5.6", "mkdocstrings==0.24.0", "mkdocstrings-python==1.7.5", "black==22.3.0", From cf05e97538d465cd0c0a8a34c3087ad660d53e98 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 30 Jan 2024 23:47:51 +0100 Subject: [PATCH 35/75] OS --- docs/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 481befb0f..ec673ca6b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,8 +2,10 @@ # ModelSkill: Assess the skill of your MIKE model +![OS](https://img.shields.io/badge/OS-Windows%20%7C%20Linux-blue) ![Python version](https://img.shields.io/pypi/pyversions/modelskill.svg) ![PyPI version](https://badge.fury.io/py/modelskill.svg) + Compare results from MIKE simulations with observations. [ModelSkill](https://github.com/DHI/modelskill) would like to be your @@ -19,7 +21,7 @@ companion during the different phases of a MIKE modelling workflow. Install **ModelSkill** with [`pip`](https://pypi.org/project/modelskill/) and get up and running in minutes - [:octicons-arrow-right-24: Getting started](getting_started.md) + [:octicons-arrow-right-24: Getting started](getting-started.md) - :fontawesome-brands-python:{ .lg .middle } __It's just Python__ From 1377ea0340c7f2160efa576f89556154b28b64b8 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 31 Jan 2024 01:11:33 +0100 Subject: [PATCH 36/75] Try to publish to Azure blob storage --- .github/workflows/build_docs.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index c6c9da267..93935cb8a 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -1,9 +1,9 @@ name: Build documentation (don't publish) on: - push: - pull_request: - branches: [ main ] + pull_request: + workflow_dispatch: + jobs: build: @@ -12,6 +12,9 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Set up Python 3.10 uses: actions/setup-python@v2 with: @@ -24,8 +27,8 @@ jobs: - name: Mkdocs build run: mkdocs build - - name: Upload documentation - uses: actions/upload-artifact@v2 + - name: Deploy to Azure blob storage + uses: azure/CLI@v1 with: - name: html - path: site/ \ No newline at end of file + inlineScript: | + az storage blob upload-batch --account-name staging --auth-mode key -d '$web' -s site/ \ No newline at end of file From d28f05ae0f07746c6988949a519a3a0205fcc6a4 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 31 Jan 2024 01:19:45 +0100 Subject: [PATCH 37/75] Try login --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 93935cb8a..dce6479f6 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -31,4 +31,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --account-name staging --auth-mode key -d '$web' -s site/ \ No newline at end of file + az storage blob upload-batch --account-name staging --auth-mode login -d '$web' -s site/ \ No newline at end of file From 13f641a473cb118d8d25d269f1b2c1e0028fa431 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Wed, 31 Jan 2024 08:42:45 +0100 Subject: [PATCH 38/75] add DHI logo --- docs/images/dhi-white-logo.svg | 11 +++++++++++ mkdocs.yml | 1 + 2 files changed, 12 insertions(+) create mode 100644 docs/images/dhi-white-logo.svg diff --git a/docs/images/dhi-white-logo.svg b/docs/images/dhi-white-logo.svg new file mode 100644 index 000000000..dc15bed4f --- /dev/null +++ b/docs/images/dhi-white-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mkdocs.yml b/mkdocs.yml index f12082e5d..1d8b6fd90 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,6 +2,7 @@ site_name: ModelSkill documentation site_url: https://dhi.github.io/modelskill/ theme: name: material + logo: images/dhi-white-logo.svg features: - navigation.tabs # - navigation.instant From 25cf2ff77c72ad43ecb07c78d6d1087eeb0e5d1b Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 31 Jan 2024 11:23:08 +0100 Subject: [PATCH 39/75] use SAS token --- .github/workflows/build_docs.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index dce6479f6..37dc5571b 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -12,9 +12,6 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Set up Python 3.10 uses: actions/setup-python@v2 with: @@ -31,4 +28,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --account-name staging --auth-mode login -d '$web' -s site/ \ No newline at end of file + az storage blob upload-batch --account-name staging login -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} \ No newline at end of file From be3b4d02b678b8a076fccc50caa05bd3afec2f45 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 31 Jan 2024 11:40:53 +0100 Subject: [PATCH 40/75] Don't index staging site --- .github/workflows/build_docs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 37dc5571b..f786d6826 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -24,6 +24,10 @@ jobs: - name: Mkdocs build run: mkdocs build + - name: Add robots.txt + run: | + echo -e "User-agent: *\nDisallow: /" > site/robots.txt + - name: Deploy to Azure blob storage uses: azure/CLI@v1 with: From d4a0d63e07601c17267f0f6cc5ba1697b9dcba78 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 31 Jan 2024 11:59:32 +0100 Subject: [PATCH 41/75] Naming --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index f786d6826..9171eab99 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -1,4 +1,4 @@ -name: Build documentation (don't publish) +name: Build documentation (staging) on: pull_request: From 812c8bf094bdbb47c17b74041485ce3cb626bbc3 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Wed, 7 Feb 2024 19:08:57 +0100 Subject: [PATCH 42/75] Remove __setitem__ from ComparerCollection --- modelskill/comparison/_collection.py | 37 +++++++++------------------- modelskill/comparison/_comparison.py | 13 +++++----- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/modelskill/comparison/_collection.py b/modelskill/comparison/_collection.py index 57586c917..01d492ba6 100644 --- a/modelskill/comparison/_collection.py +++ b/modelskill/comparison/_collection.py @@ -92,7 +92,15 @@ class ComparerCollection(Mapping, Scoreable): def __init__(self, comparers: Iterable[Comparer]) -> None: self._comparers: Dict[str, Comparer] = {} - self._insert_comparers(comparers) + + for cmp in comparers: + if cmp.name in self._comparers: + # comparer with this name already exists! + # maybe the user is trying to add a new model + # or a new time period + self._comparers[cmp.name] += cmp + else: + self._comparers[cmp.name] = cmp self.plot = ComparerCollection.plotter(self) """Plot using the ComparerCollectionPlotter @@ -105,15 +113,6 @@ def __init__(self, comparers: Iterable[Comparer]) -> None: >>> cc.plot.hist() """ - def _insert_comparers(self, comparer: Union[Comparer, Iterable[Comparer]]) -> None: - if isinstance(comparer, Iterable): - for c in comparer: - self[c.name] = c - elif isinstance(comparer, Comparer): - self[comparer.name] = comparer - else: - pass - @property def _name(self) -> str: return "Observations" @@ -252,12 +251,10 @@ def rename(self, mapping: Dict[str, str]) -> "ComparerCollection": return ComparerCollection(cmps) @overload - def __getitem__(self, x: slice | Iterable[Hashable]) -> ComparerCollection: - ... + def __getitem__(self, x: slice | Iterable[Hashable]) -> ComparerCollection: ... @overload - def __getitem__(self, x: int | Hashable) -> Comparer: - ... + def __getitem__(self, x: int | Hashable) -> Comparer: ... def __getitem__( self, x: int | Hashable | slice | Iterable[Hashable] @@ -279,18 +276,6 @@ def __getitem__( raise TypeError(f"Invalid type for __getitem__: {type(x)}") - def __setitem__(self, x: str, value: Comparer) -> None: - assert isinstance( - value, Comparer - ), f"comparer must be a Comparer, not {type(value)}" - if x in self._comparers: - # comparer with this name already exists! - # maybe the user is trying to add a new model - # or a new time period - self._comparers[x] = self._comparers[x] + value # type: ignore - else: - self._comparers[x] = value - def __len__(self) -> int: return len(self._comparers) diff --git a/modelskill/comparison/_comparison.py b/modelskill/comparison/_comparison.py index 8b678e6bc..55daff6fb 100644 --- a/modelskill/comparison/_comparison.py +++ b/modelskill/comparison/_comparison.py @@ -50,16 +50,14 @@ class Scoreable(Protocol): - def score(self, metric: str | Callable, **kwargs: Any) -> Dict[str, float]: - ... + def score(self, metric: str | Callable, **kwargs: Any) -> Dict[str, float]: ... def skill( self, by: str | Iterable[str] | None = None, metrics: Iterable[str] | Iterable[Callable] | str | Callable | None = None, **kwargs: Any, - ) -> SkillTable: - ... + ) -> SkillTable: ... def gridded_skill( self, @@ -69,8 +67,7 @@ def gridded_skill( metrics: Iterable[str] | Iterable[Callable] | str | Callable | None = None, n_min: int | None = None, **kwargs: Any, - ) -> SkillGrid: - ... + ) -> SkillGrid: ... def _parse_dataset(data: xr.Dataset) -> xr.Dataset: @@ -751,6 +748,10 @@ def _to_observation(self) -> PointObservation | TrackObservation: else: raise NotImplementedError(f"Unknown gtype: {self.gtype}") + def __iadd__(self, other): # type: ignore + # TODO proper inplace addition + return self.__add__(other) + def __add__( self, other: Union["Comparer", "ComparerCollection"] ) -> "ComparerCollection" | "Comparer": From 87fd9b9a821ec1d850eafe5a1ac42c88c78621f2 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 8 Feb 2024 16:05:00 +0100 Subject: [PATCH 43/75] drop_duplicates --- modelskill/comparison/_comparison.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modelskill/comparison/_comparison.py b/modelskill/comparison/_comparison.py index 55daff6fb..8215d0ea8 100644 --- a/modelskill/comparison/_comparison.py +++ b/modelskill/comparison/_comparison.py @@ -767,12 +767,9 @@ def __add__( if len(missing_models) == 0: # same obs name and same model names cmp = self.copy() - cmp.data = xr.concat([cmp.data, other.data], dim="time") - # cc.data = cc.data[ - # ~cc.data.time.to_index().duplicated(keep="last") - # ] # 'first' - _, index = np.unique(cmp.data["time"], return_index=True) - cmp.data = cmp.data.isel(time=index) + cmp.data = xr.concat( + [cmp.data, other.data], dim="time" + ).drop_duplicates("time") else: raw_mod_data = self.raw_mod_data.copy() From 4243f438827065ee874f1c38e57e38d94f48188e Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 8 Feb 2024 16:11:13 +0100 Subject: [PATCH 44/75] Inplace update (no copy) --- modelskill/comparison/_comparison.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/modelskill/comparison/_comparison.py b/modelskill/comparison/_comparison.py index 8215d0ea8..0fe713306 100644 --- a/modelskill/comparison/_comparison.py +++ b/modelskill/comparison/_comparison.py @@ -748,9 +748,23 @@ def _to_observation(self) -> PointObservation | TrackObservation: else: raise NotImplementedError(f"Unknown gtype: {self.gtype}") - def __iadd__(self, other): # type: ignore - # TODO proper inplace addition - return self.__add__(other) + def __iadd__(self, other: Comparer): # type: ignore + from ..matching import match_space_time + + missing_models = set(self.mod_names) - set(other.mod_names) + if len(missing_models) == 0: + # same obs name and same model names + self.data = xr.concat([self.data, other.data], dim="time").drop_duplicates( + "time" + ) + else: + self.raw_mod_data.update(other.raw_mod_data) + matched = match_space_time( + observation=self._to_observation(), raw_mod_data=self.raw_mod_data # type: ignore + ) + self.data = matched + + return self def __add__( self, other: Union["Comparer", "ComparerCollection"] From bd8f216a0ae7c06b175700c675d72eea9f9a622f Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:40:49 +0100 Subject: [PATCH 45/75] Minor --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index ec673ca6b..845992613 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,7 +29,7 @@ companion during the different phases of a MIKE modelling workflow. Focus on your modelling and less on generate a validation report - [:octicons-arrow-right-24: Reference](api/index.md) + [:octicons-arrow-right-24: API Reference](api/index.md) - :fontawesome-solid-ruler:{ .lg .middle } __Made to measure__ @@ -37,7 +37,7 @@ companion during the different phases of a MIKE modelling workflow. Choose between different skill metrics and customizable tables and charts - [:octicons-arrow-right-24: Customization](api/metrics.md) + [:octicons-arrow-right-24: Metrics](api/metrics.md) - :material-scale-balance:{ .lg .middle } __Open Source, MIT__ From 57cb9aca4c4be26379fa437cfe921126064a3e6c Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:52:59 +0100 Subject: [PATCH 46/75] move to subfolder --- docs/{ => user-guide}/getting-started.md | 16 ++++++++-------- docs/{ => user-guide}/overview.md | 0 docs/{ => user-guide}/vision.md | 0 mkdocs.yml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) rename docs/{ => user-guide}/getting-started.md (78%) rename docs/{ => user-guide}/overview.md (100%) rename docs/{ => user-guide}/vision.md (100%) diff --git a/docs/getting-started.md b/docs/user-guide/getting-started.md similarity index 78% rename from docs/getting-started.md rename to docs/user-guide/getting-started.md index 16e362e2f..30d2afd11 100644 --- a/docs/getting-started.md +++ b/docs/user-guide/getting-started.md @@ -22,8 +22,8 @@ The typical ModelSkill workflow consists of these four steps: The first step is to define the measurements to be used for the skill assessment. Two types of observation are available: -- [PointObservation](api/observation/point.md) -- [TrackObservation](api/observation/track.md) +- [PointObservation](../api/observation/point.md) +- [TrackObservation](../api/observation/track.md) Let's assume that we have one PointObservation and one TrackObservation (`name` is used to identify the observation, similar to the `name` of the model above). @@ -62,8 +62,8 @@ mr = ms.DfsuModelResult("SW/HKZN_local_2017_DutchCoast.dfsu", ### Match observations and ModelResults -This [match()](api/matching.md/#modelskill.match) method returns a [Comparer](api/comparer.md#modelskill.Comparer) (a single observation) or a -[ComparerCollection](api/comparercollection.md#modelskill.ComparerCollection) (multiple observations) +This [match()](../api/matching.md/#modelskill.match) method returns a [Comparer](../api/comparer.md#modelskill.Comparer) (a single observation) or a +[ComparerCollection](../api/comparercollection.md#modelskill.ComparerCollection) (multiple observations) for further analysis and plotting. ```python @@ -79,10 +79,10 @@ skill assessment. The primary comparer methods are: -- [skill()](api/comparercollection.md#modelskill.ComparerCollection.skill) - which returns a [SkillTable](api/skill.md) with the skill scores -- various [plot](api/comparercollection.md/#modelskill.comparison._collection_plotter.ComparerCollectionPlotter) methods of the comparer objects (e.g. `plot.scatter()`, `plot.timeseries()`) -- [sel()](api/comparercollection.md/#modelskill.ComparerCollection.sel) method for selecting data +- [skill()](../api/comparercollection.md#modelskill.ComparerCollection.skill) + which returns a [SkillTable](../api/skill.md) with the skill scores +- various [plot](../api/comparercollection.md/#modelskill.comparison._collection_plotter.ComparerCollectionPlotter) methods of the comparer objects (e.g. `plot.scatter()`, `plot.timeseries()`) +- [sel()](../api/comparercollection.md/#modelskill.ComparerCollection.sel) method for selecting data ### Save / load the ComparerCollection diff --git a/docs/overview.md b/docs/user-guide/overview.md similarity index 100% rename from docs/overview.md rename to docs/user-guide/overview.md diff --git a/docs/vision.md b/docs/user-guide/vision.md similarity index 100% rename from docs/vision.md rename to docs/user-guide/vision.md diff --git a/mkdocs.yml b/mkdocs.yml index 15dac884d..5baed1644 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,13 +14,13 @@ theme: nav: - User Guide: - 'user-guide/index.md' - - 'getting-started.md' - - 'user-guide/terminology.md' + - 'user-guide/getting-started.md' + - 'user-guide/overview.md' + - 'user-guide/terminology.md' - 'user-guide/data-structures.md' - 'user-guide/matching.md' - 'user-guide/plotting.md' - 'user-guide/selecting-data.md' - - 'overview.md' - API Reference: - 'api/index.md' - Observation: From 4b352a7f5936fc619b6c2eef4da352efc0a69a93 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:53:07 +0100 Subject: [PATCH 47/75] Useful links --- docs/index.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 845992613..637658376 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,14 @@ Compare results from MIKE simulations with observations. companion during the different phases of a MIKE modelling workflow. +**Useful links**: +[Terminology](user-guide/terminology.md) | +[Overview](user-guide/overview.md) | +[Plotting](user-guide/plotting.md) | +[Issues](https://github.com/DHI/modelskill/issues) | +[Discussion](https://github.com/DHI/modelskill/discussions) + +
- :material-clock-fast:{ .lg .middle } __Set up in 5 minutes__ @@ -21,7 +29,7 @@ companion during the different phases of a MIKE modelling workflow. Install **ModelSkill** with [`pip`](https://pypi.org/project/modelskill/) and get up and running in minutes - [:octicons-arrow-right-24: Getting started](getting-started.md) + [:octicons-arrow-right-24: Getting started](user-guide/getting-started.md) - :fontawesome-brands-python:{ .lg .middle } __It's just Python__ From 3664a188839ec5b6be2301c8a75989bc84fe9d59 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Sat, 10 Feb 2024 17:09:02 +0100 Subject: [PATCH 48/75] Examples and better docstrings --- modelskill/settings.py | 83 +++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/modelskill/settings.py b/modelskill/settings.py index c595744ae..1a453473c 100644 --- a/modelskill/settings.py +++ b/modelskill/settings.py @@ -2,7 +2,7 @@ The settings module holds package-wide configurables and provides a uniform API for working with them. -This module is heavily inspired by [pandas config module](https://github.com/pandas-dev/pandas/tree/main/pandas/_config) +This module is inspired by [pandas config module](https://github.com/pandas-dev/pandas/tree/main/pandas/_config). Overview ======== @@ -28,7 +28,42 @@ with them, which are stored in auxiliary dictionaries keyed on the fully-qualified key, e.g. "x.y.z.option". +Examples +======== +>>> import modelskill as ms +>>> ms.options +metrics.list : [, , , , , , ] +plot.rcparams : {} +plot.scatter.legend.bbox : {'facecolor': 'white', 'edgecolor': 'lightgray', 'linewidth': 1, 'boxstyle': 'round,pad=0.1', 'alpha': 0.95} +plot.scatter.legend.fontsize : 12 +plot.scatter.legend.kwargs : {} +plot.scatter.oneone_line.color : blue +plot.scatter.oneone_line.label : 1:1 +plot.scatter.points.alpha : 0.5 +plot.scatter.points.label : +plot.scatter.points.size : 20 +plot.scatter.quantiles.color : darkturquoise +plot.scatter.quantiles.kwargs : {} +plot.scatter.quantiles.label : Q-Q +plot.scatter.quantiles.marker : X +plot.scatter.quantiles.markeredgecolor : (0, 0, 0, 0.4) +plot.scatter.quantiles.markeredgewidth : 0.5 +plot.scatter.quantiles.markersize : 3.5 +plot.scatter.reg_line.kwargs : {'color': 'r'} +>>> ms.set_option("plot.scatter.points.size", 4) +>>> plot.scatter.points.size +4 +>>> ms.get_option("plot.scatter.points.size") +4 +>>> ms.options.plot.scatter.points.size = 10 +>>> ms.options.plot.scatter.points.size +10 +>>> ms.reset_option("plot.scatter.points.size") +>>> ms.options.plot.scatter.points.size +20 + """ + import yaml from pathlib import Path import re @@ -63,7 +98,6 @@ class RegisteredOption(NamedTuple): class OptionError(AttributeError, KeyError): - "Error in options handling, e.g. unknown option" pass @@ -80,7 +114,7 @@ def _get_single_key(pat: str) -> str: return key -def _get_option(pat: str) -> Any: +def get_option(pat: str) -> Any: """Get value of a single option matching a pattern Parameters @@ -100,13 +134,14 @@ def _get_option(pat: str) -> Any: return root[k] -def _set_option(*args, **kwargs) -> None: +def set_option(*args, **kwargs) -> None: """Set the value of one or more options Examples -------- - >>> modelskill.set_option("plot.scatter.point_size", 4) - >>> modelskill.set_option({"plot.scatter.point_size": 4}) + >>> ms.set_option("plot.scatter.points.size", 4) + >>> ms.set_option({"plot.scatter.points.size": 4}) + >>> ms.options.plot.scatter.points.size = 4 """ # must at least 1 arg deal with constraints later @@ -140,7 +175,7 @@ def _option_to_dict(pat: str = "") -> Dict: keys = _select_options(pat) d = dict() for k in keys: - d[k] = _get_option(k) + d[k] = get_option(k) return d @@ -149,7 +184,7 @@ def _describe_option_short(pat: str = "", _print_desc: bool = True) -> Optional[ if len(keys) == 0: raise OptionError("No such keys(s)") - s = "\n".join([f"{k} : {_get_option(k)}" for k in keys]) + s = "\n".join([f"{k} : {get_option(k)}" for k in keys]) if _print_desc: print(s) @@ -170,8 +205,21 @@ def _describe_option(pat: str = "", _print_desc: bool = True) -> Optional[str]: return s -def _reset_option(pat: str = "", silent: bool = False) -> None: - """Reset one or more options (matching a pattern) to the default value""" +def reset_option(pat: str = "", silent: bool = False) -> None: + """Reset one or more options (matching a pattern) to the default value + + Examples + -------- + >>> ms.options.plot.scatter.points.size + 20 + >>> ms.options.plot.scatter.points.size = 10 + >>> ms.options.plot.scatter.points.size + 10 + >>> ms.reset_option("plot.scatter.points.size") + >>> ms.options.plot.scatter.points.size + 20 + + """ keys = _select_options(pat) @@ -186,11 +234,10 @@ def _reset_option(pat: str = "", silent: bool = False) -> None: ) for k in keys: - _set_option(k, _registered_options[k].defval, silent=silent) + set_option(k, _registered_options[k].defval, silent=silent) class OptionsContainer: - """provide attribute-style access to a nested dict""" def __init__(self, d: Dict[str, Any], prefix: str = "") -> None: object.__setattr__(self, "d", d) @@ -204,7 +251,7 @@ def __setattr__(self, key: str, val: Any) -> None: # you can't set new keys # can you can't overwrite subtrees if key in self.d and not isinstance(self.d[key], dict): - _set_option(prefix, val) + set_option(prefix, val) else: raise OptionError("You can only set the value of existing options") @@ -220,7 +267,7 @@ def __getattr__(self, key: str): if isinstance(v, dict): return OptionsContainer(v, prefix) else: - return _get_option(prefix) + return get_option(prefix) def to_dict(self) -> Dict: """Return options as dictionary with full-name keys""" @@ -285,15 +332,15 @@ def _build_option_description(k: str) -> str: s += "No description available." if o: - s += f"\n [default: {o.defval}] [currently: {_get_option(k)}]" + s += f"\n [default: {o.defval}] [currently: {get_option(k)}]" return s # temporary disabled -get_option = _get_option -set_option = _set_option -reset_option = _reset_option +# get_option = _get_option +# set_option = _set_option +# reset_option = _reset_option # describe_option = _describe_option options = OptionsContainer(_global_settings) From ba9b1b1c4caf45230e41702dc476238959057405 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Sun, 11 Feb 2024 13:16:30 +0100 Subject: [PATCH 49/75] better docstring --- modelskill/settings.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/modelskill/settings.py b/modelskill/settings.py index 1a453473c..7a2ee707e 100644 --- a/modelskill/settings.py +++ b/modelskill/settings.py @@ -5,7 +5,7 @@ This module is inspired by [pandas config module](https://github.com/pandas-dev/pandas/tree/main/pandas/_config). Overview -======== +-------- This module supports the following requirements: - options are referenced using keys in dot.notation, e.g. "x.y.option - z". @@ -21,7 +21,7 @@ - a developer can register an option. Implementation -============== +-------------- - Data is stored using nested dictionaries, and should be accessed through the provided API. - "Registered options" have metadata associated @@ -29,12 +29,12 @@ fully-qualified key, e.g. "x.y.z.option". Examples -======== +-------- >>> import modelskill as ms >>> ms.options -metrics.list : [, , , , , , ] +metrics.list : [, (...)] plot.rcparams : {} -plot.scatter.legend.bbox : {'facecolor': 'white', 'edgecolor': 'lightgray', 'linewidth': 1, 'boxstyle': 'round,pad=0.1', 'alpha': 0.95} +plot.scatter.legend.bbox : {'facecolor': 'white', (...)} plot.scatter.legend.fontsize : 12 plot.scatter.legend.kwargs : {} plot.scatter.oneone_line.color : blue @@ -61,7 +61,6 @@ >>> ms.reset_option("plot.scatter.points.size") >>> ms.options.plot.scatter.points.size 20 - """ import yaml @@ -207,18 +206,18 @@ def _describe_option(pat: str = "", _print_desc: bool = True) -> Optional[str]: def reset_option(pat: str = "", silent: bool = False) -> None: """Reset one or more options (matching a pattern) to the default value - + Examples -------- >>> ms.options.plot.scatter.points.size - 20 + 20 >>> ms.options.plot.scatter.points.size = 10 >>> ms.options.plot.scatter.points.size 10 >>> ms.reset_option("plot.scatter.points.size") >>> ms.options.plot.scatter.points.size 20 - + """ keys = _select_options(pat) @@ -238,6 +237,10 @@ def reset_option(pat: str = "", silent: bool = False) -> None: class OptionsContainer: + """provide attribute-style access to a nested dict of options + + Accessed by ms.options + """ def __init__(self, d: Dict[str, Any], prefix: str = "") -> None: object.__setattr__(self, "d", d) From 1b8463ed49a68ed603386c02ce30baed75297835 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 08:19:03 +0100 Subject: [PATCH 50/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 9171eab99..3b6463bd6 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -32,4 +32,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --account-name staging login -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} \ No newline at end of file + az storage blob upload-batch --account-name dmistaging login -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From f74bcb97a11356fcbd126cd1dbb1cc581b2818f9 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 08:27:09 +0100 Subject: [PATCH 51/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 3b6463bd6..1de48319e 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -32,4 +32,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --account-name dmistaging login -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} + az storage blob upload-batch --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From a58e233f32f9a19c66429735e9596668954c1c48 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 08:27:37 +0100 Subject: [PATCH 52/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 1de48319e..1a928ebf6 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -1,6 +1,9 @@ name: Build documentation (staging) on: + push: + branches: + - main pull_request: workflow_dispatch: From bc0acbe71df191428ab90c09609db020419542e1 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 08:46:07 +0100 Subject: [PATCH 53/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 1a928ebf6..abe845a23 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -35,4 +35,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} + az storage blob upload-batch --overwrite true --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From 9f06b85a0e29b92d8e850ff4403b55b94a7a260d Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 08:57:42 +0100 Subject: [PATCH 54/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index abe845a23..87347817f 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -35,4 +35,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --overwrite true --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} + az storage blob upload-batch --overwrite --account-name dmistaging -d "$web" -s site/ --sas-token "${{secrets.BLOB_SAS_TOKEN}}" From 207c9f1fe8dc7e43f67f6d6ff87ff5c9b9aa4aab Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 09:18:34 +0100 Subject: [PATCH 55/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 87347817f..64c6b4c87 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -35,4 +35,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --overwrite --account-name dmistaging -d "$web" -s site/ --sas-token "${{secrets.BLOB_SAS_TOKEN}}" + az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token "${{secrets.BLOB_SAS_TOKEN}}" From 7b615e6db5793057c0ecc099b47700b347ab6cc5 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 09:24:17 +0100 Subject: [PATCH 56/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 64c6b4c87..bb3917015 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -35,4 +35,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token "${{secrets.BLOB_SAS_TOKEN}}" + az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token '${{secrets.BLOB_SAS_TOKEN}}' From fb512a2964ba6f0be9f5d85de17f52b93dd92f1e Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 09:39:02 +0100 Subject: [PATCH 57/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index bb3917015..62626a05c 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -35,4 +35,4 @@ jobs: uses: azure/CLI@v1 with: inlineScript: | - az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token '${{secrets.BLOB_SAS_TOKEN}}' + az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From 1d4f89046c09b81607cc1956d0e1c1002470817d Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 09:49:13 +0100 Subject: [PATCH 58/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 62626a05c..3b7ba3965 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -32,7 +32,5 @@ jobs: echo -e "User-agent: *\nDisallow: /" > site/robots.txt - name: Deploy to Azure blob storage - uses: azure/CLI@v1 - with: - inlineScript: | + run: az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From 5118a1a0ec8493dc044b9ef40f4e76cdafe44c38 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 10:00:06 +0100 Subject: [PATCH 59/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 3b7ba3965..d3800936c 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -33,4 +33,4 @@ jobs: - name: Deploy to Azure blob storage run: - az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} + az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s /home/runner/work/modelskill/modelskill/site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} --debug From a49157da52717eaec62d34b9aad1ce32a658f5ec Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 10:02:57 +0100 Subject: [PATCH 60/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index d3800936c..92ee8a166 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -33,4 +33,4 @@ jobs: - name: Deploy to Azure blob storage run: - az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s /home/runner/work/modelskill/modelskill/site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} --debug + az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s /home/runner/work/modelskill/modelskill/site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From d5e29b7e4f9e1ba261c39a85cfb17b5197b6b7bf Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 10:06:18 +0100 Subject: [PATCH 61/75] Update build_docs.yml --- .github/workflows/build_docs.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 92ee8a166..2c8ad2207 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -1,4 +1,4 @@ -name: Build documentation (staging) +name: Build documentation on: push: @@ -26,11 +26,3 @@ jobs: - name: Mkdocs build run: mkdocs build - - - name: Add robots.txt - run: | - echo -e "User-agent: *\nDisallow: /" > site/robots.txt - - - name: Deploy to Azure blob storage - run: - az storage blob upload-batch --overwrite --account-name dmistaging -d '$web' -s /home/runner/work/modelskill/modelskill/site/ --sas-token ${{secrets.BLOB_SAS_TOKEN}} From 4f79f3bd3b214a361b70513bbfab3751e5860151 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 14:44:01 +0100 Subject: [PATCH 62/75] Red --- tests/test_comparer.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_comparer.py b/tests/test_comparer.py index 9b01f9a9b..dc7d0d921 100644 --- a/tests/test_comparer.py +++ b/tests/test_comparer.py @@ -5,6 +5,7 @@ import matplotlib.pyplot as plt from modelskill.comparison import Comparer from modelskill import __version__ +import modelskill as ms @pytest.fixture @@ -811,3 +812,27 @@ def test_plots_directional(pt_df): ax = cmp.plot.timeseries() assert ax is not None assert ax.get_ylim() == (0.0, 360.0) + + +def test_from_matched_track_data(): + + df = pd.DataFrame( + { + "lat": [55.0, 55.1], + "lon": [-0.1, 0.01], + "c2": [1.2, 1.3], + "mikeswcal5hm0": [1.22, 1.3], + }, + index=pd.DatetimeIndex( + [ + pd.Timestamp("2000-01-01T00:00:00"), + pd.Timestamp("2000-01-01T00:00:10"), + ] + ), + ) + + cmp = ms.from_matched( + data=df, obs_item="c2", mod_items="mikeswcal5hm0", x_item="lon", y_item="lat" + ) + gs = cmp.gridded_skill(bins=2) + gs.data.sel(x=-0.01, y=55.1, method="nearest").n.values == 1 From 7f672424d1a5e34f28a10d3ed77fd9c450941750 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 14:46:46 +0100 Subject: [PATCH 63/75] Green --- modelskill/comparison/_comparison.py | 50 ++++++++++++++++++++++++---- modelskill/matching.py | 14 +++++--- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/modelskill/comparison/_comparison.py b/modelskill/comparison/_comparison.py index 1f2916222..0a0329622 100644 --- a/modelskill/comparison/_comparison.py +++ b/modelskill/comparison/_comparison.py @@ -236,6 +236,8 @@ class ItemSelection: obs: str model: Sequence[str] aux: Sequence[str] + x: Optional[str] = None + y: Optional[str] = None def __post_init__(self) -> None: # check that obs, model and aux are unique, and that they are not overlapping @@ -245,7 +247,12 @@ def __post_init__(self) -> None: @property def all(self) -> Sequence[str]: - return [self.obs] + list(self.model) + list(self.aux) + res = [self.obs] + list(self.model) + list(self.aux) + if self.x is not None: + res.append(self.x) + if self.y is not None: + res.append(self.y) + return res @staticmethod def parse( @@ -253,6 +260,8 @@ def parse( obs_item: str | int | None = None, mod_items: Optional[Iterable[str | int]] = None, aux_items: Optional[Iterable[str | int]] = None, + x_item: str | int | None = None, + y_item: str | int | None = None, ) -> ItemSelection: """Parse items and return observation, model and auxiliary items Default behaviour: @@ -280,6 +289,16 @@ def parse( else: aux_names = [] + if x_item is not None: + x_name = _get_name(x_item, items) + else: + x_name = None + + if y_item is not None: + y_name = _get_name(y_item, items) + else: + y_name = None + items.remove(obs_name) if mod_items is None: @@ -292,7 +311,9 @@ def parse( ), "observation item must not be an auxiliary item" assert isinstance(obs_name, str), "observation item must be a string" - return ItemSelection(obs=obs_name, model=mod_names, aux=aux_names) + return ItemSelection( + obs=obs_name, model=mod_names, aux=aux_names, x=x_name, y=y_name + ) def _area_is_bbox(area: Any) -> bool: @@ -349,12 +370,14 @@ def _matched_data_to_xarray( x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None, + x_item: str | int | None = None, + y_item: str | int | None = None, quantity: Optional[Quantity] = None, ) -> xr.Dataset: """Convert matched data to accepted xarray.Dataset format""" assert isinstance(df, pd.DataFrame) cols = list(df.columns) - items = ItemSelection.parse(cols, obs_item, mod_items, aux_items) + items = ItemSelection.parse(cols, obs_item, mod_items, aux_items, x_item, y_item) # check that items.obs and items.model are numeric if not np.issubdtype(df[items.obs].dtype, np.number): @@ -380,14 +403,25 @@ def _matched_data_to_xarray( for a in items.aux: ds[a].attrs["kind"] = "auxiliary" - if x is not None: + if x_item is not None: + ds = ds.rename({x_item: "x"}).set_coords("x") + elif x is not None: ds.coords["x"] = x - if y is not None: + else: + ds.coords["x"] = np.nan + + if y_item is not None: + ds = ds.rename({y_item: "y"}).set_coords("y") + elif y is not None: ds.coords["y"] = y + else: + ds.coords["y"] = np.nan + + # No z-item so far if z is not None: ds.coords["z"] = z - if x is None or np.isscalar(x): + if np.isscalar(ds.coords["x"]): ds.attrs["gtype"] = str(GeometryType.POINT) else: ds.attrs["gtype"] = str(GeometryType.TRACK) @@ -493,6 +527,8 @@ def from_matched_data( x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None, + x_item: str | int | None = None, + y_item: str | int | None = None, quantity: Optional[Quantity] = None, ) -> "Comparer": """Initialize from compared data""" @@ -507,6 +543,8 @@ def from_matched_data( x=x, y=y, z=z, + x_item=x_item, + y_item=y_item, quantity=quantity, ) data.attrs["weight"] = weight diff --git a/modelskill/matching.py b/modelskill/matching.py index 494d6282b..463e8f5bb 100644 --- a/modelskill/matching.py +++ b/modelskill/matching.py @@ -82,6 +82,8 @@ def from_matched( x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None, + x_item: str | int | None = None, + y_item: str | int | None = None, ) -> Comparer: """Create a Comparer from observation and model results that are already matched (aligned) Parameters @@ -105,6 +107,10 @@ def from_matched( y-coordinate of observation, by default None z : float, optional z-coordinate of observation, by default None + x_item: [str, int], optional, + Name of x item, only relevant for track data + y_item: [str, int], optional + Name of y item, only relevant for track data Examples -------- @@ -148,6 +154,8 @@ def from_matched( x=x, y=y, z=z, + x_item=x_item, + y_item=y_item, quantity=quantity, ) @@ -164,8 +172,7 @@ def match( gtype: Optional[GeometryTypes] = None, max_model_gap: Optional[float] = None, spatial_method: Optional[str] = None, -) -> Comparer: - ... +) -> Comparer: ... @overload @@ -178,8 +185,7 @@ def match( gtype: Optional[GeometryTypes] = None, max_model_gap: Optional[float] = None, spatial_method: Optional[str] = None, -) -> ComparerCollection: - ... +) -> ComparerCollection: ... def match( From a1371e9f1f8990f5af70d604ac4b3729e1f3256f Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 15:30:38 +0100 Subject: [PATCH 64/75] Refactor --- modelskill/comparison/_comparison.py | 40 +++++++++++----------------- tests/test_comparer.py | 11 ++++++++ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/modelskill/comparison/_comparison.py b/modelskill/comparison/_comparison.py index 0a0329622..f6559877e 100644 --- a/modelskill/comparison/_comparison.py +++ b/modelskill/comparison/_comparison.py @@ -256,7 +256,7 @@ def all(self) -> Sequence[str]: @staticmethod def parse( - items: List[str], + items: Sequence[str], obs_item: str | int | None = None, mod_items: Optional[Iterable[str | int]] = None, aux_items: Optional[Iterable[str | int]] = None, @@ -272,37 +272,25 @@ def parse( Both integer and str are accepted as items. If str, it must be a key in data. """ assert len(items) > 1, "data must contain at least two items" - if obs_item is None: - obs_name: str = items[0] - else: - obs_name = _get_name(obs_item, items) + obs_name = _get_name(obs_item, items) if obs_item else items[0] # Check existance of items and convert to names - if mod_items is not None: - if isinstance(mod_items, (str, int)): - mod_items = [mod_items] - mod_names = [_get_name(m, items) for m in mod_items] + if aux_items is not None: if isinstance(aux_items, (str, int)): aux_items = [aux_items] aux_names = [_get_name(a, items) for a in aux_items] else: aux_names = [] - - if x_item is not None: - x_name = _get_name(x_item, items) - else: - x_name = None - - if y_item is not None: - y_name = _get_name(y_item, items) + if mod_items is not None: + if isinstance(mod_items, (str, int)): + mod_items = [mod_items] + mod_names = [_get_name(m, items) for m in mod_items] else: - y_name = None - - items.remove(obs_name) + mod_names = list(set(items) - set(aux_names) - set([obs_name])) - if mod_items is None: - mod_names = list(set(items) - set(aux_names)) + x_name = _get_name(x_item, items) if x_item is not None else None + y_name = _get_name(y_item, items) if y_item is not None else None assert len(mod_names) > 0, "no model items were found! Must be at least one" assert obs_name not in mod_names, "observation item must not be a model item" @@ -404,20 +392,20 @@ def _matched_data_to_xarray( ds[a].attrs["kind"] = "auxiliary" if x_item is not None: - ds = ds.rename({x_item: "x"}).set_coords("x") + ds = ds.rename({items.x: "x"}).set_coords("x") elif x is not None: ds.coords["x"] = x else: ds.coords["x"] = np.nan if y_item is not None: - ds = ds.rename({y_item: "y"}).set_coords("y") + ds = ds.rename({items.y: "y"}).set_coords("y") elif y is not None: ds.coords["y"] = y else: ds.coords["y"] = np.nan - # No z-item so far + # No z-item so far (relevant for ProfileObservation) if z is not None: ds.coords["z"] = z @@ -425,6 +413,8 @@ def _matched_data_to_xarray( ds.attrs["gtype"] = str(GeometryType.POINT) else: ds.attrs["gtype"] = str(GeometryType.TRACK) + # TODO + # ds.attrs["gtype"] = str(GeometryType.PROFILE) if quantity is None: q = Quantity.undefined() diff --git a/tests/test_comparer.py b/tests/test_comparer.py index dc7d0d921..4319831ce 100644 --- a/tests/test_comparer.py +++ b/tests/test_comparer.py @@ -836,3 +836,14 @@ def test_from_matched_track_data(): ) gs = cmp.gridded_skill(bins=2) gs.data.sel(x=-0.01, y=55.1, method="nearest").n.values == 1 + + # positional args + cmp2 = ms.from_matched( + data=df, + x_item=0, + y_item=1, + obs_item=2, + mod_items=3, + ) + + assert len(cmp2.data.coords["x"]) == 2 From 0f1c054764d66094b96a5117c97b64665dff2f0a Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 15:51:58 +0100 Subject: [PATCH 65/75] Dfs0 test example --- tests/test_comparer.py | 24 ++++++++++++++++++++++++ tests/testdata/matched_track_data.dfs0 | Bin 0 -> 29430 bytes 2 files changed, 24 insertions(+) create mode 100644 tests/testdata/matched_track_data.dfs0 diff --git a/tests/test_comparer.py b/tests/test_comparer.py index 4319831ce..1b1e9018d 100644 --- a/tests/test_comparer.py +++ b/tests/test_comparer.py @@ -847,3 +847,27 @@ def test_from_matched_track_data(): ) assert len(cmp2.data.coords["x"]) == 2 + + +def test_from_matched_dfs0(): + fn = "tests/testdata/matched_track_data.dfs0" + # time: 2017-10-27 10:45:19 - 2017-10-29 13:10:44 (532 non-equidistant records) + # geometry: GeometryUndefined() + # items: + # 0: x (undefined) + # 1: y (undefined) + # 2: HD (undefined) + # 3: Observation (undefined) + + cmp = ms.from_matched( + data=fn, + x_item=0, + y_item=1, + obs_item=3, + mod_items=2, + quantity=ms.Quantity("Water level", "m"), + ) + gs = cmp.gridded_skill() + assert float( + gs.data.sel(x=-0.01, y=55.1, method="nearest").rmse.values + ) == pytest.approx(0.0476569069177831) diff --git a/tests/testdata/matched_track_data.dfs0 b/tests/testdata/matched_track_data.dfs0 new file mode 100644 index 0000000000000000000000000000000000000000..e1f5fcff65bc99f34e7512b8bfae1f73cb9504d9 GIT binary patch literal 29430 zcmb{5d036x`#m_weq(*rW!hxzs&HN=H=s8`MR#D=AXYDsQRM`z4%j5QQnwdRQ_K1 z!jN95SG}ljs`jUf#o^&AD#{y}s{eUWZ%yu!V>;zw73B>@EF(e{6%~OM<&8|Ws@}Ki zg?vy&`N%;U)hl5~ORKK!tt{Jj>?+gHt9)%`Y1_GrtyMQ!RlDYE$z*m^nQQdrmEJTwy0PB@z0Oq?JK#W z@?Vb$$G)BWQ}E|U?av?obW!^6KME?!ttrT#>J{bA3##6@sM1xGcbcRAr!$p5{LTH> zevJ={R=kahu3h6$x}xo;88@H0rYkDzDGQsM{Q0-?w;=jA3jbCX{bzp`{FnZud+&Gt z^A^f|)%w$0RlfL-=Kn{*|E@o(Z=PB4@}a_@-Pc1NGrIO1;WNlr;n}rkWjxvBgsMjT zFZ%OmOZRj7FCCKoE>TldR+2m1efEF;0r58vYM$&P3s5W$&RyEleYPUYF{Q|@eAb`f zN{vs24we7@FFI7CveMv*v%O}`^$hUw^Zjo<+g(RpQCZug+%fL{^}`was$XP&=j}Nvb|7RJxt&ns?_&x1ZA=A{<*Oi>f{@GFXhJ?`fEIp8Bh>9) zp$gIkY81Aa(1~E626wLz((3$41?dC%hD8!8?*nuuFq_b#j?F(0TdK} zpHTnpG6%jP8UiJ5SWRfntueGAP7HfUDDYP`6=VXmIc5c+n_Ga|rzR^Q41Ah0rY6H3spIu4&*2|qLSDQOBG}Z zbWG_)Rf<*st*_IVO3r9?R6$li4$thUim@}0+qEWCvS_)33hD^7rF9poGEg7L)!Up( zzLYtspiV&X{_UyClAO`BA@=B7Qpp=lRn!^C?OZFWaxey{II$a*O!_cDB~lll+&bt% z-UOiCZ@Uw!nLkhkSp&VBTA!+Dv;y*W>rEwbA4jR6u0RP_YEhN;Z$?p{`k3I8^X=@R zf^2|(n&}W4aRg{<<55(yuV{)2>IU?xaRnVcivxgGULHs2+twK>$QG!u&^ch)*rRr0y1`Z;!5ekq|E`apgf0|{lP>JjR?T8*Pu5(-(= zh$5Zp0c4}6NoZc$(=-;TNJ3X$8WF0P2Xy)H&$O!M#f^W>(Q66a9Rk$%7|@@EPoOs~4-=Xad6=Vj68i9~KB39m zfR=BIB9yixhNJfqdhZ2vFbAmffu)2h2PYhTkkE;nh7_r!_F(GMqU1S*rt5X%=%a*s zcLTB+0Q7l;6`_s$)j2AbP~5J16lrM)(4)ui&Q^U+cb?>*WgqS*37xABl#vE>=Vfz3 zG4o6~Dv{9sfVvb(uN0{6xSyx1A}uaS?9L*6me82TbqEdaE`6-wwbum?k5 zBy_ho(54wc#*IRHRH2pbcR2bgp?ZHCP^A0&fQl_k2t5odR#bz~j|D&lb59cbXmg39G6`7^0_uJOD6@Jxp?wRka8xcKs}t2J($Wt=SDkJU zI&G>l@U4(gu@O+Z*)ZA=xtD+}DxUF3vNW8Q0|Kj2B#lWxa}VC7NUvL~jLX#|bmoN~ zq2AkpEbK5YA922jM^cy2mHt30bAgl>b0|_@jUOCoNNDrlx)dqXU^w+@b@Mzzdd5#U z(v(o^xTDN7@pKc&JTiO*&A+e=;dj zllm%1M?yXhK-Yf){Zw8i(k0wQ0yB}zk@+hIR&+l?nT|z%BGze91f+4{rqc}oGHmMvMH6%1L zQk{_VXrQ7=TL?YBlE)*}l+c{dYJ|cz00qyCBs8zR$~?E0gocj*x_TYx$o!Rr4lFy$ zBh{8r$w?VS($T?q&oX-^p+dlth{9SMbmNk7;=7hbe@HKX1iR6AArxe@`g;0FauG6QPuK+8i~N zP%p!GgsK$+rDU9>vC-Cu+8oIx^y|hOLcNIHA@rG&pJ|q1K_V2?e?VJs94F zP;vcCJ~nDDp^J(lLMa=i9Lvl5-K)k%t8YKysD*@X{dh^JBn#+6Crd)HyLNNbQbMkY zg@oGaB14suek-*ql9lcuJ2nbyB_W5uUJ&x?1(eiscPcbAH=w#D(gjys4_4imvD6Hv4h7KsC`Kx$S7+pp~p!XEK<5a-7CHlI`|ofMqxRwgz`y$Gn6mTv9I3=J-!a)vD%g* zrJd)^ll7E7r&e!E32E;IN;9`2wD8JR7D+Bp)YD&tS_cAse9)TElI-IQDFmv1r;JdK z(Lkp2%?Ry}=Y8@JXz`^ALIbRT!cWvAWTbhLMG6vV{zF;Ms^fG}HK5@6*Lzfz_{feh zq!j4b9W_GzpW_VsPr-IV)AgbmN*8GQHFZMW&j5wnZ6l-|yqO`{UTKpX1r}1D;-!PI z?xyk7C$riI8IlV$bHyt{tJQE27CKHMbR{*JA%#Gv!d?@a`~dsjw|0LKa$Cufhd`g! zza`Y=IMDhz*kPx&RoUbMHQw-^P}v%wN6$x5q)eUdta(a->^6NQbb2z-?2q<@+Igig zlrGS~&7TPQ^#JNq)|Sxy9{h947iie#&xDNX1HD?%j?fLGNES)HPx_n&Z^A*C`T@Jq zh#PGPHQC3{dkTTTNo9s;!t$3ggX2hd|DjKa1wThCCCK(aMB z2q(=4+Wq%e+V}cBTgZ@7pqv#r2%oqD6hN_rv1S%Rnhf1uo zwlO4gkRnZQflPA!TR?s_=M$6Xm8`zKmqm&Y$fWvEs?w|+$RcbDl|-NBNGVWWO=qeivvZ~m zk**s*V3869I#mPr)E+GW+G7<>DEoK{L-~%po2G*gx(Ya-M-eI4)>r_=?qy4G_5$E(99ON04&`ROQ3x*YFKM(~ zs60ieRB6gkkU+mSBoSI4R6DX4EfXY&!#lJ9)sP+K+ z-U_9X(De^|+Mp0YhJp@wM z0J<$*sE?iqCDhJ~kB$5VO4r6z$Ur(rG_1Xf(ByHk?86Nb$fP=kZi7$Y#B#X{l7h{e zZel1xAVYo3)YdEjN*lD8B3Zid1e#Ky{e~D>Ua|)|X1j<`(-qTLq(p)8j4_cc(*W|; zLi#bnY92%B0_|>&fp6!l$Q!jtz?{(WFi&e`3#4t1dG6HpK;uo_sd;JVN3lrx0%>%_ zxP1FCphtHG6N>lm!BDY4(YBa|-)snU+suKG=kPiV$xcbfQ-&j^4YDW5@3p&yIbrI9 zY7FTMv}z!-1Qxr2f~_#bR(qn(kX)erQJB??odTpc9_U;x6NW4Wx-szu9qy~z19hz1 zp8DiJL5CrQK(4;e2^}p#9yTq@lF&cH)fjRWXv)F@LibMreHz}MkbKeyb^-7ZNPpEc zLb4@5ms2oPYiU-_kiS3!H{}y*)e9)ob16l7I+$Mo6w}LaTGq9%<4|>3wzj}&dAl1% zmcg56v#YzSK*gP!6H3wnvMZcPCH4z~81fJ(xmic5V*U*0y~*dX5+liQ8bkg9+3WNo zv?UejevU7ds0|EYC`h1)mGzG{j{7uHTBG`iblhSCMC|jU|#WI^^vw5G21sbfQB(y68 zNIeOo+R!g!SR~mDY2S;^*+(d498kX*SSdDL&y68{fnMx5LMYQ3sMa!9D*3&iZwR?S zmfokRN>*(kw=xWc$CVFbkt_vTVRnwt)gqkBYgzQAk~Y^|8Bz%J;N@kia^}2r)hNU+ zynBN!L#_hZ?7Tr}Zw!#0i-JmmHG4DUA<&Ld_o&LM*+B1KSyRdRe|j?HFHpm3PpHZS z7oenaD=Gc~)#K)aHW`flF}NN(Sr&|=SC3`GdkW72!7^0^FGjo5$MQi-`OUy7#` z=#Ac2s*-pQsQWilDw+DE8HH*Z@Ykfj%Q`$0=FVM|2+(LKm2DHEu$W+;ep<;o2L$TE1kpa-Q zjrtVnYl_O+QD5nJYUFA_7l27`a8dg;rUoIM;?^vZzCaHRv7o2m0?-TxJwm5V`G$}S zbnHHsL%D5}&{{1*TAlglWGPVeHWO;zmDxc5T+}2Kx`Hp)RR|O_Moy@m3((EYGD6J~ z>##n#3Ut({C85xkK>p2s;7XWp%#epbg*m2#9{tAUv%!O6Le+BXGUP9iMMPUdra3@E z7GS~Q#jm;y1ql?{uLGf}hk-mMy{AZRuJP5x5ds-jbR-nN0_dO~Q2nVjStO-E$B$bR zx;GAJq94{RSKjhtC{Z9kZ(BkYU4V@BfDEi_FqAHkO9OjC@>)RuxB#iQZNO0W|3jC1 z60&)TJNyeeqEErC`G=b?(2Uu=3H3_@DyhugR*hj+x@)jV#R4TZ=}*XYixg>42_Y{d z9!cgW9ZyD?E`$dA0vY&yCv-{9KPP>G;{99+_2~noHs%+hdn5VQlMCc#IGj)yX(dMY zta3t2viZJeDNyH>QG`ssVa>-h4GlUpj5O=B4WSUoe#{s`KeK=~SHoJ|i90!R70CD3 zctY8GfFh>Uq)2WJ_=oEuP-gT*LUBugUOhJ;lrV~)!u$ntwe}`7c?3{WKm$S>ZTX2M zNFbeCK7^XJ2hvP1Ce*fJE4Cpb1bXK)gHWy}&=@5~waG_1F{BhorZ$sM$Rn%*YIhc^ zz9W=23?&NGXG;Jf^AkY2S8*jgpWwt$x$%Wk@d2qBAQA-HHP8bzVlu zB7#p)ECu=z7)q$CKTzvYNQO5`U&A6P1lrUqjL??8Kqm$u!EY74fgx9c25PP)^sWg| zROcFtHNDoUnvJ~iRt#Cry;(?}yU_)ee=WFH_0u^Yi zA~azM(B^kLDAM8*C2O9mKy`jDA!IZX=$JOpArpR!!b6~oUuF=xY60Y{1~gc)n?>>$ zDEIp~LVh|xb$4v1=5=kvn-?UIy~ZFyHS;kQx@-zmT6-sp6d_PieS1R6WT2P7wo#;o zS2$7%^rfQ(A@fL}?{c7)W_*(;3gkGd384c%K%QCA6e*z3Cf2-kf$l7?MW|UXpc7qz zoYruZEs)F1vb3tbe0?JzmufhkHs6hAk@5u!c>9=8NeQMxL;7x|<_)M3!%(q6Pv)c% z8h8!pua!95Rd2+}&PvDAHT@lg;&uatv;!J+E0RUh7pP=jAfcCwfEwg%qUK$aM=&H8 zDEotgP|M*!eV1(@6k!$4kflJgR;m+nYX_8n1IdQ`_B@h8puLMj&sJ^n6`DZKm36C1 zuB3A0D$s#@7ia;0!Xr$D8fk|UI`AosHP1t!q>B^ihQ#?3K;s{;AykqW%8$(olhP`$Uh^uB!pfDF4&r;-iVCNNYiP`6eM zsY)$rPI$W0UsQ53#DyVQnshwP9EC(eRtrR0JPf(8qvtr%7wA#2HN9`hFU)Fs1&ySV ztnT(Kl3bug@x7^v)g7Q6QO;CS*K-&{mIB$GL+0z=0iY%J7`ok-@kk1RdflEx?>lQ5 zQ0?6gR5I?7HH+jb(A3AXsEU?5(3BeJW#v5phCBocC=MbNZUyvP*_KLX9%{>wzd$a& zI1mi5_6U9fr~cdcOZKy>CN%pcETq zK62}*Gn6e*s(un7Z$lu(6-*=pT7GAD8;S+Wntg`Qp?8?oJl%>Z>)7xDhGgfYL!97fLQS>-*#^C!6F}1yDvQYkvRQeX(12M$0}ebR)GYBf zi)1N~<%9c#eES34cfU{Q$;^KkQV8U3{)|wV9B9X?+k}QDr!nLz(5<;egtmXjtR}Aj zPlhb{o3B9g5NP>1EZ|PK0c70#GDULwd6-4=7bsZsJ4HIM2WW}^MMAqyY-K1&po_in z#KE4$Kw+h6gtUW`7>W?+@OdOUw+;hJw!1=TbOJ|8fnvsM)3hPj97z5bo~yY&j(@m` z0v#3AtfRe3{evJG0ibc{F=<1xNgfyxF9lZ3DB3&Q%mLa)7Mw%@M9m>b_&i9i#?O2z} z`T7V;fwo1oCN$_2&=@nMi7T3wu}BJmT#d~My;=uUc)Sipay+cZPGPPB*~GUev|uvO z?m|OCIj?xe*F&I@ZLJ8YcL&n`)RfS}FrMi27wBMOXF?$cK#iNXBIM*#n>8;;pst;5 z2$jFWlZ)N=v?p{Uv^hf&0+lCqC*+?7bY0Do(Bq_*3@HWr-Nk{>gH1r;U%L`olFgG% zi2`*w(Th-zX+SgDIuV+)ktdtd1=?@fhfq{cpb`E92;~Ly8$8(pjXj9$=-UQB-wzHZ zv^9dKfbsOzbjNMP|!AHM;B%QUH8J!tw+1zZ0pI+OUKhE zePl;Z#sGbsikrawEqL?v1=$#&#tkm#%zVt`NvQ$CDzB`HTmZ*ZYMLYL>`nHLe25dwCI>c@=2! zd(58>+OJ}L@({@4@DxHpJAe*LU+dD}f=}=K1zJ^qI-yl_fV$Pf+&#DRRu(BpAhV@@ zK+ZrNWKyzeIG-Fx%u?@JQ8jJaWsZd+>#AXpn7_3)y-mZ-`ig%)P7)>1%nmQ9N{46gigN)TBMmvsPnG7ERt-tw8Pf5c|fRtTO=`#ufhS$IMVdPBB12{ZZEKoC$Y25zXdbbNgjTvAXUI~Z!wv5e+8zt^Pu3wq+k;Lr zWFwHi!5u=arPYr!YV0S}*ya>N3V||oZxcG)0NK&MN@58;ZpkCL3e@b|O+qI(03~n1 z8TO_(U&%gNpv!M>5VFYz+Ej>p0IT-#lck41DfwB1l4~MguJQLeYTg8$Ev!#d1p0aR zIw5Okptl_`$5ubXlTAOqYT*o<8(KlgI2@<2i?M1H>39v5G3+-9$&bnC*@mYlfz}t4 z(Qs7tkuzO^1}gCsMa&bRq?~VrYRB@&v-Ab}vR<7cxoG3W56zL|GAjd?zv2l5*x;8%Cx!#%dQLbBo zZ|Lz*f1g%$b{}E+Chgys&j^7A*k2)(a}FrZHs#=`TFVP`W_toze*fH^!Ik?Ax)I9v&E` zwVR<#f#w>WBXngH(CZLW%4-+A-pn4g%@(NS{aHe_HUI^-x@lY0;Jw?N*aH!H0;ylX z>3;Zipo;8U^u$5>yEwLXG+&_In@>}uXl)GLQtphWWO$?WhYS@7bZ<&3p{ELqbb-txky7<|0OUFZvl>$+zde>I(87^hs4+Y0A!oVPd^weP8S&<23pCJp zGgWykeVy5(b;vfWK5~{P(2l2gM9M_^;xvP8i|B2{Z&Vrjl(~2=l`QYDmPINSXhR$9G&x;yCA?zdN60vCJwrbPdh!-K zP2E{Q#WSW6DtF{_LYbztmnR&?sKNCRP^9}5LUw~zvq-uEeehjNRo1-(>iWW)O2$1} z$&kK4i5=EZm4D>8KFyrzMJ2^6_&m3vK<__d_tYK(w7mBuLX{6hut;)&?)k2wDuFkF zPUnuNlIePU?rtVfP4A}_e zupj$$$E83CA)^R+%nf8nA@D0&Vpa;#7eMl$)3N&z~NE4!_ zvq-K29XlIHRSKkAvw`1`0#f~Q#nA%AbY4QJ@n4v0G`-W8O6qz}Vv#%qns#6zRT;Gt zXw=I-RPxK#gP|z`wQhr4RffsY;J9L~?!Eol3q}K3DMXi(05azhBOvD)Tac zinF>=$)bAW8Hy0dY$OiuBjrHR-Zq53rnoZ{B~Zr<9Na}Vm}|I|S`v~)@;)gAGPc6O zEuRgvD!c6lqx# zZEB2m4p2dpFN7+;`imi5fikMqC3Lw0=!lo>TvdZ(bbm3VFVL(qJO|9vj0Z3slnLE+OkhKu^?W(UuM}z5Kp=}*YP8>1PL3HW z5@_)C-$3(#dOmGRNcAzgVu6<2MBXrFCs2!b-3jd(q_F?@DeQ+pD{YaXTyqWR!IzUdo^E@ z3aEMO=X_$36awWsk*oIMw4ANMhmp?vIT93kaVCQ&GiXwt>6poJp}5}4-Z7tc>|RD4JYbC z&t@#r6oD>X>q3#X*2R6oTIR+SY0p`X`~|8%q#Gf_9zY{6HzK4{Y|SFg7sxWtj?fx! zDNUt^&m4*YgdumFN)X(sh?4bf>ymcfrAqA+#d~-tcV>_})5d!s@ z-0?+Vr9elv3?ekK3()6p3PSti z`G_S!pg6Okgc8OB4M^@uD5)!7$(|^X`+a(B@?xgl1|WOYqs!l~DC0Z-%l3N@zTp z(E4^j)m~wBepu7l4CM(Fnfe!@_z^%Y54cgJnll$OlrPX|w`qiqEd^S=a{?hfV?HM= z66i~*FQJqBfPPv{B=oR!DT`DrkYDU9LMO6;e1~FG8+3{<&io-zreZFkgi;`H>Hm6Q zZO2pJGE?dLRPk~Fp-s(^#CTWBpPJX$hTkyN704ib384kfKsWAV$=t##e4eW>P)KYL zq2U2Q3AxA;bnDF{H5ABi)-pn-+kvw5F{4U-z#kqk6Ue!L2%(ZoKtGNwran#3;i&~n zfsC82B$V_4sNNwPb84FzcewQx0&sGqXnAg9ZpCs73feD zP~3Q)*76Xj#4(akL;=vRooL>4J>I7&0{J)JNT_~w}qX^9n0m`sJq|>JSrd6mw_4mdQ zdLSj6&gdgmcQS!0#CpxnQ3b}HS(DnLAHpL%Bes5MO?^B*YXO15xlxq)E-OZCuELRKpZj>+3 zSLG2xdEP(|WMc>gB=K{3kwERjj}pq3zVKvyb7bADbXD@O0(mVxPAL5(A{}o#k|IT$ zt6XXXQu-zl+WQ3P>7}8B>g?golU4qY)GDe{0goq~BD7o^X|2V}u!hRpn}4{v0+|d= zAvDSYDDJZhMe_d6`=l?>gx;qKH5&=^yC%>MyAXDcXeiL$Zf6Mf4)b^ z1^Q%hj!?`VpxGf98$~FCSR^xndbK)Fs9zS)s0L2dr!!j17_t;7+T Date: Mon, 12 Feb 2024 16:03:38 +0100 Subject: [PATCH 66/75] Time is not essential --- tests/test_comparer.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/test_comparer.py b/tests/test_comparer.py index 1b1e9018d..a6be8a4c1 100644 --- a/tests/test_comparer.py +++ b/tests/test_comparer.py @@ -823,13 +823,8 @@ def test_from_matched_track_data(): "c2": [1.2, 1.3], "mikeswcal5hm0": [1.22, 1.3], }, - index=pd.DatetimeIndex( - [ - pd.Timestamp("2000-01-01T00:00:00"), - pd.Timestamp("2000-01-01T00:00:10"), - ] - ), ) + assert isinstance(df.index, pd.RangeIndex) # Sometime we don't care about time only space cmp = ms.from_matched( data=df, obs_item="c2", mod_items="mikeswcal5hm0", x_item="lon", y_item="lat" From 84e463c32932f98c7b49cf30e3a2a56794d26b13 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 20:42:27 +0100 Subject: [PATCH 67/75] Rely on base class for most reprs --- modelskill/model/dfsu.py | 1 - modelskill/model/grid.py | 5 +++-- modelskill/obs.py | 11 +++-------- modelskill/timeseries/_timeseries.py | 8 +++++++- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/modelskill/model/dfsu.py b/modelskill/model/dfsu.py index 9a61f676c..081ee67e1 100644 --- a/modelskill/model/dfsu.py +++ b/modelskill/model/dfsu.py @@ -92,7 +92,6 @@ def __init__( self.filename = filename # TODO: remove? backward compatibility def __repr__(self) -> str: - # TODO add item name out = [ f"<{self.__class__.__name__}>: {self.name}", f"Quantity: {self.quantity}", diff --git a/modelskill/model/grid.py b/modelskill/model/grid.py index 9a16dee92..e5c7b4eb8 100644 --- a/modelskill/model/grid.py +++ b/modelskill/model/grid.py @@ -92,8 +92,9 @@ def __init__( self.quantity = quantity def __repr__(self) -> str: - # TODO add item name - return f": {self.name}" + return "\n".join( + [f": {self.name}", f"Quantity: {self.quantity}"] + ) @property def time(self) -> pd.DatetimeIndex: diff --git a/modelskill/obs.py b/modelskill/obs.py index 38504e2e0..ffade6bf3 100644 --- a/modelskill/obs.py +++ b/modelskill/obs.py @@ -6,6 +6,7 @@ -------- >>> o1 = PointObservation("klagshamn.dfs0", item=0, x=366844, y=6154291, name="Klagshamn") """ + from __future__ import annotations from typing import Literal, Optional, Any, Union @@ -225,7 +226,7 @@ def z(self, value): self.data["z"] = value def __repr__(self): - out = f"PointObservation: {self.name}, x={self.x}, y={self.y}" + out = f": {self.name}, x={self.x}, y={self.y}" if self.z is not None: out += f", z={self.z}" if len(self._aux_vars) > 0: @@ -346,13 +347,7 @@ def __init__( aux_items=aux_items, ) assert isinstance(data, xr.Dataset) - super().__init__(data=data, weight=weight,attrs=attrs) - - def __repr__(self): - out = f": {self.name}, n={self.n_points}" - if len(self._aux_vars) > 0: - out += f", aux={self._aux_vars}" - return out + super().__init__(data=data, weight=weight, attrs=attrs) def unit_display_name(name: str) -> str: diff --git a/modelskill/timeseries/_timeseries.py b/modelskill/timeseries/_timeseries.py index 9289d3e0e..9bb4323f9 100644 --- a/modelskill/timeseries/_timeseries.py +++ b/modelskill/timeseries/_timeseries.py @@ -233,7 +233,13 @@ def _values_as_series(self) -> pd.Series: return self.data[self.name].to_series() def __repr__(self) -> str: - return f"<{self.__class__.__name__}>: {self.name} (n_points: {self.n_points})" + return "\n".join( + [ + f"<{self.__class__.__name__}>: {self.name}", + f"Time: {self.time[0]} - {self.time[-1]}", + f"Quantity: {self.quantity}", + ] + ) # len() of a DataFrame returns the number of rows, # len() of xr.Dataset returns the number of variables From 3688d6ed921885ec341027bbc5cdfe9119636206 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 12 Feb 2024 21:14:32 +0100 Subject: [PATCH 68/75] The purpose of SkillTable is for presentation. --- tests/test_aggregated_skill.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_aggregated_skill.py b/tests/test_aggregated_skill.py index 085e76515..0e6433d2c 100644 --- a/tests/test_aggregated_skill.py +++ b/tests/test_aggregated_skill.py @@ -90,7 +90,6 @@ def test_skill_table(sk_df1): def test_skill_repr_html(sk_df1): sk = ms.SkillTable(sk_df1) repr_html = sk._repr_html_() - assert "SkillTable" in repr_html assert "obs1" in repr_html From 1fab38c81bdf58987f4ad1ec5ffbf821281ff3ef Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 13 Feb 2024 08:48:23 +0100 Subject: [PATCH 69/75] aux_items arg --- modelskill/model/factory.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modelskill/model/factory.py b/modelskill/model/factory.py index 6cea9afd2..e4bbdbdd1 100644 --- a/modelskill/model/factory.py +++ b/modelskill/model/factory.py @@ -25,6 +25,7 @@ def model_result( data: DataInputType, *, + aux_items: Optional[list[int | str]] = None, gtype: Optional[Literal["point", "track", "unstructured", "grid"]] = None, **kwargs: Any, ) -> Any: @@ -34,6 +35,8 @@ def model_result( ---------- data : DataInputType The data to be used for creating the ModelResult object. + aux_items : Optional[list[int | str]] + Auxiliary items, by default None gtype : Optional[Literal["point", "track", "unstructured", "grid"]] The geometry type of the data. If not specified, it will be guessed from the data. **kwargs @@ -54,6 +57,7 @@ def model_result( return _modelresult_lookup[geometry]( data=data, + aux_items=aux_items, **kwargs, ) From 72dc79c542d91c180b46729b0878492e088420ec Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Tue, 13 Feb 2024 08:48:57 +0100 Subject: [PATCH 70/75] Nice reprs --- modelskill/model/dfsu.py | 12 +++++++----- modelskill/model/grid.py | 10 +++++++--- modelskill/obs.py | 12 ------------ modelskill/timeseries/_timeseries.py | 20 +++++++++++++------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/modelskill/model/dfsu.py b/modelskill/model/dfsu.py index 081ee67e1..37919488d 100644 --- a/modelskill/model/dfsu.py +++ b/modelskill/model/dfsu.py @@ -92,11 +92,13 @@ def __init__( self.filename = filename # TODO: remove? backward compatibility def __repr__(self) -> str: - out = [ - f"<{self.__class__.__name__}>: {self.name}", - f"Quantity: {self.quantity}", - ] - return "\n".join(out) + res = [] + res.append(f"<{self.__class__.__name__}>: {self.name}") + res.append(f"Time: {self.time[0]} - {self.time[-1]}") + res.append(f"Quantity: {self.quantity}") + if len(self.sel_items.aux) > 0: + res.append(f"Auxiliary variables: {', '.join(self.sel_items.aux)}") + return "\n".join(res) @property def time(self) -> pd.DatetimeIndex: diff --git a/modelskill/model/grid.py b/modelskill/model/grid.py index e5c7b4eb8..a7821de56 100644 --- a/modelskill/model/grid.py +++ b/modelskill/model/grid.py @@ -92,9 +92,13 @@ def __init__( self.quantity = quantity def __repr__(self) -> str: - return "\n".join( - [f": {self.name}", f"Quantity: {self.quantity}"] - ) + res = [] + res.append(f"<{self.__class__.__name__}>: {self.name}") + res.append(f"Time: {self.time[0]} - {self.time[-1]}") + res.append(f"Quantity: {self.quantity}") + if len(self.sel_items.aux) > 0: + res.append(f"Auxiliary variables: {', '.join(self.sel_items.aux)}") + return "\n".join(res) @property def time(self) -> pd.DatetimeIndex: diff --git a/modelskill/obs.py b/modelskill/obs.py index ffade6bf3..a7361a154 100644 --- a/modelskill/obs.py +++ b/modelskill/obs.py @@ -143,10 +143,6 @@ def _parse_time(time): else: return time # can be RangeIndex - @property - def _aux_vars(self): - return list(self.data.filter_by_attrs(kind="aux").data_vars) - class PointObservation(Observation): """Class for observations of fixed locations @@ -225,14 +221,6 @@ def z(self): def z(self, value): self.data["z"] = value - def __repr__(self): - out = f": {self.name}, x={self.x}, y={self.y}" - if self.z is not None: - out += f", z={self.z}" - if len(self._aux_vars) > 0: - out += f", aux={self._aux_vars}" - return out - class TrackObservation(Observation): """Class for observation with locations moving in space, e.g. satellite altimetry diff --git a/modelskill/timeseries/_timeseries.py b/modelskill/timeseries/_timeseries.py index 9bb4323f9..9586fd064 100644 --- a/modelskill/timeseries/_timeseries.py +++ b/modelskill/timeseries/_timeseries.py @@ -232,14 +232,20 @@ def _values_as_series(self) -> pd.Series: """Values to series (for plotting)""" return self.data[self.name].to_series() + @property + def _aux_vars(self): + return list(self.data.filter_by_attrs(kind="aux").data_vars) + def __repr__(self) -> str: - return "\n".join( - [ - f"<{self.__class__.__name__}>: {self.name}", - f"Time: {self.time[0]} - {self.time[-1]}", - f"Quantity: {self.quantity}", - ] - ) + res = [] + res.append(f"<{self.__class__.__name__}>: {self.name}") + if self.gtype == str(GeometryType.POINT): + res.append(f"Location: {self.x}, {self.y}") + res.append(f"Time: {self.time[0]} - {self.time[-1]}") + res.append(f"Quantity: {self.quantity}") + if len(self._aux_vars) > 0: + res.append(f"Auxiliary variables: {', '.join(self._aux_vars)}") + return "\n".join(res) # len() of a DataFrame returns the number of rows, # len() of xr.Dataset returns the number of variables From 9c6f01c75284874c31af44e415ae159cf7706b06 Mon Sep 17 00:00:00 2001 From: Ryan Murray <74630349+rywm-dhi@users.noreply.github.com> Date: Tue, 20 Feb 2024 15:22:03 +0100 Subject: [PATCH 71/75] Prevent double plots of taylor diagrams --- modelskill/plotting/_taylor_diagram.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modelskill/plotting/_taylor_diagram.py b/modelskill/plotting/_taylor_diagram.py index 154d348f3..e12507a13 100644 --- a/modelskill/plotting/_taylor_diagram.py +++ b/modelskill/plotting/_taylor_diagram.py @@ -85,4 +85,6 @@ def taylor_diagram( ) fig.suptitle(title, size="x-large") + # prevent the plot from being displayed, since it is also displayed by the returned object + plt.close() return fig From 181f535fef8932804e22a8be9c541b7ff2012b23 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 1 Mar 2024 00:18:19 +0100 Subject: [PATCH 72/75] Use deepcopy --- modelskill/comparison/_collection.py | 16 ++++------------ tests/test_comparercollection.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/modelskill/comparison/_collection.py b/modelskill/comparison/_collection.py index f08e6592e..a251fce64 100644 --- a/modelskill/comparison/_collection.py +++ b/modelskill/comparison/_collection.py @@ -1,4 +1,5 @@ from __future__ import annotations +from copy import deepcopy import os from pathlib import Path import tempfile @@ -253,12 +254,10 @@ def rename(self, mapping: Dict[str, str]) -> "ComparerCollection": return ComparerCollection(cmps) @overload - def __getitem__(self, x: slice | Iterable[Hashable]) -> ComparerCollection: - ... + def __getitem__(self, x: slice | Iterable[Hashable]) -> ComparerCollection: ... @overload - def __getitem__(self, x: int | Hashable) -> Comparer: - ... + def __getitem__(self, x: int | Hashable) -> Comparer: ... def __getitem__( self, x: int | Hashable | slice | Iterable[Hashable] @@ -298,15 +297,8 @@ def __len__(self) -> int: def __iter__(self) -> Iterator[Comparer]: return iter(self._comparers.values()) - def __copy__(self) -> "ComparerCollection": - cls = self.__class__ - cp = cls.__new__(cls) - # TODO should this use deepcopy? - cp.__init__(list(self._comparers)) # type: ignore - return cp - def copy(self) -> "ComparerCollection": - return self.__copy__() + return deepcopy(self) def __add__( self, other: Union["Comparer", "ComparerCollection"] diff --git a/tests/test_comparercollection.py b/tests/test_comparercollection.py index 544d06a35..dec0b8b32 100644 --- a/tests/test_comparercollection.py +++ b/tests/test_comparercollection.py @@ -569,3 +569,13 @@ def test_peak_ratio_2(cc_pr): sk = cc_pr.skill(metrics=["peak_ratio"]) assert "peak_ratio" in sk.data.columns assert sk.to_dataframe()["peak_ratio"].values == pytest.approx(1.0799999095653732) + + +def test_copy(cc): + cc2 = cc.copy() + assert cc2.n_models == 3 + assert cc2.n_points == 10 + assert cc2.start_time == pd.Timestamp("2019-01-01") + assert cc2.end_time == pd.Timestamp("2019-01-07") + assert cc2.obs_names == ["fake point obs", "fake track obs"] + assert cc2.mod_names == ["m1", "m2", "m3"] From 39f5893a7c8015d5e9dc551094066899c976bdfb Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 11 Mar 2024 15:17:05 +0100 Subject: [PATCH 73/75] Release me! --- modelskill/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modelskill/__init__.py b/modelskill/__init__.py index 644121d0d..3daffad31 100644 --- a/modelskill/__init__.py +++ b/modelskill/__init__.py @@ -19,7 +19,7 @@ # Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer. # 'X.Y.dev0' is the canonical version of 'X.Y.dev' # -__version__ = "1.0.dev24" +__version__ = "1.0.0" if "64" not in architecture()[0]: raise Exception("This library has not been tested for a 32 bit system.") diff --git a/pyproject.toml b/pyproject.toml index 5c08ab412..f3d5c8c09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ exclude = ["notebooks", "tests"] [project] name="modelskill" -version="1.0.dev24" +version="1.0.0" dependencies = [ "numpy >= 1.20.0", "pandas >= 1.4", From e0300cadac7f57652e2486fc5a01c3ad8013c0c1 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 11 Mar 2024 15:17:29 +0100 Subject: [PATCH 74/75] Stable --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f3d5c8c09..588a11532 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,7 @@ readme = "README.md" requires-python = ">=3.8" classifiers = [ "License :: OSI Approved :: MIT License", - "Development Status :: 4 - Beta", # TODO: change to stable - #"Development Status :: 5 - Production/Stable", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Science/Research", "Programming Language :: Python", "Programming Language :: Python :: 3", From d55b392096696086e8f03627e5f99a08817d4e35 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Mon, 11 Mar 2024 15:25:58 +0100 Subject: [PATCH 75/75] Dev version --- modelskill/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modelskill/__init__.py b/modelskill/__init__.py index 3daffad31..8e6efdb6b 100644 --- a/modelskill/__init__.py +++ b/modelskill/__init__.py @@ -19,7 +19,7 @@ # Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer. # 'X.Y.dev0' is the canonical version of 'X.Y.dev' # -__version__ = "1.0.0" +__version__ = "1.1.dev0" if "64" not in architecture()[0]: raise Exception("This library has not been tested for a 32 bit system.") diff --git a/pyproject.toml b/pyproject.toml index 588a11532..7cb2370ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ exclude = ["notebooks", "tests"] [project] name="modelskill" -version="1.0.0" +version="1.1.dev0" dependencies = [ "numpy >= 1.20.0", "pandas >= 1.4",