diff --git a/CHANGES.rst b/CHANGES.rst
index 5e898fd..a4f5788 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -12,6 +12,8 @@ New features
Breaking changes
----------------
+- The :meth:`xoa.cf.CFSpecs.decode` no uses the :class:`SGLocator` instance provided by
+ :func:`xoa.cf.get_sglocator_pivot` to manage staggered grid locations for the pivot format.
- The :meth:`xoa.cf.CFSpecs.decode` no longer sets the "cf_specs" encoding [:pull:`96`].
- The default `name_format` option of the :cfsec:`sglocator` Cf specication option is set to False to prevent parsing the grid location in names [:pull:`96`].
- :func:`xoa.filter.tidal_filter` raises an :class:`~xoa.XoaError` instead of a simple warning when the time step is greater than an hour.
diff --git a/doc/conf.py b/doc/conf.py
index a57bb5f..5e58893 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -125,9 +125,7 @@
genoptions_declarations = 'genoptions/declarations.txt'
# %% Cfgm
-import xoa.cf
-
-cfgm_get_cfgm_func = xoa.cf._get_cfgm_
+cfgm_get_cfgm_func = "xoa.cf._get_cfgm_"
cfgm_rst_file = "cf.txt"
# %% Extlinks
diff --git a/doc/ext/genlogos.py b/doc/ext/genlogos.py
index 4407c3a..3347ff6 100644
--- a/doc/ext/genlogos.py
+++ b/doc/ext/genlogos.py
@@ -28,7 +28,7 @@ def genlogo(outfile, dark=False):
circlecolor = tuple(c / 255 for c in shomlightblue)
with plt.rc_context({"font.sans-serif": [font]}):
- plt.figure(figsize=(width, height))
+ fig = plt.figure(figsize=(width, height))
ax = plt.axes([0, 0, 1, 1], aspect=1, facecolor="b")
kw = dict(
family="sans-serif",
@@ -40,8 +40,8 @@ def genlogo(outfile, dark=False):
)
ax.text(0.05, 0.5, "X", ha="left", **kw)
ax.text(0.95, 0.5, "A", ha="right", **kw)
- plt.xlim(0, width)
- plt.ylim(0, height)
+ ax.set_xlim(0, width)
+ ax.set_ylim(0, height)
clip_height = 0.26
for y0 in (0, 1 - clip_height):
@@ -61,7 +61,9 @@ def genlogo(outfile, dark=False):
circle.set_clip_box(clip)
ax.axis("off")
- plt.savefig(outfile, transparent=True)
+ fig.savefig(outfile, transparent=True)
+ plt.close(fig)
+ del fig
def genlogos(app):
diff --git a/doc/uses.cf.rst b/doc/uses.cf.rst
index a916edf..160d45e 100644
--- a/doc/uses.cf.rst
+++ b/doc/uses.cf.rst
@@ -27,14 +27,15 @@ default behaviors for user's special datasets.
.. note:: This module shares common feature with the excellent and long
- awaited `xf_xarray `_
+ awaited `cf_xarray `_
package and started a long time before with the Vacumm package.
The most notable differences differences include:
- - The current module is also designed for data variables, not only
+ - The current module is also designed for data variables an dimensions, not only
coordinates.
- - It search for items not only using standard_names but also
- specialized names.
+ - It searches for items not only using standard_names but also
+ specialized names. It means that objetcs can be found a dataset or data array
+ even if they are not properly formatted.
- It is not only available as accessors, but also as independant
objects that can be configured for each type of dataset or in
contexts by the user.
@@ -801,5 +802,6 @@ Now we can read, decode and merge all files without any conflict:
dsv = xoa.open_data_sample("hycom.gdp.u.nc").xoa.decode()
dsh = xoa.open_data_sample("hycom.gdp.h.nc").xoa.decode()
+ print(dsu)
ds = xr.merge([dsu, dsv, dsh])
ds
\ No newline at end of file
diff --git a/examples/plot_croco_section.py b/examples/plot_croco_section.py
index 1bf2227..75943ff 100644
--- a/examples/plot_croco_section.py
+++ b/examples/plot_croco_section.py
@@ -4,7 +4,7 @@
Interpolate a meridional section of CROCO outputs to regular depths
===================================================================
-This notebook, we show:
+In this notebook, we show:
* how to compute the depths from s-coordinates,
* how to easily find the name of variables and coordinates,
@@ -146,5 +146,5 @@
axs[0].set_title("Original")
axs[1].set_title("Interpolated")
-# # %%
-# # Et voilĂ !
+# %%
+# Et voilĂ !
diff --git a/examples/plot_mercator_argo.py b/examples/plot_mercator_argo.py
index e1d1dee..ff15e48 100644
--- a/examples/plot_mercator_argo.py
+++ b/examples/plot_mercator_argo.py
@@ -4,7 +4,7 @@
Compare Mercator to ARGO
========================
-This notebook, we show:
+In this notebook, we show:
* how to easily rename variables and coordinates in an ARGO and a Mercator datasets,
* how to plot a T-S diagram,
@@ -99,7 +99,7 @@
scatter_cmap="cmo.deep",
axes=axs[1],
)
-axs[1].axvline(x=35.65, ls="--", color="k");
+axs[1].axvline(x=35.65, ls="--", color="k")
# %%
# Here we select the last ARGO profile as a reference profile
@@ -161,7 +161,7 @@
ax.scatter(ds_merc_ens_rect.lon, ds_merc_ens_rect.lat, label="Rejected", alpha=0.15, **kws)
ax.scatter(ds_merc_ens.lon, ds_merc_ens.lat, label='Mercator', **kws)
ax.scatter(ds_argo_prof.lon, ds_argo_prof.lat, s=100, c="C2", transform=pcar, label='ARGO')
-plt.legend();
+plt.legend()
# %%
# We used the :func:`xoa.geo.get_extent` to compute a square geographical extent based
@@ -191,7 +191,11 @@
ds_argo_prof.sal.plot(y="depth", label="ARGO", color="C0")
plt.title("Uncertain profile")
plt.legend()
-xplot.plot_double_minimap(ds_argo_prof, regional_ax="left", global_ax=(0.88, 0.88, 0.11),);
+xplot.plot_double_minimap(
+ ds_argo_prof,
+ regional_ax="left",
+ global_ax=(0.88, 0.88, 0.11),
+)
# %%
# Therefore, if we accept an uncertainty in the positioning of the ocean
@@ -228,7 +232,7 @@
sal_argo_prof_m.plot(y="depth", label="ARGO", color="C0", ax=axes[1])
plt.stairs(sal_argo_prof_m, merc_prof_edges, orientation="horizontal", color="C0", lw=0.5)
axes[1].set_title("On Mercator depths")
-axes[1].axis(axis);
+axes[1].axis(axis)
# %%
# These plots show that the model is too haline, except at the
diff --git a/xoa/_samples/gdp.cfg b/xoa/_samples/gdp.cfg
index 434bb1d..f62745c 100644
--- a/xoa/_samples/gdp.cfg
+++ b/xoa/_samples/gdp.cfg
@@ -1,3 +1,6 @@
+[sglocator]
+name_format=False
+
[coords]
[[lon]]
diff --git a/xoa/_samples/hycom.cfg b/xoa/_samples/hycom.cfg
index ceb58d6..2481f47 100644
--- a/xoa/_samples/hycom.cfg
+++ b/xoa/_samples/hycom.cfg
@@ -4,6 +4,10 @@ name=hycom
[[attrs]]
nsigma = "[0-9]?"
+[sglocator]
+name_format="{root}_{loc}"
+valid_locations=u,v
+
[vertical]
positive=down
type=dz
diff --git a/xoa/cf.py b/xoa/cf.py
index b2819d3..25f2d1b 100644
--- a/xoa/cf.py
+++ b/xoa/cf.py
@@ -731,6 +731,14 @@ def add_loc(self, da, loc, to_name=True, to_attrs=True):
)
+def get_sglocator_pivot():
+ """Get the :class:`SGLocator` instance that is used as a pivot format"""
+ cache = _get_cache_()
+ if "sglocator_pivot" not in cache:
+ cache["sglocator_pivot"] = SGLocator()
+ return cache["sglocator_pivot"]
+
+
def _solve_rename_conflicts_(rename_args):
"""Skip renaming items that overwride previous items"""
used = {}
@@ -933,6 +941,17 @@ def sglocator(self):
""":class:`SGLocator` instance"""
return self._sgl
+ def get_sglocator(self, specialize):
+ """Get the right :class:`SGLocator` instance
+
+ Parameters
+ ----------
+ specialize: book
+ If True, the locator is the one of this dataset, as given by :attr:`sglocator`.
+ Else, if is the pivot locator as given by :func:`get_sglocator_pivot`.
+ """
+ return self._sgl if specialize else get_sglocator_pivot()
+
@property
def cfgspecs(self):
return self._cfgspecs
@@ -2746,8 +2765,11 @@ def format_dataarray(
elif not attrs:
attrs = {}
+ # Get the appropriate sglocator for formatting
+ sglocator = self.parent.get_sglocator(specialize)
+
# Format array
- new_da = self.sglocator.format_dataarray(
+ new_da = sglocator.format_dataarray(
da,
loc=loc,
name=new_name,
@@ -2763,8 +2785,8 @@ def format_dataarray(
# Return new name but don't rename
if not rename:
if old_name is None:
- return self.sglocator.format_attr("name", new_name, loc)
- return self.sglocator.merge_attr("name", old_name, new_name, loc)
+ return sglocator.format_attr("name", new_name, loc)
+ return sglocator.merge_attr("name", old_name, new_name, loc)
# # Rename dim if axis coordinate
# rename_dim = rename and rename_dim
diff --git a/xoa/cfgm.py b/xoa/cfgm.py
index d6f3278..1d280a4 100644
--- a/xoa/cfgm.py
+++ b/xoa/cfgm.py
@@ -33,6 +33,7 @@
from collections import OrderedDict
from warnings import warn
import logging
+import importlib
try:
import configobj.validate as validate
@@ -584,7 +585,7 @@ def is_dict(value, default={}, vtype=None):
"cmap": is_cmap,
"color": is_color,
"dict": is_dict,
- "boolstr": is_boolstr
+ "boolstr": is_boolstr,
# lists validators for these scalars will be automatically generated
}
@@ -2175,7 +2176,10 @@ def gen_cfgm_rst(app):
logging.info("Generating rst declarations for the ConfigManager")
- rst = app.config.cfgm_get_cfgm_func().to_rst(secrole="cfgmsec", optrole="cfgmopt")
+ mname, fname = os.path.splitext(app.config.cfgm_get_cfgm_func)
+ mloaded = importlib.import_module(mname)
+ func = getattr(mloaded, fname[1:])
+ rst = func().to_rst(secrole="cfgmsec", optrole="cfgmopt")
outfile = os.path.abspath(app.config.cfgm_rst_file)
outdir = os.path.dirname(outfile)
@@ -2192,7 +2196,10 @@ def gen_cfgm_cfg(app):
return
logging.info("Generating the default config from the ConfigManager")
- cfg = app.config.cfgm_get_cfgm_func().defaults
+ mname, fname = os.path.splitext(app.config.cfgm_get_cfgm_func)
+ mloaded = importlib.import_module(mname)
+ func = getattr(mloaded, fname[1:])
+ cfg = func().defaults
outfile = os.path.abspath(app.config.cfgm_cfg_file)
outdir = os.path.dirname(outfile)
if not os.path.exists(outdir):