From 6748626e05bba51b0d3d1a6315658f7783998941 Mon Sep 17 00:00:00 2001 From: Sandor Kertesz Date: Tue, 12 May 2026 08:02:02 +0100 Subject: [PATCH 1/6] Xarray earthkit accessor update --- src/earthkit/data/xr_engine/accessor.py | 96 ++++++++++++++++ src/earthkit/data/xr_engine/builder.py | 77 ++++++------- src/earthkit/data/xr_engine/engine.py | 123 +++++++++++++++++---- src/earthkit/data/xr_engine/grid.py | 19 ++++ tests/xr_engine/test_xr_engine_accessor.py | 64 +++++++++++ tests/xr_engine/test_xr_engine_write.py | 11 +- 6 files changed, 330 insertions(+), 60 deletions(-) create mode 100644 src/earthkit/data/xr_engine/accessor.py create mode 100644 tests/xr_engine/test_xr_engine_accessor.py diff --git a/src/earthkit/data/xr_engine/accessor.py b/src/earthkit/data/xr_engine/accessor.py new file mode 100644 index 000000000..57156dc0b --- /dev/null +++ b/src/earthkit/data/xr_engine/accessor.py @@ -0,0 +1,96 @@ +# (C) Copyright 2020 ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +# + + +class EarthkitAttrsBuilder: + ACCESSOR_KEY = "_earthkit" + VARIABLE_GRID_SPEC_KEY = "earthkit_grid_spec" + + @staticmethod + def grid_spec_str(field): + try: + grid_spec = field.geography.grid_spec() + if grid_spec is not None: + import json + + return json.dumps(grid_spec) + return None + + except Exception: + return None + + # def build_variable_grid_spec_attr(self, field): + # grid_spec = self.grid_spec_str(field) + # if grid_spec is not None: + # return {self.VARIABLE_GRID_SPEC_KEY: grid_spec} + # return dict() + + def build(self, field, add_earthkit_attrs=True): + res = dict() + grid_spec = self.grid_spec_str(field) + + if add_earthkit_attrs: + bpv = None + try: + md = field._get_grib().message(deflate=True) + bpv = field._get_grib().get_extra_key("bitsPerValue", default=None) + if bpv is None: + bpv = field.get("metadata.bitsPerValue", default=None) + except Exception: + md = "" + + attrs = { + "message": md, + } + + if bpv is not None and bpv != 0: + attrs["bitsPerValue"] = bpv + + if grid_spec is not None: + attrs["grid_spec"] = grid_spec + + res[self.ACCESSOR_KEY] = attrs + + # if grid_spec is not None: + # res[self.VARIABLE_GRID_SPEC_KEY] = grid_spec + + return res + + def set(self, field, da_attrs): + res = dict() + + grid_spec = self.grid_spec_str(field) + + attrs_ori = da_attrs.get(self.ACCESSOR_KEY, dict()) + attrs = attrs_ori.copy() + + if attrs_ori: + try: + message = field._get_grib().message(deflate=True) + except Exception: + message = "" + + if message: + attrs["message"] = message + else: + del attrs["message"] + + if grid_spec is not None: + attrs["grid_spec"] = grid_spec + elif "grid_spec" in attrs: + del attrs["grid_spec"] + + res[self.ACCESSOR_KEY] = attrs + + if grid_spec is not None: + res[self.VARIABLE_GRID_SPEC_KEY] = grid_spec + elif self.VARIABLE_GRID_SPEC_KEY in res: + res[self.VARIABLE_GRID_SPEC_KEY] = None + + return res diff --git a/src/earthkit/data/xr_engine/builder.py b/src/earthkit/data/xr_engine/builder.py index 108542383..e2003929a 100644 --- a/src/earthkit/data/xr_engine/builder.py +++ b/src/earthkit/data/xr_engine/builder.py @@ -72,42 +72,47 @@ def __init__( self.remapping = remapping def build(self, add_earthkit_attrs=True): - grid_spec = None - try: - grid_spec = self.tensor.source[0].geography.grid_spec() - if grid_spec is not None: - if isinstance(grid_spec, dict): - import json - - grid_spec = json.dumps(grid_spec) - except Exception: - grid_spec = None - - if add_earthkit_attrs: - f = self.tensor.source[0] - bpv = None - try: - md = f._get_grib().message(deflate=True) - bpv = f._get_grib().get_extra_key("bitsPerValue", default=None) - if bpv is None: - bpv = f.get("metadata.bitsPerValue", default=None) - except Exception: - md = "" + from .accessor import EarthkitAttrsBuilder - attrs = { - "message": md, - } + attrs = EarthkitAttrsBuilder().build(self.tensor.source[0], add_earthkit_attrs=add_earthkit_attrs) + if attrs: + self._attrs.update(attrs) - if bpv is not None and bpv != 0: - attrs["bitsPerValue"] = bpv + # try: + # grid_spec = self.tensor.source[0].geography.grid_spec() + # if grid_spec is not None: + # if isinstance(grid_spec, dict): + # import json - if grid_spec is not None: - attrs["grid_spec"] = grid_spec + # grid_spec = json.dumps(grid_spec) + # except Exception: + # grid_spec = None - self._attrs["_earthkit"] = attrs + # if add_earthkit_attrs: + # f = self.tensor.source[0] + # bpv = None + # try: + # md = f._get_grib().message(deflate=True) + # bpv = f._get_grib().get_extra_key("bitsPerValue", default=None) + # if bpv is None: + # bpv = f.get("metadata.bitsPerValue", default=None) + # except Exception: + # md = "" - if grid_spec is not None: - self._attrs["earthkit_grid_spec"] = grid_spec + # attrs = { + # "message": md, + # } + + # if bpv is not None and bpv != 0: + # attrs["bitsPerValue"] = bpv + + # if grid_spec is not None: + # attrs["grid_spec"] = grid_spec + + # self._attrs["_earthkit"] = attrs + + # if grid_spec is not None: + # self._attrs["earthkit_grid_spec"] = grid_spec self._attrs.update(self.fixed_local_attrs) data = self.data_maker(self.tensor, self.var_dims, self.name) @@ -431,7 +436,11 @@ def build(self): # build variable and global attributes xr_attrs = self.profile.attrs.builder.build(self.ds, var_builders, rename=True) + xr_coords = self.coords() + grid_spec = self.grid.grid_spec_str + if grid_spec is not None: + xr_coords["earthkit_grid_spec"] = grid_spec # build variables xr_vars = { @@ -444,12 +453,6 @@ def build(self): dataset = self.profile.rename_dataset_dims(dataset) - # dim_map = self.profile.rename_dims_map() - # if dim_map: - # d = {k: v for k, v in dim_map.items() if k in dataset.dims} - # if d: - # dataset = dataset.rename(d) - if "source" not in dataset.encoding: dataset.encoding["source"] = None diff --git a/src/earthkit/data/xr_engine/engine.py b/src/earthkit/data/xr_engine/engine.py index 87c0fd9a1..542ff741d 100644 --- a/src/earthkit/data/xr_engine/engine.py +++ b/src/earthkit/data/xr_engine/engine.py @@ -466,6 +466,19 @@ def _default_encoder(self): return GeneratorFieldList(self._to_fields()) + def _to_dict(self, s): + if isinstance(s, dict): + return s + elif isinstance(s, str): + import json + + try: + return json.loads(s) + except Exception: + return None + else: + return None + @xarray.register_dataarray_accessor("earthkit") class XarrayEarthkitDataArray(XarrayEarthkit): @@ -474,6 +487,51 @@ def __init__(self, xarray_obj): @property def _reference_field(self): + # if "_earthkit" not in self._obj.attrs: + # raise ValueError( + # "The xarray object does not contain the '_earthkit' attribute. Cannot determine the reference field." + # ) + + # md = self._obj.attrs.get("_earthkit") + + # if not isinstance(md, dict): + # raise ValueError( + # ( + # "The '_earthkit' attribute must be a dictionary containing the metadata of the" + # f" reference field. Found: {type(md)}" + # ) + # ) + + # if "message" not in md: + # raise ValueError( + # "The '_earthkit' attribute must contain the 'message' key with the metadata of the reference field." + # ) + + message = self._grib_message + + # if not message: + # raise ValueError( + # "The 'message' key in the '_earthkit' attrsibute must contain the metadata of the reference field." + # ) + + try: + if message: + from earthkit.data.field.grib.create import create_grib_field_from_message + + return create_grib_field_from_message(message) + except Exception as e: + raise ValueError( + ( + "Could not generate earthkit reference field from xarray object." + "Attribute '_earthkit' contains incorrect data." + f"Error: {str(e)}" + ) + ) from e + + return None + + @property + def _grib_message(self): if "_earthkit" not in self._obj.attrs: raise ValueError( "The xarray object does not contain the '_earthkit' attribute. Cannot determine the reference field." @@ -501,19 +559,7 @@ def _reference_field(self): "The 'message' key in the '_earthkit' attribute must contain the metadata of the reference field." ) - try: - if message: - from earthkit.data.field.grib.create import create_grib_field_from_message - - return create_grib_field_from_message(message) - except Exception as e: - raise ValueError( - ( - "Could not generate earthkit reference field from xarray object." - "Attribute '_earthkit' contains incorrect data." - f"Error: {str(e)}" - ) - ) from e + return message def _extra_grib_metadata(self): if "_earthkit" in self._obj.attrs: @@ -563,21 +609,56 @@ def to_device(self, device, *, array_backend=None, array_namespace=None, **kwarg return da @property - def grid_spec(self): + def grid_spec(self) -> dict | None: """Return the grid specification of the DataArray.""" try: if "earthkit_grid_spec" in self._obj.attrs: - v = self._obj.attrs["earthkit_grid_spec"] - if isinstance(v, str): - import json + v = self._obj.attrs.get("earthkit_grid_spec", None) + v = self._to_dict(v) + if v is not None: + return v + + except Exception: + pass + + try: + if "_earthkit" in self._obj.attrs: + v = self._obj.attrs["_earthkit"].get("grid_spec", None) + v = self._to_dict(v) + if v is not None: + return v + except Exception: + pass - return json.loads(v) - return v + try: return self._reference_field.geography.grid_spec() - except Exception as e: - print(e) + except Exception: + # print(e) return None + def set(self, *args, **kwargs): + """Return a new DataArray with updated attributes.""" + if not args and not kwargs: + return self._obj + + field = self._reference_field + if field is None: + raise ValueError( + ( + "Cannot update attributes of the reference field because it cannot be determined" + " from the xarray object." + ) + ) + + from .accessor import EarthkitAttrsBuilder + + field = field.set(*args, **kwargs).sync() + da = self._obj.copy(deep=False) + attrs = EarthkitAttrsBuilder().set(field, da.attrs) + da.attrs.update(attrs) + + return da + @xarray.register_dataset_accessor("earthkit") class XarrayEarthkitDataSet(XarrayEarthkit): diff --git a/src/earthkit/data/xr_engine/grid.py b/src/earthkit/data/xr_engine/grid.py index 1100e44b3..722592b39 100644 --- a/src/earthkit/data/xr_engine/grid.py +++ b/src/earthkit/data/xr_engine/grid.py @@ -117,6 +117,9 @@ class TensorGrid: def __init__(self, field, flatten_values=False): self.dims, self.coords, self.coords_dim = self.build(field, flatten_values) + self.grid_spec = field.geography.grid_spec() + self.grid_spec_str = self._to_str(self.grid_spec) + @staticmethod def build(field, flatten_values): field_shape = field.shape @@ -193,3 +196,19 @@ def build(field, flatten_values): assert v.size == math.prod([dims[x] for x in coords_dim[k]]) return dims, coords, coords_dim + + @staticmethod + def _to_str(d): + if isinstance(d, (str)): + return d + elif isinstance(d, (dict, list, tuple)): + try: + if d is not None: + import json + + return json.dumps(d) + + except Exception: + return None + + return None diff --git a/tests/xr_engine/test_xr_engine_accessor.py b/tests/xr_engine/test_xr_engine_accessor.py new file mode 100644 index 000000000..17f81e308 --- /dev/null +++ b/tests/xr_engine/test_xr_engine_accessor.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# (C) Copyright 2020 ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +# + + +import pytest +from earthkit.utils.array import array_namespace as eku_array_namespace + +from earthkit.data import from_source +from earthkit.data.utils.testing import earthkit_remote_test_data_file + +_NUMPY = eku_array_namespace("numpy") + + +@pytest.mark.cache +@pytest.mark.parametrize("lazy_load", [True, False]) +def test_xr_engine_accessor_1(lazy_load): + ds_ek = from_source("url", earthkit_remote_test_data_file("xr_engine/level/pl.grib")).to_fieldlist() + + ds = ds_ek.to_xarray(lazy_load=lazy_load) + + print(ds) + da = ds["t"] + print(da) + + ref_grid_spec_dict = {"grid": [10, 10]} + ref_grid_spec_str = '{"grid": [10, 10]}' + ref_grid_spec_1_dict = {"grid": "O32"} + ref_grid_spec_1_str = '{"grid": "O32"}' + + md = da.attrs["_earthkit"] + assert "message" in md + assert isinstance(md["message"], bytes) + assert md["grid_spec"] == ref_grid_spec_str + assert da.attrs["earthkit_grid_spec"] == ref_grid_spec_str + assert da.earthkit.grid_spec == ref_grid_spec_dict + + field = da.earthkit._reference_field + assert field is not None + assert field._get_grib().message(deflate=True) == md["message"] + assert field.geography.grid_spec() == ref_grid_spec_dict + + # modify + da_1 = da.earthkit.set({"geography.grid_spec": {"grid": "O32"}}) + + md_1 = da_1.attrs["_earthkit"] + assert "message" in md_1 + assert isinstance(md_1["message"], bytes) + assert md_1["grid_spec"] == ref_grid_spec_1_str + assert da_1.attrs["earthkit_grid_spec"] == ref_grid_spec_1_str + assert da_1.earthkit.grid_spec == ref_grid_spec_1_dict + + field_1 = da_1.earthkit._reference_field + assert field_1 is not None + assert field_1.geography.grid_spec() == ref_grid_spec_1_dict + assert da_1.attrs["_earthkit"]["grid_spec"] == ref_grid_spec_1_str + assert da_1.attrs["earthkit_grid_spec"] == ref_grid_spec_1_str diff --git a/tests/xr_engine/test_xr_engine_write.py b/tests/xr_engine/test_xr_engine_write.py index 75ba21c74..ea81ebe19 100644 --- a/tests/xr_engine/test_xr_engine_write.py +++ b/tests/xr_engine/test_xr_engine_write.py @@ -28,7 +28,12 @@ [ {"profile": "mars", "time_dims": ["date", "time", "step"]}, {"profile": "mars", "time_dims": ["forecast_reference_time", "step"]}, - {"profile": "mars", "time_dims": ["date", "time", "step"], "decode_times": False, "decode_timedelta": False}, + { + "profile": "mars", + "time_dims": ["date", "time", "step"], + "decode_times": False, + "decode_timedelta": False, + }, { "profile": "mars", "time_dims": ["forecast_reference_time", "step"], @@ -326,7 +331,9 @@ def test_xr_engine_write_bits_per_value(allow_holes, lazy_load): xr.set_options(keep_attrs=True) ds = ds_ek.to_xarray( - allow_holes=allow_holes, lazy_load=lazy_load, **{"profile": "mars", "time_dims": ["date", "time", "step"]} + allow_holes=allow_holes, + lazy_load=lazy_load, + **{"profile": "mars", "time_dims": ["date", "time", "step"]}, ) ds += 1 From 2549069fbb635eb6512f07796f97e5ef12d6122c Mon Sep 17 00:00:00 2001 From: Sandor Kertesz Date: Tue, 12 May 2026 17:17:57 +0100 Subject: [PATCH 2/6] Allow updating Xarray earthkit accessor --- docs/source/how-tos/grib/grib_overview.ipynb | 31 ++-- docs/source/how-tos/grib/grib_to_netcdf.ipynb | 12 +- docs/source/how-tos/source/data.ipynb | 148 ++------------- .../how-tos/source/data_from_stream.ipynb | 2 +- docs/source/how-tos/source/file_stream.ipynb | 2 +- .../xr_engine/xarray_engine_ensemble.ipynb | 14 +- .../xarray_engine_mono_variable.ipynb | 64 ++++--- ...array_engine_mono_variable_remapping.ipynb | 8 +- .../xr_engine/xarray_engine_step_ranges.ipynb | 12 +- src/earthkit/data/utils/__init__.py | 28 +++ src/earthkit/data/xr_engine/accessor.py | 71 ++++--- src/earthkit/data/xr_engine/builder.py | 46 +---- src/earthkit/data/xr_engine/engine.py | 175 +++++++++--------- tests/xr_engine/test_xr_engine_accessor.py | 29 +-- tests/xr_engine/test_xr_engine_attrs.py | 4 +- tests/xr_engine/test_xr_engine_dims.py | 5 - 16 files changed, 272 insertions(+), 379 deletions(-) diff --git a/docs/source/how-tos/grib/grib_overview.ipynb b/docs/source/how-tos/grib/grib_overview.ipynb index fcd8d3f07..95779c8c1 100644 --- a/docs/source/how-tos/grib/grib_overview.ipynb +++ b/docs/source/how-tos/grib/grib_overview.ipynb @@ -13,6 +13,11 @@ "# Using GRIB data" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, { "attachments": {}, "cell_type": "raw", @@ -946,8 +951,8 @@ "
\n", "
\n", "\n", - "\n", - "\n", + "\n", + "\n", "
\n", "
GRIB file

