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):