Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Overview

In this tutorial we are going to use a large collection of pre-generated Kerchunk reference files and open them with Xarray’s new DataTree functionality. This chapter is heavily inspired by this blog post.

About the Dataset

This collection of reference files were generated from the NASA NEX-GDDP-CMIP6 (Global Daily Downscaled Projections) dataset. A version of this dataset is hosted on s3 as a collection of NetCDF files.

Prerequisites

ConceptsImportanceNotes
Kerchunk BasicsRequiredCore
Multiple Files and KerchunkRequiredCore
Kerchunk and DaskRequiredCore
Multi-File Datasets with KerchunkRequiredIO/Visualization
Xarray-Datatree OverviewRequiredIO
  • Time to learn: 30 minutes

Motivation

In total the dataset is roughly 12TB in compressed blob storage, with a single NetCDF file per yearly timestep, per variable. Downloading this entire dataset for analysis on a local machine would difficult to say the least. The collection of Kerchunk reference files for this entire dataset is only 272 Mb, which is about 42,000 times smaller!

Imports

import dask
import hvplot.xarray  # noqa
import pandas as pd
import xarray as xr
from xarray import DataTree
from distributed import Client
from fsspec.implementations.reference import ReferenceFileSystem
Loading...
Loading...
Loading...
Loading...

Read the reference catalog

The NASA NEX-GDDP-CMIP6 dataset is organized by GCM, Scenario and Ensemble Member. Each of these Scenario/GCM combinations is represented as a combined reference file, which was created by merging across variables and concatenating along time-steps. All of these references are organized into a simple .csv catalog in the schema:

GCM/Scenariourl

Organzing with Xarray-Datatree

Not all of the GCM/Scenario reference datasets have shared spatial coordinates and many of the have slight differences in their calendar and thus time dimension. Because of this, these cannot be combined into a single Xarray-Dataset. Fortunately Xarray-Datatree provides a higher level abstraction where related Xarray-Datasets are organized into a tree structure where each dataset corresponds to a leaf.

# Read the reference catalog into a Pandas DataFrame
cat_df = pd.read_csv(
    "s3://carbonplan-share/nasa-nex-reference/reference_catalog_nested.csv"
)
# Convert the DataFrame into a dictionary
catalog = cat_df.set_index("ID").T.to_dict("records")[0]

Load Reference Datasets into Xarray-DataTree

In the following cell we create a function load_ref_ds, which can be parallelized via Dask to load Kerchunk references into a dictionary of Xarray-Datasets.

def load_ref_ds(url: str):
    fs = ReferenceFileSystem(
        url,
        remote_protocol="s3",
        target_protocol="s3",
        remote_options={"anon": True},
        target_options={"anon": True},
        lazy=True,
    )
    return xr.open_dataset(
        fs.get_mapper(),
        engine="zarr",
        backend_kwargs={"consolidated": False},
        chunks={"time": 300},
    )


tasks = {id: dask.delayed(load_ref_ds)(url) for id, url in catalog.items()}

Use Dask Distributed to load the Xarray-Datasets from Kerchunk reference files

Using Dask, we are loading 164 reference datasets into memory. Since they are are Xarray datasets the coordinates are loaded eagerly, but the underlying data is still lazy.

