From ca2d986ae17b12c3f247ee80e331c814a6fff49c Mon Sep 17 00:00:00 2001 From: Vecko <36369090+VeckoTheGecko@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:26:12 +0200 Subject: [PATCH 1/2] Add data cataloging tutorial --- intermediate/cataloging.ipynb | 143 ++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 intermediate/cataloging.ipynb diff --git a/intermediate/cataloging.ipynb b/intermediate/cataloging.ipynb new file mode 100644 index 00000000..047b9f09 --- /dev/null +++ b/intermediate/cataloging.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "source": [ + "# Data cataloguing for Xarray\n", + "\n", + "**Goals:** At the end of this tutorial, you'll have an overview of what data cataloging is, why it is done, what tools are available. You'll also know how to open and browse some data catalogues.\n", + "\n", + "> A data catalog is a detailed inventory of data assets within an organization. It helps users easily discover, understand, manage, curate and access data. -[IBM](https://www.ibm.com/think/topics/data-catalog)\n", + "\n", + "Within an organisation, you may work with a lot of different datasets. As someone managing this data, you might want the following things:\n", + "\n", + "- **An organized, easily browsable collection**: By easing discovery and loading of your datasets you can reduce the friction for those analysing the data. Users can eaily get an overview of available datasets, discover datasets of interest, and load them for analysis.\n", + "- **Access control and logging**: You can limit who is able to access these datasets, and track when datasets are being accessed - keeping the data private, and providing metrics that can inform data management (e.g., by removing little-used datasets).\n", + "- **Combine individual data assets**: Combine individual data assets that are similar into a larger object (e.g., combining individual time snapshots into a larger data cube)\n", + "\n", + "There are a bunch of solutions available in Xarray that meet some of these needs - we'll broadly call these \"data catalogs\". These solutions differ in functionality, and the correct data cataloguing solution depends on your needs as an institute.\n", + "\n", + "If you feel there are data cataloguing tools missing from this page, please submit a PR.\n", + "\n", + "## intake v2\n", + "\n", + "Intake is a lightweight Python package which allows one to specify data catalogues (or a hierarchy of catalogues) via YAML files. These YAML files describe:\n", + "\n", + "- how to load the dataset. This is done via \"readers\", which support different file formats, and support lazily defining additional transformations to the dataset using Dask\n", + "- additional metadata for the dataset\n", + "\n", + "Uploading the catalogue file to a Git forge like GitHub allows for versioning of this file.\n", + "\n", + "This catalogue can be browsed in Python, or via third-party tools which parse the datalog, allowing the user to select and open a dataset. This tool has been adopted in the geosciences community for working with Xarray datasets, but is also flexible to work with other dataset types.\n", + "\n", + "There is no separate authentication layer in Intake, hence access control and logging depends entirely on the way the data is accessed. If the dataset is loaded from a file location on a mounted drive, then you need to have access to that mounted drive. If the dataset is located in an S3 bucket, you need to have the appropriate access credentials for the resource.\n", + "\n", + "Intake was originally developed within Anaconda by the team behind Dask.\n", + "\n", + "### Example using intake v2\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "526792bd", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "d6767fe7", + "metadata": {}, + "source": [ + "## STAC\n", + "\n", + "> SpatioTemporal Asset Catalogs\n", + "> The STAC specification is a common language to describe geospatial information, so it can more easily be worked with, indexed, and discovered.\n", + "> -stacspec.org\n", + "\n", + "Let's set the scene a bit: During sattelite data processing, many image files (predominantly TIFF) get generated. Each of these files can have different spatial and temporal extents, and over time these individual files can number in the millions, containing terrabytes of data in total. When doing analyses on these files, the first thing one needs to know is whether the file is even relevant to the analysis at hand (i.e., at least \"what is the spatial and temporal extent of the file?\"), however downloading the file just to check this metadata within is very wasteful. This is the context from which the STAC project was born.\n", + "\n", + "The goal of the STAC project is to make geospatial data more accesible by providing a specification to describe assets and their metadata. Adding this metadata alongside the asset (or lifting it out above the asset itself) allows:\n", + "\n", + "- The combining of assets into larger collections representing a larger dataset (e.g., a dataset with multiple time slices)\n", + "- For more efficient workflows, as the whole asset doesn't need to be downloaded to check the metadata.\n", + "\n", + "\n", + "Within the STAC project is:\n", + "\n", + "- **The STAC Specification**: A set of specifications describing (from most atomic to least) STAC Items, STAC Catalogs, and STAC collections. There is also a spec for the STAC API.\n", + "- **Tooling for working with STAC**: More on this just now\n", + "- **The community**\n", + "\n", + "There are various tools in the STAC ecosystem. [`odc-stac`](https://github.com/opendatacube/odc-stac), [`stacstac`](https://github.com/gjoseph92/stackstac) and [`xpystac`](https://github.com/stac-utils/xpystac) are all proojects that llow the opening of STAC items as Xarray datasets.\n", + "\n", + "### More resources\n", + "\n", + "- https://stacspec.org/en\n", + "- https://stacindex.org/\n", + "\n", + "### Example using odc-stac\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6a76a8e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "## Commercial offering - Arraylake\n", + "\n", + "There are also commercial offerings available that have data cataloguing functionality.\n", + "\n", + "Arraylake is Earthmover's managed cloud platform built on top of the open-source Icechunk data format\n", + "(where Icechunk is a project offering versioning of Zarr-like datasets).\n", + "\n", + "See [here](https://icechunk.io/en/latest/arraylake/) for a full comparison between Icechunk and Arraylake.\n", + "\n", + "A notable feature is that Arraylake integrates with [Earthmover's data marketplace](https://www.earthmover.io/marketplace/),\n", + "powering data discovery and allowing for the dissemination of datasets (or subsets of datasets) to other interested users.\n", + "\n", + "\n", + "\n", + "## More resources\n", + "\n", + "https://guide.cloudnativegeo.org/cookbooks/zarr-stac-report/data-consumers/" + ] + }, + { + "cell_type": "markdown", + "id": "06af9324", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From d9bedeac51f13b8da0c44d44878ecdc29795edf4 Mon Sep 17 00:00:00 2001 From: Vecko <36369090+VeckoTheGecko@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:23:51 +0200 Subject: [PATCH 2/2] Add examples --- intermediate/cataloging.ipynb | 93 ++++++++++++++++++++++++++++------- pixi.lock | 72 +++++++++++++++++++++++++++ pyproject.toml | 2 + 3 files changed, 150 insertions(+), 17 deletions(-) diff --git a/intermediate/cataloging.ipynb b/intermediate/cataloging.ipynb index 047b9f09..6d24b882 100644 --- a/intermediate/cataloging.ipynb +++ b/intermediate/cataloging.ipynb @@ -40,20 +40,86 @@ "\n", "Intake was originally developed within Anaconda by the team behind Dask.\n", "\n", - "### Example using intake v2\n" + "### Resources\n", + "\n", + "Project Pythia has a [cookbook on Intake](https://projectpythia.org/intake-cookbook/notebooks/creating-catalogs/).\n", + "\n", + "### Example code\n", + "\n", + "Here we work based off [an Intake tutorial on easy.gems!](https://easy.gems.dkrz.de/Processing/intake.html) from the DKRZ (German Climate Supercomputing Center). Note that the tutorial is based on v1 of Intake (which also uses `intake-xarray`).\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "526792bd", + "id": "1", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "# Browse an existing catalogue\n", + "\n", + "import intake\n", + "\n", + "cat = intake.open_catalog(\"https://data.nextgems-h2020.eu/online.yaml\")\n", + "# TIP: Its just a YAML file - open it in your browser and you'll see!\n", + "\n", + "# view the available subcatalogues or datasets\n", + "list(cat)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "# Access catalogue elements using `[\"attr\"]` or `.attr` notation\n", + "# NOTE: The `.attr` notation only works if the entry is a valid Python attribute name - which the entry might not be\n", + "\n", + "# Let's see what the `tutorial` item is...\n", + "cat[\"tutorial\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], + "source": [ + "# it's a subcatalogue!\n", + "\n", + "print(list(cat[\"tutorial\"]))\n", + "\n", + "# Let's look at an entry within...\n", + "cat['tutorial']['ICON.native.2d_PT6H_inst']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "# Let's open it as an xarray dataset\n", + "\n", + "ds = cat['tutorial']['ICON.native.2d_PT6H_inst'].to_dask()\n", + "ds" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "That's it for the example! Feel free to poke around further to see what other datasets are available in this catalogue, or to see which other catalogues are available online." + ] }, { "cell_type": "markdown", - "id": "d6767fe7", + "id": "6", "metadata": {}, "source": [ "## STAC\n", @@ -62,9 +128,9 @@ "> The STAC specification is a common language to describe geospatial information, so it can more easily be worked with, indexed, and discovered.\n", "> -stacspec.org\n", "\n", - "Let's set the scene a bit: During sattelite data processing, many image files (predominantly TIFF) get generated. Each of these files can have different spatial and temporal extents, and over time these individual files can number in the millions, containing terrabytes of data in total. When doing analyses on these files, the first thing one needs to know is whether the file is even relevant to the analysis at hand (i.e., at least \"what is the spatial and temporal extent of the file?\"), however downloading the file just to check this metadata within is very wasteful. This is the context from which the STAC project was born.\n", + "Let's set the scene a bit: During satellite data processing, many image files (predominantly TIFF) get generated. Each of these files can have different spatial and temporal extents, and over time these individual files can number in the millions, containing terrabytes of data in total. When doing analyses on these files, the first thing one needs to know is whether the file is even relevant to the analysis at hand (i.e., at least \"what is the spatial and temporal extent of the file?\"), however downloading the file just to check this metadata within is very wasteful. This is the context from which the STAC project was born.\n", "\n", - "The goal of the STAC project is to make geospatial data more accesible by providing a specification to describe assets and their metadata. Adding this metadata alongside the asset (or lifting it out above the asset itself) allows:\n", + "The goal of the STAC project is to make geospatial data more accessible by providing a specification to describe assets and their metadata. Adding this metadata alongside the asset (or lifting it out above the asset itself) allows:\n", "\n", "- The combining of assets into larger collections representing a larger dataset (e.g., a dataset with multiple time slices)\n", "- For more efficient workflows, as the whole asset doesn't need to be downloaded to check the metadata.\n", @@ -83,20 +149,13 @@ "- https://stacspec.org/en\n", "- https://stacindex.org/\n", "\n", - "### Example using odc-stac\n" + "### Example using odc-stac\n", + "\n" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6a76a8e", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", - "id": "2", + "id": "7", "metadata": {}, "source": [ "## Commercial offering - Arraylake\n", @@ -120,7 +179,7 @@ }, { "cell_type": "markdown", - "id": "06af9324", + "id": "8", "metadata": {}, "source": [] } diff --git a/pixi.lock b/pixi.lock index a5ab6fc6..8279ad15 100644 --- a/pixi.lock +++ b/pixi.lock @@ -271,6 +271,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-23.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/arrow-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.0-pyhd8ed1ab_1.conda @@ -310,6 +311,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.5.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docopt-ng-0.9.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/donfig-0.8.1.post1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.17.0-pyhd8ed1ab_0.conda @@ -347,6 +349,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.6.1-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-0.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-xarray-0.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh3099207_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.32.0-pyh907856f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.1.5-pyhd8ed1ab_1.conda @@ -525,6 +529,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-23.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/arrow-1.3.0-pyhd8ed1ab_1.conda @@ -565,6 +570,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.5.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docopt-ng-0.9.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/donfig-0.8.1.post1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.17.0-pyhd8ed1ab_0.conda @@ -602,6 +608,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.6.1-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-0.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-xarray-0.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh57ce528_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.32.0-pyh907856f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.1.5-pyhd8ed1ab_1.conda @@ -993,6 +1001,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-23.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/arrow-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.0-pyhd8ed1ab_1.conda @@ -1033,6 +1042,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.5.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docopt-ng-0.9.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/donfig-0.8.1.post1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.17.0-pyhd8ed1ab_0.conda @@ -1070,6 +1080,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.6.1-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-0.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-xarray-0.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh4bbf305_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-8.32.0-pyh9ab4c32_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.1.5-pyhd8ed1ab_1.conda @@ -4771,6 +4783,16 @@ packages: license_family: MIT size: 115305 timestamp: 1736174485476 + - conda: https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda + sha256: 5b9ef6d338525b332e17c3ed089ca2f53a5d74b7a7b432747d29c6466e39346d + md5: f4e90937bbfc3a4a92539545a37bb448 + depends: + - python >=3.9 + license: MIT + license_family: MIT + run_exports: {} + size: 14835 + timestamp: 1733754069532 - conda: https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.4-pyhd8ed1ab_1.conda sha256: 8f032b140ea4159806e4969a68b4a3c0a7cab1ad936eb958a2b5ffe5335e19bf md5: 54898d0f524c9dee622d44bbb081a8ab @@ -5241,6 +5263,16 @@ packages: license_family: MIT size: 22491 timestamp: 1734368817583 + - conda: https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.4-pyhd8ed1ab_1.conda + sha256: 80f579bfc71b3dab5bef74114b89e26c85cb0df8caf4c27ab5ffc16363d57ee7 + md5: 3366592d3c219f2731721f11bc93755c + depends: + - python >=3.9 + license: MIT + license_family: MIT + run_exports: {} + size: 11259 + timestamp: 1733327239578 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda sha256: cbde2c64ec317118fc06b223c5fd87c8a680255e7348dd60e7b292d2e103e701 md5: a16662747cdeb9abbac74d0057cc976e @@ -5665,6 +5697,46 @@ packages: license_family: APACHE size: 33781 timestamp: 1736252433366 + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-0.7.0-pyhd8ed1ab_0.conda + sha256: 8dba632e81a11347d959bb11367f6b0184e2dcc9aeab550de156beac5fa6091b + md5: 310f0fdaec6eecd9cc7833a788bafb1f + depends: + - appdirs + - cloudpickle >=0.2.2 + - dask >=1.0 + - entrypoints + - fsspec >=0.7.4 + - jinja2 + - msgpack-python + - numpy + - partd >=0.3.10 + - python >=3.6 + - pyyaml + - requests + - toolz >=0.8.2 + license: BSD-2-Clause + license_family: BSD + run_exports: {} + size: 193092 + timestamp: 1685391772164 + - conda: https://conda.anaconda.org/conda-forge/noarch/intake-xarray-0.7.0-pyhd8ed1ab_0.conda + sha256: ceb8cf5761c29467684cb860f1c73fce396ed412a3b54f69cdd314b96ef736b6 + md5: d6471673fac9fa8f13a2517315ffcf6b + depends: + - dask >=2.2 + - fsspec >=2022 + - intake >=0.6.6 + - msgpack-python + - netcdf4 + - python >=3.5 + - requests + - xarray >=2022 + - zarr + license: BSD-2-Clause + license_family: BSD + run_exports: {} + size: 27517 + timestamp: 1685414168477 - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh3099207_0.conda sha256: 33cfd339bb4efac56edf93474b37ddc049e08b1b4930cf036c893cc1f5a1f32a md5: b40131ab6a36ac2c09b7c57d4d3fbf99 diff --git a/pyproject.toml b/pyproject.toml index e45b1274..96ce393f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,3 +105,5 @@ flox = ">=0.10.4,<0.11" numbagg = ">=0.9.0,<0.10" rich = ">=14.0.0,<15" jupyterlab_vim = ">=4.1.4,<5" +intake = "<2" +intake-xarray = "<2"