\n", - "\n", - "\n", - "
pathtest.grib
size720
typesfieldlist, pandas, xarray, numpy, array
" - ], - "text/plain": [ - "GRIB file\n", - "path: test.grib\n", - "size: 720\n", - "types: fieldlist, pandas, xarray, numpy, array" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "d.describe()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "9339dc43-352c-4115-a097-ba69a1dcf641", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "GRIB file\n", - "path: test.grib\n", - "size: 720\n", - "types: fieldlist, pandas, xarray, numpy, array\n", - "\n" - ] - } - ], - "source": [ - "print(d.describe())" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "ec642c37-5f5f-4a38-8e57-1fb1a90b16e3", - "metadata": {}, - "outputs": [], - "source": [ - "buf = fl[0].message()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "b50cbfcf-5593-44f3-87bb-0379cc5d99f6", - "metadata": {}, - "outputs": [], - "source": [ - "r = ekd.from_source(\"memory\", buf)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "79613602-01de-4470-b41b-71c70370ebea", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "r" - ] - }, { "cell_type": "code", "execution_count": null, "id": "79df2e7e-da86-4a80-af71-7d00697e3a03", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [] } diff --git a/docs/source/how-tos/source/data_from_stream.ipynb b/docs/source/how-tos/source/data_from_stream.ipynb index 8bfa039d6..dd6f3efe2 100644 --- a/docs/source/how-tos/source/data_from_stream.ipynb +++ b/docs/source/how-tos/source/data_from_stream.ipynb @@ -1234,7 +1234,7 @@ " t (level, latitude, longitude) float64 1kB ...\n", "Attributes:\n", " Conventions: CF-1.8\n", - " institution: ECMWF
" + " institution: ECMWF
" ], "text/plain": [ " Size: 2kB\n", diff --git a/docs/source/how-tos/source/file_stream.ipynb b/docs/source/how-tos/source/file_stream.ipynb index 5c87c0434..0d0e7bba8 100644 --- a/docs/source/how-tos/source/file_stream.ipynb +++ b/docs/source/how-tos/source/file_stream.ipynb @@ -1224,7 +1224,7 @@ " t (level, latitude, longitude) float64 1kB ...\n", "Attributes:\n", " Conventions: CF-1.8\n", - " institution: ECMWF
" + " institution: ECMWF" ], "text/plain": [ " Size: 2kB\n", diff --git a/docs/source/how-tos/xr_engine/xarray_engine_ensemble.ipynb b/docs/source/how-tos/xr_engine/xarray_engine_ensemble.ipynb index c70a3cb3f..8660e7c4b 100644 --- a/docs/source/how-tos/xr_engine/xarray_engine_ensemble.ipynb +++ b/docs/source/how-tos/xr_engine/xarray_engine_ensemble.ipynb @@ -43,7 +43,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "791c6da0950f465dba97ab9034c4fd6c", + "model_id": "b78cb395072349feadef4532397d5928", "version_major": 2, "version_minor": 0 }, @@ -788,10 +788,10 @@ " t (member, step, latitude, longitude) float64 33kB ...\n", "Attributes:\n", " Conventions: CF-1.8\n", - " institution: ECMWF
    • t
      (member, step, latitude, longitude)
      float64
      ...
      standard_name :
      air_temperature
      long_name :
      Temperature
      units :
      kelvin
      level_type :
      pressure
      _earthkit :
      {'message': b"GRIB\\x00\\x00\\xa2\\x01\\x00\\x00j\\x80b\\x9a\\xff\\x80\\x82d\\x01\\xf4\\x18\\x06\\x03\\x00\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x15\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x1e\\x01\\n\\x04\\x0b0001\\x003\\x02\\x00\\x00\\x00\\x014\\xd8\\xdb\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\xff\\x00\\x00$\\x00\\x13\\x01_\\x90\\x00\\x00\\x00\\x80\\x81_\\x90\\x05W0'\\x10'\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\x80\\x02D\\xb9}n\\x00\\x007777", 'bitsPerValue': 12, 'grid_spec': '{"grid": [10, 10]}'}
      [4104 values with dtype=float64]
  • Conventions :
    CF-1.8
    institution :
    ECMWF
  • " ], "text/plain": [ " Size: 33kB\n", @@ -1394,10 +1394,10 @@ " t (member, step, latitude, longitude) float64 33kB ...\n", "Attributes:\n", " Conventions: CF-1.8\n", - " institution: ECMWF
    • t
      (member, step, latitude, longitude)
      float64
      ...
      standard_name :
      air_temperature
      long_name :
      Temperature
      units :
      kelvin
      level_type :
      pressure
      _earthkit :
      {'message': b"GRIB\\x00\\x00\\xa2\\x01\\x00\\x00j\\x80b\\x9a\\xff\\x80\\x82d\\x01\\xf4\\x18\\x06\\x03\\x00\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x15\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x1e\\x01\\n\\x04\\x0b0001\\x003\\x02\\x00\\x00\\x00\\x014\\xd8\\xdb\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\xff\\x00\\x00$\\x00\\x13\\x01_\\x90\\x00\\x00\\x00\\x80\\x81_\\x90\\x05W0'\\x10'\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\x80\\x02D\\xb9}n\\x00\\x007777", 'bitsPerValue': 12, 'grid_spec': '{"grid": [10, 10]}'}
      [4104 values with dtype=float64]
  • Conventions :
    CF-1.8
    institution :
    ECMWF
  • " ], "text/plain": [ " Size: 33kB\n", diff --git a/docs/source/how-tos/xr_engine/xarray_engine_mono_variable.ipynb b/docs/source/how-tos/xr_engine/xarray_engine_mono_variable.ipynb index 5df6d5300..9619c3505 100644 --- a/docs/source/how-tos/xr_engine/xarray_engine_mono_variable.ipynb +++ b/docs/source/how-tos/xr_engine/xarray_engine_mono_variable.ipynb @@ -3,7 +3,13 @@ { "cell_type": "markdown", "id": "b74f6a93-148e-4668-a401-6104f54838e1", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "# Xarray engine: mono variable" ] @@ -33,7 +39,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "7045d0c32d644a5cb16f20221e7c8eca", + "model_id": "54699725d9864ef48a53329870afa71b", "version_major": 2, "version_minor": 0 }, @@ -646,10 +652,10 @@ " data (valid_datetime, variable, values) float64 105kB dask.array<chunksize=(732, 2, 9), meta=np.ndarray>\n", "Attributes:\n", " Conventions: CF-1.8\n", - " institution: ECMWF