client = Client(n_workers=8)
client
Loading...
catalog_computed = dask.compute(tasks)
2025-12-19 00:46:32,006 - distributed.worker - ERROR - Compute Failed
Key:       load_ref_ds-fa6f62bf-91f6-4471-aaae-547fa836e2b0
State:     executing
Task:  <Task 'load_ref_ds-fa6f62bf-91f6-4471-aaae-547fa836e2b0' load_ref_ds(...)>
Exception: 'ValueError("Reference-FS\'s target filesystem must have same value of asynchronous")'
Traceback: '  File "/tmp/ipykernel_4318/3963997076.py", line 10, in load_ref_ds\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/api.py", line 606, in open_dataset\n    backend_ds = backend.open_dataset(\n        filename_or_obj,\n    ...<2 lines>...\n        **kwargs,\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 1660, in open_dataset\n    store = ZarrStore.open_group(\n        filename_or_obj,\n    ...<10 lines>...\n        cache_members=cache_members,\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 714, in open_group\n    ) = _get_open_params(\n        ~~~~~~~~~~~~~~~~^\n        store=store,\n        ^^^^^^^^^^^^\n    ...<9 lines>...\n        zarr_format=zarr_format,\n        ^^^^^^^^^^^^^^^^^^^^^^^^\n    )\n    ^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 1902, in _get_open_params\n    zarr_group = zarr.open_group(store, **open_kwargs)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/synchronous.py", line 549, in open_group\n    sync(\n    ~~~~^\n        async_api.open_group(\n        ^^^^^^^^^^^^^^^^^^^^^\n    ...<12 lines>...\n        )\n        ^\n    )\n    ^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py", line 159, in sync\n    raise return_result\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py", line 119, in _runner\n    return await coro\n           ^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/asynchronous.py", line 860, in open_group\n    store_path = await make_store_path(store, mode=mode, storage_options=storage_options, path=path)\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py", line 422, in make_store_path\n    store = await make_store(store_like, mode=mode, storage_options=storage_options)\n            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py", line 354, in make_store\n    return FsspecStore.from_mapper(store_like, read_only=_read_only)\n           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py", line 197, in from_mapper\n    fs = _make_async(fs_map.fs)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py", line 57, in _make_async\n    return fsspec.AbstractFileSystem.from_json(json.dumps(fs_dict))\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 1491, in from_json\n    return json.loads(blob, cls=FilesystemJSONDecoder)\n           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/__init__.py", line 365, in loads\n    return cls(**kw).decode(s)\n           ~~~~~~~~~~~~~~~~^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py", line 345, in decode\n    obj, end = self.raw_decode(s, idx=_w(s, 0).end())\n               ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py", line 361, in raw_decode\n    obj, end = self.scan_once(s, idx)\n               ~~~~~~~~~~~~~~^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/json.py", line 92, in custom_object_hook\n    return AbstractFileSystem.from_dict(dct)\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 1567, in from_dict\n    return cls(\n        *json_decoder.unmake_serializable(dct.pop("args", ())),\n        **json_decoder.unmake_serializable(dct),\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 84, in __call__\n    obj = super().__call__(*args, **kwargs, **strip_tokenize_options)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/implementations/reference.py", line 776, in __init__\n    raise ValueError(\n    ...<2 lines>...\n    )\n'

