Skip to content

Commit

Permalink
FIX: debug and document run package for use in REF (#18)
Browse files Browse the repository at this point in the history
* fixes to run

* replace nan with javscript NaN

* overall scores don't have an analysis

* docs and exception

* added tests for run
  • Loading branch information
nocollier authored Feb 5, 2025
1 parent 3c63916 commit 51cc6d5
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 16 deletions.
2 changes: 1 addition & 1 deletion ilamb3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def ilamb_catalog() -> pooch.Pooch:
"compare",
"analysis",
"regions",
"output",
"run",
"ilamb_catalog,",
"conf",
]
Expand Down
12 changes: 2 additions & 10 deletions ilamb3/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,13 @@ class AnalysisFailure(ILAMBException):
----------
analysis : str
The name of the analysis which has failed.
variable : str
The name of the variable associated with this analysis.
source : str
The name of the source of the reference data.
model : str
The name of the model whose analysis failed.
"""

def __init__(
self, analysis: str, variable: str, source: str, model: str
): # numpydoc ignore=GL08
def __init__(self, analysis: str, model: str): # numpydoc ignore=GL08
self.analysis = analysis
self.variable = variable
self.source = source
self.model = model

def __str__(self): # numpydoc ignore=GL08
return f"The '{self.analysis}' analysis failed for '{self.variable} | {self.source}' against '{self.model}'"
return f"The '{self.analysis}' analysis failed for '{self.model}'"
72 changes: 67 additions & 5 deletions ilamb3/run.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""Functions for rendering ilamb3 output."""

import importlib
from pathlib import Path

import matplotlib.pyplot as plt
import pandas as pd
import xarray as xr
from jinja2 import Template
Expand All @@ -13,7 +15,25 @@

def run_analyses(
ref: xr.Dataset, com: xr.Dataset, analyses: dict[str, ILAMBAnalysis]
) -> None:
) -> tuple[pd.DataFrame, xr.Dataset, xr.Dataset]:
"""
Run the input analyses on the given reference and comparison datasets.
Parameters
----------
ref : xr.Dataset
The dataset which will be considered as the reference.
com : xr.Dataset
The dataset which will be considered as the comparison.
analyses: dict[str, ILAMBAnalysis]
A dictionary of analyses to run.
Returns
-------
pd.DataFrame, xr.Dataset, xr.Dataset
Analysis output, dataframe with scalar information and datasets with
reference and comparison information for plotting.
"""
dfs = []
ds_refs = []
ds_coms = []
Expand All @@ -34,7 +54,30 @@ def plot_analyses(
ref: xr.Dataset,
com: dict[str, xr.Dataset],
analyses: dict[str, ILAMBAnalysis],
plot_path: Path,
) -> pd.DataFrame:
"""
Plot analysis output encoded in each analysis.
Parameters
----------
df : pd.DataFrame
A dataframe of all scalars from the analyses.
ref : xr.Dataset
A dataset containing reference data for plotting.
com : dict[str,xr.Dataset]
A dictionary of the comparison datasets whose keys are the model names.
analyses : dict[str, ILAMBAnalysis]
A dictionary of analyses to run.
plot_path : Path
A path to prepend all filenames.
Returns
-------
pd.DataFrame
A dataframe containing plot information and matplotlib axes.
"""
plot_path.mkdir(exist_ok=True, parents=True)
df_plots = []
for name, a in analyses.items():
dfp = a.plots(df, ref, com)
Expand All @@ -43,8 +86,9 @@ def plot_analyses(
df_plots = pd.concat(df_plots)
for _, row in df_plots.iterrows():
row["axis"].get_figure().savefig(
f"{row['source']}_{row['region']}_{row['name']}.png"
plot_path / f"{row['source']}_{row['region']}_{row['name']}.png"
)
plt.close("all")
return df_plots


Expand All @@ -54,11 +98,29 @@ def generate_html_page(
com: dict[str, xr.Dataset],
df_plots: pd.DataFrame,
) -> str:
"""."""
"""
Generate an html page encoding all analysis data.
Parameters
----------
df : pd.DataFrame
A dataframe of all scalars from the analyses.
ref : xr.Dataset
A dataset containing reference data for plotting.
com : dict[str,xr.Dataset]
A dictionary of the comparison datasets whose keys are the model names.
df_plots : pd.DataFrame
A dataframe containing plot information and matplotlib axes.
Returns
-------
str
The html page.
"""
ilamb_regions = ilr.Regions()

# Setup template analyses and plots
analyses = {analysis: {} for analysis in df["analysis"].unique()}
analyses = {analysis: {} for analysis in df["analysis"].dropna().unique()}
for (aname, pname), df_grp in df_plots.groupby(["analysis", "name"], sort=False):
analyses[aname][pname] = []
if "Reference" in df_grp["source"].unique():
Expand Down Expand Up @@ -92,7 +154,7 @@ def generate_html_page(
},
"table_data": str(
[row.to_dict() for _, row in df.drop(columns="units").iterrows()]
),
).replace("nan", "NaN"),
}

# Generate the html from the template
Expand Down
61 changes: 61 additions & 0 deletions ilamb3/tests/test_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import tempfile
from pathlib import Path

import cftime as cf
import numpy as np
import xarray as xr

import ilamb3
import ilamb3.run as run
from ilamb3.analysis import bias_analysis


def generate_test_dset(seed: int = 1, nyear=None, nlat=None, nlon=None):
rs = np.random.RandomState(seed)
coords = []
dims = []
if nyear is not None:
time = [
cf.DatetimeNoLeap(1980 + int(m / 12), (m % 12) + 1, 15)
for m in range(nyear * 12)
]
coords.append(time)
dims.append("time")
if nlat is not None:
lat = np.linspace(-90, -80, nlat + 1)
lat = 0.5 * (lat[1:] + lat[:-1])
coords.append(lat)
dims.append("lat")
if nlon is not None:
lon = np.linspace(0, 20, nlon + 1)
lon = 0.5 * (lon[1:] + lon[:-1])
coords.append(lon)
dims.append("lon")
ds = xr.Dataset(
data_vars={
"tas": xr.DataArray(
rs.rand(*[len(c) for c in coords]) * 20,
coords=coords,
dims=dims,
),
}
)
ds["tas"].attrs["units"] = "degC"
return ds


def test_run():
reg = ilamb3.ilamb_catalog()
ref = xr.open_dataset(reg.fetch("test/Test/tas.nc"))
com = generate_test_dset(1, nyear=35, nlat=10, nlon=20)
tmp = Path(tempfile.gettempdir())
ds_com = {}
anl = {"Bias": bias_analysis("tas")}
df, ds_ref, ds_com["Comparison"] = run.run_analyses(ref, com, anl)
dfp = run.plot_analyses(df, ds_ref, ds_com, anl, tmp)
html = run.generate_html_page(df, ds_ref, ds_com, dfp)
q = df.query("type=='score'")
assert len(q) == 1
assert np.allclose(q.iloc[0].value, 0.138678)
assert len(dfp) == 4
assert '<img id="divComparison" src="Comparison_None_mean.png" width="32%">' in html

0 comments on commit 51cc6d5

Please sign in to comment.