2025-12-19 00:46:32,033 - distributed.worker - ERROR - Compute Failed
Key:       load_ref_ds-ec73ba56-acd6-4b6c-aeb0-34991cc2e8d8
State:     executing
Task:  <Task 'load_ref_ds-ec73ba56-acd6-4b6c-aeb0-34991cc2e8d8' load_ref_ds(...)>
Exception: 'ValueError("Reference-FS\'s target filesystem must have same value of asynchronous")'
Traceback: '  File "/tmp/ipykernel_4318/3963997076.py", line 10, in load_ref_ds\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/api.py", line 606, in open_dataset\n    backend_ds = backend.open_dataset(\n        filename_or_obj,\n    ...<2 lines>...\n        **kwargs,\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 1660, in open_dataset\n    store = ZarrStore.open_group(\n        filename_or_obj,\n    ...<10 lines>...\n        cache_members=cache_members,\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 714, in open_group\n    ) = _get_open_params(\n        ~~~~~~~~~~~~~~~~^\n        store=store,\n        ^^^^^^^^^^^^\n    ...<9 lines>...\n        zarr_format=zarr_format,\n        ^^^^^^^^^^^^^^^^^^^^^^^^\n    )\n    ^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 1902, in _get_open_params\n    zarr_group = zarr.open_group(store, **open_kwargs)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/synchronous.py", line 549, in open_group\n    sync(\n    ~~~~^\n        async_api.open_group(\n        ^^^^^^^^^^^^^^^^^^^^^\n    ...<12 lines>...\n        )\n        ^\n    )\n    ^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py", line 159, in sync\n    raise return_result\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py", line 119, in _runner\n    return await coro\n           ^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/asynchronous.py", line 860, in open_group\n    store_path = await make_store_path(store, mode=mode, storage_options=storage_options, path=path)\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py", line 422, in make_store_path\n    store = await make_store(store_like, mode=mode, storage_options=storage_options)\n            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py", line 354, in make_store\n    return FsspecStore.from_mapper(store_like, read_only=_read_only)\n           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py", line 197, in from_mapper\n    fs = _make_async(fs_map.fs)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py", line 57, in _make_async\n    return fsspec.AbstractFileSystem.from_json(json.dumps(fs_dict))\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 1491, in from_json\n    return json.loads(blob, cls=FilesystemJSONDecoder)\n           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/__init__.py", line 365, in loads\n    return cls(**kw).decode(s)\n           ~~~~~~~~~~~~~~~~^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py", line 345, in decode\n    obj, end = self.raw_decode(s, idx=_w(s, 0).end())\n               ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py", line 361, in raw_decode\n    obj, end = self.scan_once(s, idx)\n               ~~~~~~~~~~~~~~^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/json.py", line 92, in custom_object_hook\n    return AbstractFileSystem.from_dict(dct)\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 1567, in from_dict\n    return cls(\n        *json_decoder.unmake_serializable(dct.pop("args", ())),\n        **json_decoder.unmake_serializable(dct),\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 84, in __call__\n    obj = super().__call__(*args, **kwargs, **strip_tokenize_options)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/implementations/reference.py", line 776, in __init__\n    raise ValueError(\n    ...<2 lines>...\n    )\n'

2025-12-19 00:46:32,046 - distributed.worker - ERROR - Compute Failed
Key:       load_ref_ds-eb091374-89ab-402c-9864-3cf4826ad211
State:     executing
Task:  <Task 'load_ref_ds-eb091374-89ab-402c-9864-3cf4826ad211' load_ref_ds(...)>
Exception: 'ValueError("Reference-FS\'s target filesystem must have same value of asynchronous")'
Traceback: '  File "/tmp/ipykernel_4318/3963997076.py", line 10, in load_ref_ds\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/api.py", line 606, in open_dataset\n    backend_ds = backend.open_dataset(\n        filename_or_obj,\n    ...<2 lines>...\n        **kwargs,\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 1660, in open_dataset\n    store = ZarrStore.open_group(\n        filename_or_obj,\n    ...<10 lines>...\n        cache_members=cache_members,\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 714, in open_group\n    ) = _get_open_params(\n        ~~~~~~~~~~~~~~~~^\n        store=store,\n        ^^^^^^^^^^^^\n    ...<9 lines>...\n        zarr_format=zarr_format,\n        ^^^^^^^^^^^^^^^^^^^^^^^^\n    )\n    ^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py", line 1902, in _get_open_params\n    zarr_group = zarr.open_group(store, **open_kwargs)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/synchronous.py", line 549, in open_group\n    sync(\n    ~~~~^\n        async_api.open_group(\n        ^^^^^^^^^^^^^^^^^^^^^\n    ...<12 lines>...\n        )\n        ^\n    )\n    ^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py", line 159, in sync\n    raise return_result\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py", line 119, in _runner\n    return await coro\n           ^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/asynchronous.py", line 860, in open_group\n    store_path = await make_store_path(store, mode=mode, storage_options=storage_options, path=path)\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py", line 422, in make_store_path\n    store = await make_store(store_like, mode=mode, storage_options=storage_options)\n            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py", line 354, in make_store\n    return FsspecStore.from_mapper(store_like, read_only=_read_only)\n           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py", line 197, in from_mapper\n    fs = _make_async(fs_map.fs)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py", line 57, in _make_async\n    return fsspec.AbstractFileSystem.from_json(json.dumps(fs_dict))\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 1491, in from_json\n    return json.loads(blob, cls=FilesystemJSONDecoder)\n           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/__init__.py", line 365, in loads\n    return cls(**kw).decode(s)\n           ~~~~~~~~~~~~~~~~^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py", line 345, in decode\n    obj, end = self.raw_decode(s, idx=_w(s, 0).end())\n               ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py", line 361, in raw_decode\n    obj, end = self.scan_once(s, idx)\n               ~~~~~~~~~~~~~~^^^^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/json.py", line 92, in custom_object_hook\n    return AbstractFileSystem.from_dict(dct)\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 1567, in from_dict\n    return cls(\n        *json_decoder.unmake_serializable(dct.pop("args", ())),\n        **json_decoder.unmake_serializable(dct),\n    )\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py", line 84, in __call__\n    obj = super().__call__(*args, **kwargs, **strip_tokenize_options)\n  File "/home/runner/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/implementations/reference.py", line 776, in __init__\n    raise ValueError(\n    ...<2 lines>...\n    )\n'

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[5], line 1
----> 1 catalog_computed = dask.compute(tasks)

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/dask/base.py:686, in compute(traverse, optimize_graph, scheduler, get, *args, **kwargs)
    683     expr = expr.optimize()
    684     keys = list(flatten(expr.__dask_keys__()))
--> 686     results = schedule(expr, keys, **kwargs)
    688 return repack(results)

Cell In[3], line 10, in load_ref_ds()
      1 def load_ref_ds(url: str):
      2     fs = ReferenceFileSystem(
      3         url,
      4         remote_protocol="s3",
   (...)      8         lazy=True,
      9     )
---> 10     return xr.open_dataset(
     11         fs.get_mapper(),
     12         engine="zarr",
     13         backend_kwargs={"consolidated": False},
     14         chunks={"time": 300},
     15     )

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/api.py:606, in open_dataset()
    594 decoders = _resolve_decoders_kwargs(
    595     decode_cf,
    596     open_backend_dataset_parameters=backend.open_dataset_parameters,
   (...)    602     decode_coords=decode_coords,
    603 )
    605 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 606 backend_ds = backend.open_dataset(
    607     filename_or_obj,
    608     drop_variables=drop_variables,
    609     **decoders,
    610     **kwargs,
    611 )
    612 ds = _dataset_from_backend_dataset(
    613     backend_ds,
    614     filename_or_obj,
   (...)    625     **kwargs,
    626 )
    627 return ds

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py:1660, in open_dataset()
   1658 filename_or_obj = _normalize_path(filename_or_obj)
   1659 if not store:
-> 1660     store = ZarrStore.open_group(
   1661         filename_or_obj,
   1662         group=group,
   1663         mode=mode,
   1664         synchronizer=synchronizer,
   1665         consolidated=consolidated,
   1666         consolidate_on_close=False,
   1667         chunk_store=chunk_store,
   1668         storage_options=storage_options,
   1669         zarr_version=zarr_version,
   1670         use_zarr_fill_value_as_mask=None,
   1671         zarr_format=zarr_format,
   1672         cache_members=cache_members,
   1673     )
   1675 store_entrypoint = StoreBackendEntrypoint()
   1676 with close_on_error(store):

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py:714, in open_group()
    688 @classmethod
    689 def open_group(
    690     cls,
   (...)    707     cache_members: bool = True,
    708 ):
    709     (
    710         zarr_group,
    711         consolidate_on_close,
    712         close_store_on_close,
    713         use_zarr_fill_value_as_mask,
--> 714     ) = _get_open_params(
    715         store=store,
    716         mode=mode,
    717         synchronizer=synchronizer,
    718         group=group,
    719         consolidated=consolidated,
    720         consolidate_on_close=consolidate_on_close,
    721         chunk_store=chunk_store,
    722         storage_options=storage_options,
    723         zarr_version=zarr_version,
    724         use_zarr_fill_value_as_mask=use_zarr_fill_value_as_mask,
    725         zarr_format=zarr_format,
    726     )
    728     return cls(
    729         zarr_group,
    730         mode,
   (...)    739         cache_members=cache_members,
    740     )

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/xarray/backends/zarr.py:1902, in _get_open_params()
   1898     if _zarr_v3():
   1899         # we have determined that we don't want to use consolidated metadata
   1900         # so we set that to False to avoid trying to read it
   1901         open_kwargs["use_consolidated"] = False
-> 1902     zarr_group = zarr.open_group(store, **open_kwargs)
   1904 close_store_on_close = zarr_group.store is not store
   1906 # we use this to determine how to handle fill_value

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/synchronous.py:549, in open_group()
    478 def open_group(
    479     store: StoreLike | None = None,
    480     *,
   (...)    491     use_consolidated: bool | str | None = None,
    492 ) -> Group:
    493     """Open a group using file-mode-like semantics.
    494 
    495     Parameters
   (...)    546         The new group.
    547     """
    548     return Group(
--> 549         sync(
    550             async_api.open_group(
    551                 store=store,
    552                 mode=mode,
    553                 cache_attrs=cache_attrs,
    554                 synchronizer=synchronizer,
    555                 path=path,
    556                 chunk_store=chunk_store,
    557                 storage_options=storage_options,
    558                 zarr_version=zarr_version,
    559                 zarr_format=zarr_format,
    560                 meta_array=meta_array,
    561                 attributes=attributes,
    562                 use_consolidated=use_consolidated,
    563             )
    564         )
    565     )

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py:159, in sync()
    156 return_result = next(iter(finished)).result()
    158 if isinstance(return_result, BaseException):
--> 159     raise return_result
    160 else:
    161     return return_result

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/core/sync.py:119, in _runner()
    114 """
    115 Await a coroutine and return the result of running it. If awaiting the coroutine raises an
    116 exception, the exception will be returned.
    117 """
    118 try:
--> 119     return await coro
    120 except Exception as ex:
    121     return ex

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/api/asynchronous.py:860, in open_group()
    857 if chunk_store is not None:
    858     warnings.warn("chunk_store is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
--> 860 store_path = await make_store_path(store, mode=mode, storage_options=storage_options, path=path)
    861 if attributes is None:
    862     attributes = {}

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py:422, in make_store_path()
    417     raise ValueError(
    418         "'path' was provided but is not used for FSMap store_like objects. Specify the path when creating the FSMap instance instead."
    419     )
    421 else:
--> 422     store = await make_store(store_like, mode=mode, storage_options=storage_options)
    423     return await StorePath.open(store, path=path_normalized, mode=mode)

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_common.py:354, in make_store()
    351         return await make_store(Path(store_like), mode=mode, storage_options=storage_options)
    353 elif _has_fsspec and isinstance(store_like, FSMap):
--> 354     return FsspecStore.from_mapper(store_like, read_only=_read_only)
    356 else:
    357     raise TypeError(f"Unsupported type for store_like: '{type(store_like).__name__}'")

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py:197, in from_mapper()
    173 @classmethod
    174 def from_mapper(
    175     cls,
   (...)    178     allowed_exceptions: tuple[type[Exception], ...] = ALLOWED_EXCEPTIONS,
    179 ) -> FsspecStore:
    180     """
    181     Create a FsspecStore from a FSMap object.
    182 
   (...)    195     FsspecStore
    196     """
--> 197     fs = _make_async(fs_map.fs)
    198     return cls(
    199         fs=fs,
    200         path=fs_map.root,
    201         read_only=read_only,
    202         allowed_exceptions=allowed_exceptions,
    203     )

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/zarr/storage/_fsspec.py:57, in _make_async()
     55     fs_dict = json.loads(fs.to_json())
     56     fs_dict["asynchronous"] = True
---> 57     return fsspec.AbstractFileSystem.from_json(json.dumps(fs_dict))
     59 if fsspec_version < parse_version("2024.12.0"):
     60     raise ImportError(
     61         f"The filesystem '{fs}' is synchronous, and the required "
     62         "AsyncFileSystemWrapper is not available. Upgrade fsspec to version "
     63         "2024.12.0 or later to enable this functionality."
     64     )

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py:1491, in from_json()
   1470 """
   1471 Recreate a filesystem instance from JSON representation.
   1472 
   (...)   1487 at import time.
   1488 """
   1489 from .json import FilesystemJSONDecoder
-> 1491 return json.loads(blob, cls=FilesystemJSONDecoder)

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/__init__.py:365, in loads()
    363 if parse_constant is not None:
    364     kw['parse_constant'] = parse_constant
--> 365 return cls(**kw).decode(s)

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py:345, in decode()
    340 def decode(self, s, _w=WHITESPACE.match):
    341     """Return the Python representation of ``s`` (a ``str`` instance
    342     containing a JSON document).
    343 
    344     """
--> 345     obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    346     end = _w(s, end).end()
    347     if end != len(s):

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/json/decoder.py:361, in raw_decode()
    352 """Decode a JSON document from ``s`` (a ``str`` beginning with
    353 a JSON document) and return a 2-tuple of the Python
    354 representation and the index in ``s`` where the document ended.
   (...)    358 
    359 """
    360 try:
--> 361     obj, end = self.scan_once(s, idx)
    362 except StopIteration as err:
    363     raise JSONDecodeError("Expecting value", s, err.value) from None

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/json.py:92, in custom_object_hook()
     90 if "cls" in dct:
     91     if (obj_cls := self.try_resolve_fs_cls(dct)) is not None:
---> 92         return AbstractFileSystem.from_dict(dct)
     93     if (obj_cls := self.try_resolve_path_cls(dct)) is not None:
     94         return obj_cls(dct["str"])

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py:1567, in from_dict()
   1564 dct.pop("cls", None)
   1565 dct.pop("protocol", None)
-> 1567 return cls(
   1568     *json_decoder.unmake_serializable(dct.pop("args", ())),
   1569     **json_decoder.unmake_serializable(dct),
   1570 )

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/spec.py:84, in __call__()
     82     return cls._cache[token]
     83 else:
---> 84     obj = super().__call__(*args, **kwargs, **strip_tokenize_options)
     85     # Setting _fs_token here causes some static linters to complain.
     86     obj._fs_token_ = token

File ~/micromamba/envs/kerchunk-cookbook/lib/python3.14/site-packages/fsspec/implementations/reference.py:776, in __init__()
    774     self.fss[k] = AsyncFileSystemWrapper(f, asynchronous=self.asynchronous)
    775 elif self.asynchronous ^ f.asynchronous:
--> 776     raise ValueError(
    777         "Reference-FS's target filesystem must have same value "
    778         "of asynchronous"
    779     )

ValueError: Reference-FS's target filesystem must have same value of asynchronous

Build an Xarray-Datatree from the dictionary of datasets

dt = DataTree.from_dict(catalog_computed[0])

Accessing the Datatree

A Datatree is a collection of related Xarray datasets. We can access individual datasets using UNIX syntax. In the cell below, we will access a single dataset from the datatree.

dt["ACCESS-CM2/ssp585"]

# or

dt["ACCESS-CM2"]["ssp585"]
Convert a Datatree node to a Dataset
dt["ACCESS-CM2"]["ssp585"].to_dataset()

Operations across a Datatree

A Datatree contains a collection of datasets with related coordinates and variables. Using some in-built methods, we can analyze it as if it were a single dataset. Instead of looping through hundreds of Xarray datasets, we can apply operations across the Datatree. In the example below, we will lazily create a time-series.

ts = dt.mean(dim=["lat", "lon"])

Visualize a single dataset with HvPlot

display(  # noqa
    dt["ACCESS-CM2/ssp585"].to_dataset().pr.hvplot("lon", "lat", rasterize=True)
)

Shut down the Dask cluster

client.shutdown()