Skip to content

Instantly share code, notes, and snippets.

@TomNicholas
Last active February 20, 2024 09:13
Show Gist options
  • Save TomNicholas/d9eb8ac81d3fd214a23b5e921dbd72b7 to your computer and use it in GitHub Desktop.
Save TomNicholas/d9eb8ac81d3fd214a23b5e921dbd72b7 to your computer and use it in GitHub Desktop.
Use xarray to concatenate kerchunked files
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "854d44c2-af48-4e9d-9916-24327edc5b67",
"metadata": {},
"source": [
"## Kerchunk concatenation using xarray instead of `MultiZarrToZarr`"
]
},
{
"cell_type": "markdown",
"id": "8a2a0cf4-6b73-4ccd-ad1e-7d23b3aa799c",
"metadata": {},
"source": [
"3rd Feb 2024"
]
},
{
"cell_type": "markdown",
"id": "b544d876-1444-4185-b5c4-3bc74487c889",
"metadata": {},
"source": [
"Tom Nicholas"
]
},
{
"cell_type": "markdown",
"id": "54ad6dc3-56e3-4e53-86e8-37a136916214",
"metadata": {},
"source": [
"This is an attempt to implement what I suggested in https://github.com/fsspec/kerchunk/issues/377#issuecomment-1922688615"
]
},
{
"cell_type": "markdown",
"id": "6edd0301-7ec1-48c0-b23b-94abfc747222",
"metadata": {},
"source": [
"We want to be able to do this:\n",
"\n",
"```python\n",
"ds = xr.open_mfdataset(\n",
" '/my/files*.nc',\n",
" engine='kerchunk', # kerchunk registers an xarray IO backend that returns zarr.Array objects\n",
" combine='nested', # 'by_coords' would require actually reading coordinate data\n",
" parallel=True, # would use dask.delayed to generate reference dicts for each file in parallel\n",
")\n",
"\n",
"ds # now wraps a bunch of zarr.Array / kerchunk.Array objects, no need for dask arrays\n",
"\n",
"ds.kerchunk.to_zarr(store='out.zarr') # kerchunk defines an xarray accessor that extracts the zarr arrays and serializes them\n",
"```\n",
"i.e. we can generate a set of kerchunk references for many different netCDF files, but only using xarray API."
]
},
{
"cell_type": "markdown",
"id": "bec2fdda-6747-41fc-a025-4019b6800436",
"metadata": {},
"source": [
"For this to work we will need:\n",
"1. A `KerchunkArray` class that\n",
" * Keeps track of the bytes ranges of chunks required for a single zarr array\n",
" * Understands concatenation\n",
" * Can be wrapped by xarray\n",
"2. A way to create the `KerchunkArray` objects from the netCDF files using `kerchunk.backends.SingleHdf5ToZarr`\n",
" * Ideally hidden within a new xarray backend `KerchunkBackendEntrypoint` so that the user can just call `xr.open_dataset/open_mfdataset`\n",
"3. A way to prevent xarray from trying to create `pandas.Index` objects for 1D coordinates by default (because we can't load any actual data values)\n",
"4. A function to take the resultant concatenated dataset and serialize the kerchunk references to json(/parquet)\n",
" * Which could be neatly called by a kerchunk xarray accessor.\n",
"5. (Stretch goal) Parallelism via dask/cubed wrapping"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "796b5958-0d53-44d7-b617-23d7e3ff029b",
"metadata": {},
"outputs": [],
"source": [
"import fsspec"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ecdfd2b9-449d-4c4e-9339-a56b9de13214",
"metadata": {},
"outputs": [],
"source": [
"from kerchunk.hdf import SingleHdf5ToZarr"
]
},
{
"cell_type": "markdown",
"id": "0e2cc481-1e7f-46bb-85a9-7c435f483af6",
"metadata": {},
"source": [
"## Create some data to zarr-ify"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5a47ef88-4aed-4404-a22b-5cad8d5f24e6",
"metadata": {},
"outputs": [],
"source": [
"import xarray as xr\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "53f85be9-7cd6-4659-90bb-c5670e860aa4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024.1.1.dev31+gdb9e448a.d20240203\n"
]
}
],
"source": [
"# actually using v2023.8.0, see section on \"Use xarray to wrap the KerchunkArrays\" for why\n",
"print(xr.__version__)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "17c1c964-87fc-4dfe-aca1-d917d8236dab",
"metadata": {},
"outputs": [],
"source": [
"ds = xr.tutorial.open_dataset('air_temperature')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "72694c97-ed06-4dbd-934c-f9a3b910f93d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (lat: 25, time: 2920, lon: 53)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 ...\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-428b2d95-0bba-4fd6-bf60-ea1d3c91c9c0' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-428b2d95-0bba-4fd6-bf60-ea1d3c91c9c0' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span class='xr-has-index'>lat</span>: 25</li><li><span class='xr-has-index'>time</span>: 2920</li><li><span class='xr-has-index'>lon</span>: 53</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-c80a2c66-14c8-427a-bdf9-8eab2c37f894' class='xr-section-summary-in' type='checkbox' checked><label for='section-c80a2c66-14c8-427a-bdf9-8eab2c37f894' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>75.0 72.5 70.0 ... 20.0 17.5 15.0</div><input id='attrs-169aaf49-6eb0-461e-96f6-c89902e1ef49' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-169aaf49-6eb0-461e-96f6-c89902e1ef49' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-2f438619-bcd9-49b8-9f7f-d5020d20a388' class='xr-var-data-in' type='checkbox'><label for='data-2f438619-bcd9-49b8-9f7f-d5020d20a388' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>latitude</dd><dt><span>long_name :</span></dt><dd>Latitude</dd><dt><span>units :</span></dt><dd>degrees_north</dd><dt><span>axis :</span></dt><dd>Y</dd></dl></div><div class='xr-var-data'><pre>array([75. , 72.5, 70. , 67.5, 65. , 62.5, 60. , 57.5, 55. , 52.5, 50. , 47.5,\n",
" 45. , 42.5, 40. , 37.5, 35. , 32.5, 30. , 27.5, 25. , 22.5, 20. , 17.5,\n",
" 15. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>200.0 202.5 205.0 ... 327.5 330.0</div><input id='attrs-3ca1c57d-dd2a-45b7-bd81-dd813668f5d3' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-3ca1c57d-dd2a-45b7-bd81-dd813668f5d3' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-879567a9-b4fa-44b4-b386-3917d0572b0b' class='xr-var-data-in' type='checkbox'><label for='data-879567a9-b4fa-44b4-b386-3917d0572b0b' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>longitude</dd><dt><span>long_name :</span></dt><dd>Longitude</dd><dt><span>units :</span></dt><dd>degrees_east</dd><dt><span>axis :</span></dt><dd>X</dd></dl></div><div class='xr-var-data'><pre>array([200. , 202.5, 205. , 207.5, 210. , 212.5, 215. , 217.5, 220. , 222.5,\n",
" 225. , 227.5, 230. , 232.5, 235. , 237.5, 240. , 242.5, 245. , 247.5,\n",
" 250. , 252.5, 255. , 257.5, 260. , 262.5, 265. , 267.5, 270. , 272.5,\n",
" 275. , 277.5, 280. , 282.5, 285. , 287.5, 290. , 292.5, 295. , 297.5,\n",
" 300. , 302.5, 305. , 307.5, 310. , 312.5, 315. , 317.5, 320. , 322.5,\n",
" 325. , 327.5, 330. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>datetime64[ns]</div><div class='xr-var-preview xr-preview'>2013-01-01 ... 2014-12-31T18:00:00</div><input id='attrs-ed0620be-c774-4d60-891c-9ba4e506717f' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-ed0620be-c774-4d60-891c-9ba4e506717f' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-e92f8036-58f7-4a17-9509-ca6c8cdd3d4f' class='xr-var-data-in' type='checkbox'><label for='data-e92f8036-58f7-4a17-9509-ca6c8cdd3d4f' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>time</dd><dt><span>long_name :</span></dt><dd>Time</dd></dl></div><div class='xr-var-data'><pre>array([&#x27;2013-01-01T00:00:00.000000000&#x27;, &#x27;2013-01-01T06:00:00.000000000&#x27;,\n",
" &#x27;2013-01-01T12:00:00.000000000&#x27;, ..., &#x27;2014-12-31T06:00:00.000000000&#x27;,\n",
" &#x27;2014-12-31T12:00:00.000000000&#x27;, &#x27;2014-12-31T18:00:00.000000000&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;)</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-a13d465a-a88e-45dd-8966-0792a7e86d65' class='xr-section-summary-in' type='checkbox' checked><label for='section-a13d465a-a88e-45dd-8966-0792a7e86d65' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>...</div><input id='attrs-95104484-abf9-40b9-be65-19c82bc755ef' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-95104484-abf9-40b9-be65-19c82bc755ef' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-16df7f70-55ed-4861-8d2b-457941049791' class='xr-var-data-in' type='checkbox'><label for='data-16df7f70-55ed-4861-8d2b-457941049791' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>actual_range :</span></dt><dd>[185.16 322.1 ]</dd></dl></div><div class='xr-var-data'><pre>[3869000 values with dtype=float32]</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-f0c5d9c4-a26e-46aa-95cd-bd39efdd0132' class='xr-section-summary-in' type='checkbox' ><label for='section-f0c5d9c4-a26e-46aa-95cd-bd39efdd0132' class='xr-section-summary' >Indexes: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-index-name'><div>lat</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-e982e60a-693d-4639-a317-114ee7b33218' class='xr-index-data-in' type='checkbox'/><label for='index-e982e60a-693d-4639-a317-114ee7b33218' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([75.0, 72.5, 70.0, 67.5, 65.0, 62.5, 60.0, 57.5, 55.0, 52.5, 50.0, 47.5,\n",
" 45.0, 42.5, 40.0, 37.5, 35.0, 32.5, 30.0, 27.5, 25.0, 22.5, 20.0, 17.5,\n",
" 15.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lat&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>lon</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-bddd2879-25c3-4420-a167-27c32d7baa4b' class='xr-index-data-in' type='checkbox'/><label for='index-bddd2879-25c3-4420-a167-27c32d7baa4b' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([200.0, 202.5, 205.0, 207.5, 210.0, 212.5, 215.0, 217.5, 220.0, 222.5,\n",
" 225.0, 227.5, 230.0, 232.5, 235.0, 237.5, 240.0, 242.5, 245.0, 247.5,\n",
" 250.0, 252.5, 255.0, 257.5, 260.0, 262.5, 265.0, 267.5, 270.0, 272.5,\n",
" 275.0, 277.5, 280.0, 282.5, 285.0, 287.5, 290.0, 292.5, 295.0, 297.5,\n",
" 300.0, 302.5, 305.0, 307.5, 310.0, 312.5, 315.0, 317.5, 320.0, 322.5,\n",
" 325.0, 327.5, 330.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lon&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>time</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-04e0d338-5fd7-493a-be0b-d5dabf0de950' class='xr-index-data-in' type='checkbox'/><label for='index-04e0d338-5fd7-493a-be0b-d5dabf0de950' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(DatetimeIndex([&#x27;2013-01-01 00:00:00&#x27;, &#x27;2013-01-01 06:00:00&#x27;,\n",
" &#x27;2013-01-01 12:00:00&#x27;, &#x27;2013-01-01 18:00:00&#x27;,\n",
" &#x27;2013-01-02 00:00:00&#x27;, &#x27;2013-01-02 06:00:00&#x27;,\n",
" &#x27;2013-01-02 12:00:00&#x27;, &#x27;2013-01-02 18:00:00&#x27;,\n",
" &#x27;2013-01-03 00:00:00&#x27;, &#x27;2013-01-03 06:00:00&#x27;,\n",
" ...\n",
" &#x27;2014-12-29 12:00:00&#x27;, &#x27;2014-12-29 18:00:00&#x27;,\n",
" &#x27;2014-12-30 00:00:00&#x27;, &#x27;2014-12-30 06:00:00&#x27;,\n",
" &#x27;2014-12-30 12:00:00&#x27;, &#x27;2014-12-30 18:00:00&#x27;,\n",
" &#x27;2014-12-31 00:00:00&#x27;, &#x27;2014-12-31 06:00:00&#x27;,\n",
" &#x27;2014-12-31 12:00:00&#x27;, &#x27;2014-12-31 18:00:00&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;, name=&#x27;time&#x27;, length=2920, freq=None))</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-6e3dfe44-26cc-46ba-91d0-841832353a20' class='xr-section-summary-in' type='checkbox' checked><label for='section-6e3dfe44-26cc-46ba-91d0-841832353a20' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (lat: 25, time: 2920, lon: 53)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 ...\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly..."
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "8b5afa11-71fa-4322-ae93-8a820387ab8c",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/tom/miniconda3/envs/dev3.11/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3548: SerializationWarning: saving variable air with floating point data as an integer dtype without any _FillValue to use for NaNs\n",
" exec(code_obj, self.user_global_ns, self.user_ns)\n"
]
}
],
"source": [
"ds.to_netcdf('air.nc')"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "9975cb67-3382-4974-8877-08fa8623eedc",
"metadata": {},
"outputs": [],
"source": [
"ds1 = ds.isel(time=slice(0, 1460))\n",
"ds2 = ds.isel(time=slice(1460, None))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "8036b68e-7b35-4e60-9378-d37439fbc88b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (lat: 25, time: 1460, lon: 53)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2013-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 ...\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-fbb27f2d-d2ba-4fba-af2e-146490535377' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-fbb27f2d-d2ba-4fba-af2e-146490535377' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span class='xr-has-index'>lat</span>: 25</li><li><span class='xr-has-index'>time</span>: 1460</li><li><span class='xr-has-index'>lon</span>: 53</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-ef5121e3-2bba-40b6-9ab8-87da8852e2dd' class='xr-section-summary-in' type='checkbox' checked><label for='section-ef5121e3-2bba-40b6-9ab8-87da8852e2dd' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>75.0 72.5 70.0 ... 20.0 17.5 15.0</div><input id='attrs-b86e1a35-8fcd-42cc-a948-73bb0a9d604d' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-b86e1a35-8fcd-42cc-a948-73bb0a9d604d' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-8386a04a-dc43-41e7-8797-9ec4540599aa' class='xr-var-data-in' type='checkbox'><label for='data-8386a04a-dc43-41e7-8797-9ec4540599aa' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>latitude</dd><dt><span>long_name :</span></dt><dd>Latitude</dd><dt><span>units :</span></dt><dd>degrees_north</dd><dt><span>axis :</span></dt><dd>Y</dd></dl></div><div class='xr-var-data'><pre>array([75. , 72.5, 70. , 67.5, 65. , 62.5, 60. , 57.5, 55. , 52.5, 50. , 47.5,\n",
" 45. , 42.5, 40. , 37.5, 35. , 32.5, 30. , 27.5, 25. , 22.5, 20. , 17.5,\n",
" 15. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>200.0 202.5 205.0 ... 327.5 330.0</div><input id='attrs-3dcef93f-be67-4fb5-9c12-2e632c7f6c1b' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-3dcef93f-be67-4fb5-9c12-2e632c7f6c1b' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-1b146952-f3dd-439b-98f5-f1319ae44050' class='xr-var-data-in' type='checkbox'><label for='data-1b146952-f3dd-439b-98f5-f1319ae44050' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>longitude</dd><dt><span>long_name :</span></dt><dd>Longitude</dd><dt><span>units :</span></dt><dd>degrees_east</dd><dt><span>axis :</span></dt><dd>X</dd></dl></div><div class='xr-var-data'><pre>array([200. , 202.5, 205. , 207.5, 210. , 212.5, 215. , 217.5, 220. , 222.5,\n",
" 225. , 227.5, 230. , 232.5, 235. , 237.5, 240. , 242.5, 245. , 247.5,\n",
" 250. , 252.5, 255. , 257.5, 260. , 262.5, 265. , 267.5, 270. , 272.5,\n",
" 275. , 277.5, 280. , 282.5, 285. , 287.5, 290. , 292.5, 295. , 297.5,\n",
" 300. , 302.5, 305. , 307.5, 310. , 312.5, 315. , 317.5, 320. , 322.5,\n",
" 325. , 327.5, 330. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>datetime64[ns]</div><div class='xr-var-preview xr-preview'>2013-01-01 ... 2013-12-31T18:00:00</div><input id='attrs-9a7ee0be-5e66-4ca6-99ba-21aeb5411546' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-9a7ee0be-5e66-4ca6-99ba-21aeb5411546' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-9372c23f-ef8a-4061-bd3d-c83b28ad6ea2' class='xr-var-data-in' type='checkbox'><label for='data-9372c23f-ef8a-4061-bd3d-c83b28ad6ea2' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>time</dd><dt><span>long_name :</span></dt><dd>Time</dd></dl></div><div class='xr-var-data'><pre>array([&#x27;2013-01-01T00:00:00.000000000&#x27;, &#x27;2013-01-01T06:00:00.000000000&#x27;,\n",
" &#x27;2013-01-01T12:00:00.000000000&#x27;, ..., &#x27;2013-12-31T06:00:00.000000000&#x27;,\n",
" &#x27;2013-12-31T12:00:00.000000000&#x27;, &#x27;2013-12-31T18:00:00.000000000&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;)</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-6a4a8865-5e1c-4edd-a7fd-6f72bbcb44eb' class='xr-section-summary-in' type='checkbox' checked><label for='section-6a4a8865-5e1c-4edd-a7fd-6f72bbcb44eb' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>...</div><input id='attrs-b09f7e53-1833-46ca-83d5-ea5a10aee761' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-b09f7e53-1833-46ca-83d5-ea5a10aee761' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-9eaa1766-4e7b-4046-862a-2233efe3193b' class='xr-var-data-in' type='checkbox'><label for='data-9eaa1766-4e7b-4046-862a-2233efe3193b' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>actual_range :</span></dt><dd>[185.16 322.1 ]</dd></dl></div><div class='xr-var-data'><pre>[1934500 values with dtype=float32]</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-6a645b9a-3969-47ac-bea3-04b8db20e75a' class='xr-section-summary-in' type='checkbox' ><label for='section-6a645b9a-3969-47ac-bea3-04b8db20e75a' class='xr-section-summary' >Indexes: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-index-name'><div>lat</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-2939a56d-5197-4fb4-8e2d-f0a09485c1a9' class='xr-index-data-in' type='checkbox'/><label for='index-2939a56d-5197-4fb4-8e2d-f0a09485c1a9' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([75.0, 72.5, 70.0, 67.5, 65.0, 62.5, 60.0, 57.5, 55.0, 52.5, 50.0, 47.5,\n",
" 45.0, 42.5, 40.0, 37.5, 35.0, 32.5, 30.0, 27.5, 25.0, 22.5, 20.0, 17.5,\n",
" 15.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lat&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>lon</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-9c8a33b9-8444-4430-a137-cf2e7a6a84a7' class='xr-index-data-in' type='checkbox'/><label for='index-9c8a33b9-8444-4430-a137-cf2e7a6a84a7' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([200.0, 202.5, 205.0, 207.5, 210.0, 212.5, 215.0, 217.5, 220.0, 222.5,\n",
" 225.0, 227.5, 230.0, 232.5, 235.0, 237.5, 240.0, 242.5, 245.0, 247.5,\n",
" 250.0, 252.5, 255.0, 257.5, 260.0, 262.5, 265.0, 267.5, 270.0, 272.5,\n",
" 275.0, 277.5, 280.0, 282.5, 285.0, 287.5, 290.0, 292.5, 295.0, 297.5,\n",
" 300.0, 302.5, 305.0, 307.5, 310.0, 312.5, 315.0, 317.5, 320.0, 322.5,\n",
" 325.0, 327.5, 330.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lon&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>time</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-8322ef34-4f5e-4e07-8de6-9a91b3eeaefd' class='xr-index-data-in' type='checkbox'/><label for='index-8322ef34-4f5e-4e07-8de6-9a91b3eeaefd' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(DatetimeIndex([&#x27;2013-01-01 00:00:00&#x27;, &#x27;2013-01-01 06:00:00&#x27;,\n",
" &#x27;2013-01-01 12:00:00&#x27;, &#x27;2013-01-01 18:00:00&#x27;,\n",
" &#x27;2013-01-02 00:00:00&#x27;, &#x27;2013-01-02 06:00:00&#x27;,\n",
" &#x27;2013-01-02 12:00:00&#x27;, &#x27;2013-01-02 18:00:00&#x27;,\n",
" &#x27;2013-01-03 00:00:00&#x27;, &#x27;2013-01-03 06:00:00&#x27;,\n",
" ...\n",
" &#x27;2013-12-29 12:00:00&#x27;, &#x27;2013-12-29 18:00:00&#x27;,\n",
" &#x27;2013-12-30 00:00:00&#x27;, &#x27;2013-12-30 06:00:00&#x27;,\n",
" &#x27;2013-12-30 12:00:00&#x27;, &#x27;2013-12-30 18:00:00&#x27;,\n",
" &#x27;2013-12-31 00:00:00&#x27;, &#x27;2013-12-31 06:00:00&#x27;,\n",
" &#x27;2013-12-31 12:00:00&#x27;, &#x27;2013-12-31 18:00:00&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;, name=&#x27;time&#x27;, length=1460, freq=None))</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-de2926e2-e53b-4e41-a9f1-4637a44c899d' class='xr-section-summary-in' type='checkbox' checked><label for='section-de2926e2-e53b-4e41-a9f1-4637a44c899d' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (lat: 25, time: 1460, lon: 53)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2013-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 ...\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly..."
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds1"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "72427d7f-0605-4c64-b22e-a7f1912468bd",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/tom/miniconda3/envs/dev3.11/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3548: SerializationWarning: saving variable air with floating point data as an integer dtype without any _FillValue to use for NaNs\n",
" exec(code_obj, self.user_global_ns, self.user_ns)\n",
"/Users/tom/miniconda3/envs/dev3.11/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3548: SerializationWarning: saving variable air with floating point data as an integer dtype without any _FillValue to use for NaNs\n",
" exec(code_obj, self.user_global_ns, self.user_ns)\n"
]
}
],
"source": [
"ds1.to_netcdf('air1.nc')\n",
"ds2.to_netcdf('air2.nc')"
]
},
{
"cell_type": "markdown",
"id": "911b14ca-0274-4dff-91aa-eba476455540",
"metadata": {},
"source": [
"Opening this dataset with xarray would look like this"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "b612b567-2cdc-4787-855e-1f5121f1069e",
"metadata": {},
"outputs": [],
"source": [
"full_ds = xr.open_mfdataset('air*.nc', combine='nested', compat='override', coords='minimal', data_vars='minimal')"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "00d8042b-c75f-41f6-a5ad-5b771503e3e7",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (lat: 25, lon: 53, time: 2920)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 dask.array&lt;chunksize=(2920, 25, 53), meta=np.ndarray&gt;\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-be0b7c1d-748a-4d77-bf62-4d92d76f5c0e' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-be0b7c1d-748a-4d77-bf62-4d92d76f5c0e' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span class='xr-has-index'>lat</span>: 25</li><li><span class='xr-has-index'>lon</span>: 53</li><li><span class='xr-has-index'>time</span>: 2920</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-72052378-2232-4978-8321-8cb3e876162c' class='xr-section-summary-in' type='checkbox' checked><label for='section-72052378-2232-4978-8321-8cb3e876162c' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>75.0 72.5 70.0 ... 20.0 17.5 15.0</div><input id='attrs-41591591-df36-4edd-a8b8-75f4aed75836' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-41591591-df36-4edd-a8b8-75f4aed75836' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-5e9fe6cf-8b96-441f-a6e0-f574435b93d5' class='xr-var-data-in' type='checkbox'><label for='data-5e9fe6cf-8b96-441f-a6e0-f574435b93d5' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>latitude</dd><dt><span>long_name :</span></dt><dd>Latitude</dd><dt><span>units :</span></dt><dd>degrees_north</dd><dt><span>axis :</span></dt><dd>Y</dd></dl></div><div class='xr-var-data'><pre>array([75. , 72.5, 70. , 67.5, 65. , 62.5, 60. , 57.5, 55. , 52.5, 50. , 47.5,\n",
" 45. , 42.5, 40. , 37.5, 35. , 32.5, 30. , 27.5, 25. , 22.5, 20. , 17.5,\n",
" 15. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>200.0 202.5 205.0 ... 327.5 330.0</div><input id='attrs-c338be2d-eedc-4de5-94d6-ae44752cd2a7' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-c338be2d-eedc-4de5-94d6-ae44752cd2a7' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-7e11c164-3c63-48f8-a33b-deecd034ab35' class='xr-var-data-in' type='checkbox'><label for='data-7e11c164-3c63-48f8-a33b-deecd034ab35' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>longitude</dd><dt><span>long_name :</span></dt><dd>Longitude</dd><dt><span>units :</span></dt><dd>degrees_east</dd><dt><span>axis :</span></dt><dd>X</dd></dl></div><div class='xr-var-data'><pre>array([200. , 202.5, 205. , 207.5, 210. , 212.5, 215. , 217.5, 220. , 222.5,\n",
" 225. , 227.5, 230. , 232.5, 235. , 237.5, 240. , 242.5, 245. , 247.5,\n",
" 250. , 252.5, 255. , 257.5, 260. , 262.5, 265. , 267.5, 270. , 272.5,\n",
" 275. , 277.5, 280. , 282.5, 285. , 287.5, 290. , 292.5, 295. , 297.5,\n",
" 300. , 302.5, 305. , 307.5, 310. , 312.5, 315. , 317.5, 320. , 322.5,\n",
" 325. , 327.5, 330. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>datetime64[ns]</div><div class='xr-var-preview xr-preview'>2013-01-01 ... 2014-12-31T18:00:00</div><input id='attrs-73f6a42f-c69b-4fb6-8917-1f197a5307c2' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-73f6a42f-c69b-4fb6-8917-1f197a5307c2' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-987ce377-3793-4fee-a0ec-9421f2aab10c' class='xr-var-data-in' type='checkbox'><label for='data-987ce377-3793-4fee-a0ec-9421f2aab10c' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>time</dd><dt><span>long_name :</span></dt><dd>Time</dd></dl></div><div class='xr-var-data'><pre>array([&#x27;2013-01-01T00:00:00.000000000&#x27;, &#x27;2013-01-01T06:00:00.000000000&#x27;,\n",
" &#x27;2013-01-01T12:00:00.000000000&#x27;, ..., &#x27;2014-12-31T06:00:00.000000000&#x27;,\n",
" &#x27;2014-12-31T12:00:00.000000000&#x27;, &#x27;2014-12-31T18:00:00.000000000&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;)</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-76e9d584-a453-4e1b-9cea-35881fd48cdb' class='xr-section-summary-in' type='checkbox' checked><label for='section-76e9d584-a453-4e1b-9cea-35881fd48cdb' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>dask.array&lt;chunksize=(2920, 25, 53), meta=np.ndarray&gt;</div><input id='attrs-300a136b-a7cc-474f-9239-3144ee832f40' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-300a136b-a7cc-474f-9239-3144ee832f40' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-c73ccbc8-0a2a-41f1-8cec-c2813b816fef' class='xr-var-data-in' type='checkbox'><label for='data-c73ccbc8-0a2a-41f1-8cec-c2813b816fef' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>actual_range :</span></dt><dd>[185.16 322.1 ]</dd></dl></div><div class='xr-var-data'><table>\n",
" <tr>\n",
" <td>\n",
" <table style=\"border-collapse: collapse;\">\n",
" <thead>\n",
" <tr>\n",
" <td> </td>\n",
" <th> Array </th>\n",
" <th> Chunk </th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" \n",
" <tr>\n",
" <th> Bytes </th>\n",
" <td> 14.76 MiB </td>\n",
" <td> 14.76 MiB </td>\n",
" </tr>\n",
" \n",
" <tr>\n",
" <th> Shape </th>\n",
" <td> (2920, 25, 53) </td>\n",
" <td> (2920, 25, 53) </td>\n",
" </tr>\n",
" <tr>\n",
" <th> Dask graph </th>\n",
" <td colspan=\"2\"> 1 chunks in 2 graph layers </td>\n",
" </tr>\n",
" <tr>\n",
" <th> Data type </th>\n",
" <td colspan=\"2\"> float32 numpy.ndarray </td>\n",
" </tr>\n",
" </tbody>\n",
" </table>\n",
" </td>\n",
" <td>\n",
" <svg width=\"159\" height=\"146\" style=\"stroke:rgb(0,0,0);stroke-width:1\" >\n",
"\n",
" <!-- Horizontal lines -->\n",
" <line x1=\"10\" y1=\"0\" x2=\"80\" y2=\"70\" style=\"stroke-width:2\" />\n",
" <line x1=\"10\" y1=\"25\" x2=\"80\" y2=\"96\" style=\"stroke-width:2\" />\n",
"\n",
" <!-- Vertical lines -->\n",
" <line x1=\"10\" y1=\"0\" x2=\"10\" y2=\"25\" style=\"stroke-width:2\" />\n",
" <line x1=\"80\" y1=\"70\" x2=\"80\" y2=\"96\" style=\"stroke-width:2\" />\n",
"\n",
" <!-- Colored Rectangle -->\n",
" <polygon points=\"10.0,0.0 80.58823529411765,70.58823529411765 80.58823529411765,96.00085180870013 10.0,25.41261651458249\" style=\"fill:#ECB172A0;stroke-width:0\"/>\n",
"\n",
" <!-- Horizontal lines -->\n",
" <line x1=\"10\" y1=\"0\" x2=\"38\" y2=\"0\" style=\"stroke-width:2\" />\n",
" <line x1=\"80\" y1=\"70\" x2=\"109\" y2=\"70\" style=\"stroke-width:2\" />\n",
"\n",
" <!-- Vertical lines -->\n",
" <line x1=\"10\" y1=\"0\" x2=\"80\" y2=\"70\" style=\"stroke-width:2\" />\n",
" <line x1=\"38\" y1=\"0\" x2=\"109\" y2=\"70\" style=\"stroke-width:2\" />\n",
"\n",
" <!-- Colored Rectangle -->\n",
" <polygon points=\"10.0,0.0 38.48973265594604,0.0 109.0779679500637,70.58823529411765 80.58823529411765,70.58823529411765\" style=\"fill:#ECB172A0;stroke-width:0\"/>\n",
"\n",
" <!-- Horizontal lines -->\n",
" <line x1=\"80\" y1=\"70\" x2=\"109\" y2=\"70\" style=\"stroke-width:2\" />\n",
" <line x1=\"80\" y1=\"96\" x2=\"109\" y2=\"96\" style=\"stroke-width:2\" />\n",
"\n",
" <!-- Vertical lines -->\n",
" <line x1=\"80\" y1=\"70\" x2=\"80\" y2=\"96\" style=\"stroke-width:2\" />\n",
" <line x1=\"109\" y1=\"70\" x2=\"109\" y2=\"96\" style=\"stroke-width:2\" />\n",
"\n",
" <!-- Colored Rectangle -->\n",
" <polygon points=\"80.58823529411765,70.58823529411765 109.0779679500637,70.58823529411765 109.0779679500637,96.00085180870013 80.58823529411765,96.00085180870013\" style=\"fill:#ECB172A0;stroke-width:0\"/>\n",
"\n",
" <!-- Text -->\n",
" <text x=\"94.833102\" y=\"116.000852\" font-size=\"1.0rem\" font-weight=\"100\" text-anchor=\"middle\" >53</text>\n",
" <text x=\"129.077968\" y=\"83.294544\" font-size=\"1.0rem\" font-weight=\"100\" text-anchor=\"middle\" transform=\"rotate(0,129.077968,83.294544)\">25</text>\n",
" <text x=\"35.294118\" y=\"80.706734\" font-size=\"1.0rem\" font-weight=\"100\" text-anchor=\"middle\" transform=\"rotate(45,35.294118,80.706734)\">2920</text>\n",
"</svg>\n",
" </td>\n",
" </tr>\n",
"</table></div></li></ul></div></li><li class='xr-section-item'><input id='section-9651fd8b-9ef5-439c-b54e-f22d9bf2a9ae' class='xr-section-summary-in' type='checkbox' ><label for='section-9651fd8b-9ef5-439c-b54e-f22d9bf2a9ae' class='xr-section-summary' >Indexes: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-index-name'><div>lat</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-682428da-c30b-49d7-9ce8-7d408c484254' class='xr-index-data-in' type='checkbox'/><label for='index-682428da-c30b-49d7-9ce8-7d408c484254' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([75.0, 72.5, 70.0, 67.5, 65.0, 62.5, 60.0, 57.5, 55.0, 52.5, 50.0, 47.5,\n",
" 45.0, 42.5, 40.0, 37.5, 35.0, 32.5, 30.0, 27.5, 25.0, 22.5, 20.0, 17.5,\n",
" 15.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lat&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>lon</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-425082c3-be60-4096-8229-95876b13d782' class='xr-index-data-in' type='checkbox'/><label for='index-425082c3-be60-4096-8229-95876b13d782' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([200.0, 202.5, 205.0, 207.5, 210.0, 212.5, 215.0, 217.5, 220.0, 222.5,\n",
" 225.0, 227.5, 230.0, 232.5, 235.0, 237.5, 240.0, 242.5, 245.0, 247.5,\n",
" 250.0, 252.5, 255.0, 257.5, 260.0, 262.5, 265.0, 267.5, 270.0, 272.5,\n",
" 275.0, 277.5, 280.0, 282.5, 285.0, 287.5, 290.0, 292.5, 295.0, 297.5,\n",
" 300.0, 302.5, 305.0, 307.5, 310.0, 312.5, 315.0, 317.5, 320.0, 322.5,\n",
" 325.0, 327.5, 330.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lon&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>time</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-80fb7a2c-eb6b-49b4-b182-898d450a80b6' class='xr-index-data-in' type='checkbox'/><label for='index-80fb7a2c-eb6b-49b4-b182-898d450a80b6' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(DatetimeIndex([&#x27;2013-01-01 00:00:00&#x27;, &#x27;2013-01-01 06:00:00&#x27;,\n",
" &#x27;2013-01-01 12:00:00&#x27;, &#x27;2013-01-01 18:00:00&#x27;,\n",
" &#x27;2013-01-02 00:00:00&#x27;, &#x27;2013-01-02 06:00:00&#x27;,\n",
" &#x27;2013-01-02 12:00:00&#x27;, &#x27;2013-01-02 18:00:00&#x27;,\n",
" &#x27;2013-01-03 00:00:00&#x27;, &#x27;2013-01-03 06:00:00&#x27;,\n",
" ...\n",
" &#x27;2014-12-29 12:00:00&#x27;, &#x27;2014-12-29 18:00:00&#x27;,\n",
" &#x27;2014-12-30 00:00:00&#x27;, &#x27;2014-12-30 06:00:00&#x27;,\n",
" &#x27;2014-12-30 12:00:00&#x27;, &#x27;2014-12-30 18:00:00&#x27;,\n",
" &#x27;2014-12-31 00:00:00&#x27;, &#x27;2014-12-31 06:00:00&#x27;,\n",
" &#x27;2014-12-31 12:00:00&#x27;, &#x27;2014-12-31 18:00:00&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;, name=&#x27;time&#x27;, length=2920, freq=&#x27;6H&#x27;))</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-86149ed8-dd87-41e4-87ca-fde3a4eaea2a' class='xr-section-summary-in' type='checkbox' checked><label for='section-86149ed8-dd87-41e4-87ca-fde3a4eaea2a' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (lat: 25, lon: 53, time: 2920)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 dask.array<chunksize=(2920, 25, 53), meta=np.ndarray>\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly..."
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_ds"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "470aea6f-a954-4567-b694-707b9533acde",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x16a75dbe0>]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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vbpe3erVq+Px48d6vh507t69qyvLVV973hA2bNiAgQMHokqVKti1axf+97//YdasWThx4gSjnFqtRteuXTFv3jz07dsX//33H+bNm4ejR48iJCQE6enpurIDBw7E4sWLMXDgQOzduxeffvopunfvzus3N2jQINjY2ODPP//E33//DRsbG8yZMwd9+vRBUFAQ/vrrL/z55594//49mjVrhoiICF3dkydPokmTJkhKSsKKFSuwd+9e1KxZE7169WL4nYSFhWH58uUYNWoUDh06hD///BOff/453rx5I/ue/fjjj4iOjsaaNWuwatUqREZGokuXLlCpVLoyc+fOxeDBg1G1alXs3r0bS5Yswe3bt9GoUSM9H6CsrCx88sknaNWqFfbu3YsZM2Zg2bJlaNKkCXx9fXXPNVuA+eOPP3D06FEsXrwYW7ZsQWpqKjp27JgnwsvWrVvRtWtXuLq6Ytu2bVi7di3evXuHkJAQvecfAD799FNUrFgRu3btwsSJE7F161aMHTtW9DpqtVrSWKXfezk8ffoU0dHROlOhENoxwVV23rx5sLW1haOjI5o2bYp9+/ZJuv7du3dRpUoVxuIJyB3rho7t9PR0tGnTBkeOHMHcuXOxc+dO+Pr6olevXnplpY6h27dvo23btkhLS8PGjRuxYsUKXL9+HbNnz+bsw/Xr1zFhwgTdmPv0008RHx+P+vXr4/Dhw5g6dSoOHjyIwYMHY+7cuRgyZIiurpz5pshDEQgirF+/ngJAPXv2jPO8Wq2msrOzqejoaAoAtXfvXt25X375RbAu37Wk/BPj+vXr1OjRo6k9e/ZQZ86codatW0dVqVKFUiqV1KFDh3Tlzp8/TwGgtm3bptfGnDlzKABUbGws73W2bNlCAaAuXryod+6bb76hbG1tBft58uRJCgB18uRJxnGVSkX5+flRtWvXptRqte54VFQUZWNjQwUGBuqObdu2jQJA7dq1i9HG1atXKQDUsmXLKIqiqHv37lEAqB9++IFRTlu/f//+umPa36Jfv36MsjExMZS1tTU1cuRIxvH3799Tvr6+VM+ePXXHKleuTNWqVYvKzs5mlO3cuTNVokQJSqVSURRFUcHBwVS3bt0E7pI42vvYsWNHxvG//vqL8fu8e/eOcnBw0CsXExND2dnZUX379tUd69+/PwWAWrdund71OnXqxPgNtDx79owC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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"full_ds['air'].isel(lat=10, lon=10).plot()"
]
},
{
"cell_type": "markdown",
"id": "a2dde1e2-9a20-44c1-ae91-b79bffa90801",
"metadata": {},
"source": [
"## Concatenation using `MultiZarrToZarr`"
]
},
{
"cell_type": "markdown",
"id": "c7bfe03e-3a05-4a30-adca-db9f92a27352",
"metadata": {},
"source": [
"Let's do the concatenation the standard way first"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "f1d5064f-fd58-4a04-8dc4-2306571e7b43",
"metadata": {},
"outputs": [],
"source": [
"from kerchunk.combine import MultiZarrToZarr"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "e9a6d03e-83d2-4e6d-84b1-d86c8988017e",
"metadata": {},
"outputs": [],
"source": [
"fs = fsspec.filesystem('')"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "a6138a5e-a351-47c3-a3a7-794507895469",
"metadata": {},
"outputs": [],
"source": [
"from typing import NewType, Literal, Any\n",
"\n",
"# Distinguishing these via type hints makes it a lot easier to keep track of what the opaque kerchunk \"reference dicts\" actually mean (idea from https://kobzol.github.io/rust/python/2023/05/20/writing-python-like-its-rust.html)\n",
"# What would be even better would be to instead pass around parts of Zarr Object Models (see https://github.com/zarr-developers/zarr-python/pull/1526)\n",
"StoreRefs = NewType(\"StoreRefs\", dict[Literal['version'] | Literal['refs'], int | dict]) # top-level dict with keys for 'version', 'refs'\n",
"ArrRefs = NewType(\"ArrRefs\", dict[Literal['.zattrs'] | Literal['.zarray'] | str, dict]) # lower-level dict containing just the information for one zarr array\n",
"ZAttrs = NewType(\"ZAttrs\", dict[str, Any]) # just the .zattrs (for one array or for the whole store/group)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "ca2e2d74-9811-44b2-bc72-ae35c46ea4b2",
"metadata": {},
"outputs": [],
"source": [
"def ref_dict_from_file(path: str) -> StoreRefs:\n",
" h5chunks = SingleHdf5ToZarr(path, inline_threshold=300)\n",
" d = h5chunks.translate()\n",
" return d"
]
},
{
"cell_type": "markdown",
"id": "2c1e685b-a628-44c5-be35-eada2c908669",
"metadata": {},
"source": [
"For context, kerchunk's \"reference dict\" for the original un-split file looks like this"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "5c22626b-9295-485e-a8b9-4de9e6ae67bf",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'version': 1,\n",
" 'refs': {'.zgroup': '{\"zarr_format\":2}',\n",
" '.zattrs': '{\"Conventions\":\"COARDS\",\"description\":\"Data is from NMC initialized reanalysis\\\\n(4x\\\\/day). These are the 0.9950 sigma level values.\",\"platform\":\"Model\",\"references\":\"http:\\\\/\\\\/www.esrl.noaa.gov\\\\/psd\\\\/data\\\\/gridded\\\\/data.ncep.reanalysis.html\",\"title\":\"4x daily NMC reanalysis (1948)\"}',\n",
" 'air/.zarray': '{\"chunks\":[2920,25,53],\"compressor\":null,\"dtype\":\"<i2\",\"fill_value\":null,\"filters\":null,\"order\":\"C\",\"shape\":[2920,25,53],\"zarr_format\":2}',\n",
" 'air/.zattrs': '{\"GRIB_id\":11,\"GRIB_name\":\"TMP\",\"_ARRAY_DIMENSIONS\":[\"time\",\"lat\",\"lon\"],\"actual_range\":[185.16000366210938,322.1000061035156],\"dataset\":\"NMC Reanalysis\",\"level_desc\":\"Surface\",\"long_name\":\"4xDaily Air temperature at sigma level 995\",\"parent_stat\":\"Other\",\"precision\":2,\"scale_factor\":0.01,\"statistic\":\"Individual Obs\",\"units\":\"degK\",\"var_desc\":\"Air temperature\"}',\n",
" 'air/0.0.0': ['air.nc', 15419, 7738000],\n",
" 'lat/.zarray': '{\"chunks\":[25],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[25],\"zarr_format\":2}',\n",
" 'lat/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lat\"],\"axis\":\"Y\",\"long_name\":\"Latitude\",\"standard_name\":\"latitude\",\"units\":\"degrees_north\"}',\n",
" 'lat/0': ['air.nc', 5179, 100],\n",
" 'lon/.zarray': '{\"chunks\":[53],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[53],\"zarr_format\":2}',\n",
" 'lon/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lon\"],\"axis\":\"X\",\"long_name\":\"Longitude\",\"standard_name\":\"longitude\",\"units\":\"degrees_east\"}',\n",
" 'lon/0': ['air.nc', 5279, 212],\n",
" 'time/.zarray': '{\"chunks\":[2920],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[2920],\"zarr_format\":2}',\n",
" 'time/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"time\"],\"calendar\":\"standard\",\"long_name\":\"Time\",\"standard_name\":\"time\",\"units\":\"hours since 1800-01-01\"}',\n",
" 'time/0': ['air.nc', 7757515, 11680]}}"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ref_dict_from_file('air.nc')"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "f7eeafbf-ec02-481f-85ab-3959b80ff208",
"metadata": {},
"outputs": [],
"source": [
"refs1 = ref_dict_from_file('air1.nc')\n",
"refs2 = ref_dict_from_file('air2.nc')"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "79961dc3-1f94-46ad-b6c6-2a4478cac97f",
"metadata": {},
"outputs": [],
"source": [
"mzz = MultiZarrToZarr(\n",
" [refs1, refs2],\n",
" concat_dims=['time'],\n",
" identical_dims = ['lat', 'lon']\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "6c630dd8-525c-4fe8-869b-9235a94b3f55",
"metadata": {},
"outputs": [],
"source": [
"full_refs = mzz.translate()"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "7f5db6c5-cef5-45c6-aff1-1c929f7d6f04",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'version': 1,\n",
" 'refs': {'.zgroup': '{\"zarr_format\":2}',\n",
" 'time/.zarray': '{\\n \"chunks\": [\\n 2920\\n ],\\n \"compressor\": {\\n \"id\": \"zstd\",\\n \"level\": 1\\n },\\n \"dtype\": \"<f4\",\\n \"fill_value\": \"NaN\",\\n \"filters\": null,\\n \"order\": \"C\",\\n \"shape\": [\\n 2920\\n ],\\n \"zarr_format\": 2\\n}',\n",
" 'time/0': 'base64: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',\n",
" 'time/.zattrs': '{\\n \"_ARRAY_DIMENSIONS\": [\\n \"time\"\\n ],\\n \"calendar\": \"standard\",\\n \"long_name\": \"Time\",\\n \"standard_name\": \"time\",\\n \"units\": \"hours since 1800-01-01\"\\n}',\n",
" '.zattrs': '{\"Conventions\":\"COARDS\",\"description\":\"Data is from NMC initialized reanalysis\\\\n(4x\\\\/day). These are the 0.9950 sigma level values.\",\"platform\":\"Model\",\"references\":\"http:\\\\/\\\\/www.esrl.noaa.gov\\\\/psd\\\\/data\\\\/gridded\\\\/data.ncep.reanalysis.html\",\"title\":\"4x daily NMC reanalysis (1948)\"}',\n",
" 'air/.zarray': '{\"chunks\":[1460,25,53],\"compressor\":null,\"dtype\":\"<i2\",\"fill_value\":null,\"filters\":null,\"order\":\"C\",\"shape\":[2920,25,53],\"zarr_format\":2}',\n",
" 'air/.zattrs': '{\"GRIB_id\":11,\"GRIB_name\":\"TMP\",\"_ARRAY_DIMENSIONS\":[\"time\",\"lat\",\"lon\"],\"actual_range\":[185.16000366210938,322.1000061035156],\"dataset\":\"NMC Reanalysis\",\"level_desc\":\"Surface\",\"long_name\":\"4xDaily Air temperature at sigma level 995\",\"parent_stat\":\"Other\",\"precision\":2,\"scale_factor\":0.01,\"statistic\":\"Individual Obs\",\"units\":\"degK\",\"var_desc\":\"Air temperature\"}',\n",
" 'air/0.0.0': ['air1.nc', 15419, 3869000],\n",
" 'lat/.zarray': '{\"chunks\":[25],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[25],\"zarr_format\":2}',\n",
" 'lat/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lat\"],\"axis\":\"Y\",\"long_name\":\"Latitude\",\"standard_name\":\"latitude\",\"units\":\"degrees_north\"}',\n",
" 'lat/0': ['air1.nc', 5179, 100],\n",
" 'lon/.zarray': '{\"chunks\":[53],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[53],\"zarr_format\":2}',\n",
" 'lon/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lon\"],\"axis\":\"X\",\"long_name\":\"Longitude\",\"standard_name\":\"longitude\",\"units\":\"degrees_east\"}',\n",
" 'lon/0': ['air1.nc', 5279, 212],\n",
" 'air/1.0.0': ['air2.nc', 15419, 3869000]}}"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_refs"
]
},
{
"cell_type": "markdown",
"id": "47aa49da-5afa-47d5-8636-797891b2f069",
"metadata": {},
"source": [
"Q: Why are the there 2 chunks for the 'air' variable (i.e. `'air/0.0.0'` and `'air/1.0.0'`), but only one chunk for the 'time' variable? (i.e. `'time/0'`)? Even though both variables should have been split in half along the time dimension..."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "51d4b4be-4dc5-4eb4-a311-254de2790755",
"metadata": {},
"outputs": [],
"source": [
"ds_mzz = xr.open_dataset(\n",
" \"reference://\", \n",
" engine='zarr',\n",
" backend_kwargs={\"consolidated\": False, \"storage_options\": {\"fo\": full_refs}}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "3abc0b8e-79e2-4a87-99fb-b6b86a86ab98",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 ...\n",
"Attributes:\n",
" Conventions: COARDS\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...\n",
" title: 4x daily NMC reanalysis (1948)</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-d8d40af0-b0bd-4124-b265-1a7a54ba2bb4' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-d8d40af0-b0bd-4124-b265-1a7a54ba2bb4' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span class='xr-has-index'>time</span>: 2920</li><li><span class='xr-has-index'>lat</span>: 25</li><li><span class='xr-has-index'>lon</span>: 53</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-9477e83f-f770-49c4-a069-a7564d252b18' class='xr-section-summary-in' type='checkbox' checked><label for='section-9477e83f-f770-49c4-a069-a7564d252b18' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>75.0 72.5 70.0 ... 20.0 17.5 15.0</div><input id='attrs-74578112-49b7-496a-a153-af7a98451111' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-74578112-49b7-496a-a153-af7a98451111' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-d340a5e8-a643-4d01-a9b9-ea6c29796a68' class='xr-var-data-in' type='checkbox'><label for='data-d340a5e8-a643-4d01-a9b9-ea6c29796a68' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>axis :</span></dt><dd>Y</dd><dt><span>long_name :</span></dt><dd>Latitude</dd><dt><span>standard_name :</span></dt><dd>latitude</dd><dt><span>units :</span></dt><dd>degrees_north</dd></dl></div><div class='xr-var-data'><pre>array([75. , 72.5, 70. , 67.5, 65. , 62.5, 60. , 57.5, 55. , 52.5, 50. , 47.5,\n",
" 45. , 42.5, 40. , 37.5, 35. , 32.5, 30. , 27.5, 25. , 22.5, 20. , 17.5,\n",
" 15. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>200.0 202.5 205.0 ... 327.5 330.0</div><input id='attrs-75aad2ca-e3a5-4c45-8e98-718ae6d2d7e4' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-75aad2ca-e3a5-4c45-8e98-718ae6d2d7e4' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-65def298-8dac-4e11-83bf-169fc7d2be10' class='xr-var-data-in' type='checkbox'><label for='data-65def298-8dac-4e11-83bf-169fc7d2be10' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>axis :</span></dt><dd>X</dd><dt><span>long_name :</span></dt><dd>Longitude</dd><dt><span>standard_name :</span></dt><dd>longitude</dd><dt><span>units :</span></dt><dd>degrees_east</dd></dl></div><div class='xr-var-data'><pre>array([200. , 202.5, 205. , 207.5, 210. , 212.5, 215. , 217.5, 220. , 222.5,\n",
" 225. , 227.5, 230. , 232.5, 235. , 237.5, 240. , 242.5, 245. , 247.5,\n",
" 250. , 252.5, 255. , 257.5, 260. , 262.5, 265. , 267.5, 270. , 272.5,\n",
" 275. , 277.5, 280. , 282.5, 285. , 287.5, 290. , 292.5, 295. , 297.5,\n",
" 300. , 302.5, 305. , 307.5, 310. , 312.5, 315. , 317.5, 320. , 322.5,\n",
" 325. , 327.5, 330. ], dtype=float32)</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span class='xr-has-index'>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>datetime64[ns]</div><div class='xr-var-preview xr-preview'>2013-01-01 ... 2014-12-31T18:00:00</div><input id='attrs-a5a4d5b8-fd87-4d9f-ac53-d9607d68f803' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-a5a4d5b8-fd87-4d9f-ac53-d9607d68f803' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-a3390981-256f-46f5-89b9-129d9812a58c' class='xr-var-data-in' type='checkbox'><label for='data-a3390981-256f-46f5-89b9-129d9812a58c' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>long_name :</span></dt><dd>Time</dd><dt><span>standard_name :</span></dt><dd>time</dd></dl></div><div class='xr-var-data'><pre>array([&#x27;2013-01-01T00:00:00.000000000&#x27;, &#x27;2013-01-01T06:00:00.000000000&#x27;,\n",
" &#x27;2013-01-01T12:00:00.000000000&#x27;, ..., &#x27;2014-12-31T06:00:00.000000000&#x27;,\n",
" &#x27;2014-12-31T12:00:00.000000000&#x27;, &#x27;2014-12-31T18:00:00.000000000&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;)</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-f3b0885d-dfad-46b2-84e6-54d0eaf52997' class='xr-section-summary-in' type='checkbox' checked><label for='section-f3b0885d-dfad-46b2-84e6-54d0eaf52997' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>...</div><input id='attrs-6dfd5970-a7b9-4471-9ee9-a1a01534f1af' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-6dfd5970-a7b9-4471-9ee9-a1a01534f1af' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-d7ec6b8b-bf8d-4622-94b5-73410f1bcf08' class='xr-var-data-in' type='checkbox'><label for='data-d7ec6b8b-bf8d-4622-94b5-73410f1bcf08' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>actual_range :</span></dt><dd>[185.16000366210938, 322.1000061035156]</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd></dl></div><div class='xr-var-data'><pre>[3869000 values with dtype=float32]</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-0126264a-5527-45a9-89fe-7d16a9b70c7a' class='xr-section-summary-in' type='checkbox' ><label for='section-0126264a-5527-45a9-89fe-7d16a9b70c7a' class='xr-section-summary' >Indexes: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-index-name'><div>lat</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-fdb53818-1951-4f16-b789-b7726be7c7a0' class='xr-index-data-in' type='checkbox'/><label for='index-fdb53818-1951-4f16-b789-b7726be7c7a0' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([75.0, 72.5, 70.0, 67.5, 65.0, 62.5, 60.0, 57.5, 55.0, 52.5, 50.0, 47.5,\n",
" 45.0, 42.5, 40.0, 37.5, 35.0, 32.5, 30.0, 27.5, 25.0, 22.5, 20.0, 17.5,\n",
" 15.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lat&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>lon</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-115dca7e-7b2e-40a6-a231-071717cee7f2' class='xr-index-data-in' type='checkbox'/><label for='index-115dca7e-7b2e-40a6-a231-071717cee7f2' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(Index([200.0, 202.5, 205.0, 207.5, 210.0, 212.5, 215.0, 217.5, 220.0, 222.5,\n",
" 225.0, 227.5, 230.0, 232.5, 235.0, 237.5, 240.0, 242.5, 245.0, 247.5,\n",
" 250.0, 252.5, 255.0, 257.5, 260.0, 262.5, 265.0, 267.5, 270.0, 272.5,\n",
" 275.0, 277.5, 280.0, 282.5, 285.0, 287.5, 290.0, 292.5, 295.0, 297.5,\n",
" 300.0, 302.5, 305.0, 307.5, 310.0, 312.5, 315.0, 317.5, 320.0, 322.5,\n",
" 325.0, 327.5, 330.0],\n",
" dtype=&#x27;float32&#x27;, name=&#x27;lon&#x27;))</pre></div></li><li class='xr-var-item'><div class='xr-index-name'><div>time</div></div><div class='xr-index-preview'>PandasIndex</div><div></div><input id='index-7e5f004c-154f-4db6-bfe8-a552ce61f1de' class='xr-index-data-in' type='checkbox'/><label for='index-7e5f004c-154f-4db6-bfe8-a552ce61f1de' title='Show/Hide index repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-index-data'><pre>PandasIndex(DatetimeIndex([&#x27;2013-01-01 00:00:00&#x27;, &#x27;2013-01-01 06:00:00&#x27;,\n",
" &#x27;2013-01-01 12:00:00&#x27;, &#x27;2013-01-01 18:00:00&#x27;,\n",
" &#x27;2013-01-02 00:00:00&#x27;, &#x27;2013-01-02 06:00:00&#x27;,\n",
" &#x27;2013-01-02 12:00:00&#x27;, &#x27;2013-01-02 18:00:00&#x27;,\n",
" &#x27;2013-01-03 00:00:00&#x27;, &#x27;2013-01-03 06:00:00&#x27;,\n",
" ...\n",
" &#x27;2014-12-29 12:00:00&#x27;, &#x27;2014-12-29 18:00:00&#x27;,\n",
" &#x27;2014-12-30 00:00:00&#x27;, &#x27;2014-12-30 06:00:00&#x27;,\n",
" &#x27;2014-12-30 12:00:00&#x27;, &#x27;2014-12-30 18:00:00&#x27;,\n",
" &#x27;2014-12-31 00:00:00&#x27;, &#x27;2014-12-31 06:00:00&#x27;,\n",
" &#x27;2014-12-31 12:00:00&#x27;, &#x27;2014-12-31 18:00:00&#x27;],\n",
" dtype=&#x27;datetime64[ns]&#x27;, name=&#x27;time&#x27;, length=2920, freq=None))</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-331153fc-667d-44d1-b43c-3ec583d870d6' class='xr-section-summary-in' type='checkbox' checked><label for='section-331153fc-667d-44d1-b43c-3ec583d870d6' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Coordinates:\n",
" * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
" * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
" * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
"Data variables:\n",
" air (time, lat, lon) float32 ...\n",
"Attributes:\n",
" Conventions: COARDS\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...\n",
" title: 4x daily NMC reanalysis (1948)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds_mzz"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "ce96b1a3-595a-4fae-8a18-c0a759dc75ba",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x16ab40b00>]"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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vbpe3erVq+Px48d6vh507t69qyvLVV973hA2bNiAgQMHokqVKti1axf+97//YdasWThx4gSjnFqtRteuXTFv3jz07dsX//33H+bNm4ejR48iJCQE6enpurIDBw7E4sWLMXDgQOzduxeffvopunfvzus3N2jQINjY2ODPP//E33//DRsbG8yZMwd9+vRBUFAQ/vrrL/z55594//49mjVrhoiICF3dkydPokmTJkhKSsKKFSuwd+9e1KxZE7169WL4nYSFhWH58uUYNWoUDh06hD///BOff/453rx5I/ue/fjjj4iOjsaaNWuwatUqREZGokuXLlCpVLoyc+fOxeDBg1G1alXs3r0bS5Yswe3bt9GoUSM9H6CsrCx88sknaNWqFfbu3YsZM2Zg2bJlaNKkCXx9fXXPNVuA+eOPP3D06FEsXrwYW7ZsQWpqKjp27JgnwsvWrVvRtWtXuLq6Ytu2bVi7di3evXuHkJAQvecfAD799FNUrFgRu3btwsSJE7F161aMHTtW9DpqtVrSWKXfezk8ffoU0dHROlOhENoxwVV23rx5sLW1haOjI5o2bYp9+/ZJuv7du3dRpUoVxuIJyB3rho7t9PR0tGnTBkeOHMHcuXOxc+dO+Pr6olevXnplpY6h27dvo23btkhLS8PGjRuxYsUKXL9+HbNnz+bsw/Xr1zFhwgTdmPv0008RHx+P+vXr4/Dhw5g6dSoOHjyIwYMHY+7cuRgyZIiurpz5pshDEQgirF+/ngJAPXv2jPO8Wq2msrOzqejoaAoAtXfvXt25X375RbAu37Wk/BPj+vXr1OjRo6k9e/ZQZ86codatW0dVqVKFUiqV1KFDh3Tlzp8/TwGgtm3bptfGnDlzKABUbGws73W2bNlCAaAuXryod+6bb76hbG1tBft58uRJCgB18uRJxnGVSkX5+flRtWvXptRqte54VFQUZWNjQwUGBuqObdu2jQJA7dq1i9HG1atXKQDUsmXLKIqiqHv37lEAqB9++IFRTlu/f//+umPa36Jfv36MsjExMZS1tTU1cuRIxvH3799Tvr6+VM+ePXXHKleuTNWqVYvKzs5mlO3cuTNVokQJSqVSURRFUcHBwVS3bt0E7pI42vvYsWNHxvG//vqL8fu8e/eOcnBw0CsXExND2dnZUX379tUd69+/PwWAWrdund71OnXqxPgNtDx79owC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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ds_mzz['air'].isel(lat=10, lon=10).plot()"
]
},
{
"cell_type": "markdown",
"id": "aa1be75a-6b6f-4247-b57f-6051d3b1f45e",
"metadata": {},
"source": [
"This is the result we want to replicate, but hopefully with the UI handled entirely by xarray, rather than the user having to call `MultiZarrToZarr`."
]
},
{
"cell_type": "markdown",
"id": "aa6a1395-aef9-486c-b5bb-ae77afe5f113",
"metadata": {},
"source": [
"## `KerchunkArray` class"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "1b3e95a3-4ce7-4984-b1c8-b3870aca33a4",
"metadata": {},
"outputs": [],
"source": [
"def find_var_names(ds_reference_dict: StoreRefs) -> list[str]:\n",
" \"\"\"Find the names of zarr variables in this store/group.\"\"\"\n",
" \n",
" refs = ds_reference_dict['refs']\n",
" found_var_names = [key.split('/')[0] for key in refs.keys() if '/' in key]\n",
" return found_var_names\n",
"\n",
"\n",
"def extract_array_refs(ds_reference_dict: StoreRefs, var_name: str) -> tuple[ArrRefs, ZAttrs]:\n",
" \"\"\"Extract only the part of the kerchunk reference dict that is relevant to this one zarr array\"\"\"\n",
" \n",
" found_var_names = find_var_names(ds_reference_dict)\n",
"\n",
" refs = ds_reference_dict['refs']\n",
" if var_name in found_var_names:\n",
" var_refs = {key.split('/')[1]: refs[key] for key in refs.keys() if var_name == key.split('/')[0]}\n",
"\n",
" zattrs = var_refs.pop('.zattrs') # we are going to store these separately later\n",
" \n",
" return var_refs, zattrs\n",
" else:\n",
" raise KeyError(f\"Could not find zarr array variable name {var_name}, only {found_var_names}\")"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "10643165-19a9-4e0d-a529-6fcfbfcbf22b",
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"\n",
"def fully_decode(d: ArrRefs) -> ArrRefs:\n",
" \"\"\"\n",
" Only have to do this because kerchunk.SingleHdf5ToZarr apparently doesn't bother converting .zarray and .zattrs contents to dicts, see https://github.com/fsspec/kerchunk/issues/415 .\n",
" \"\"\"\n",
" sanitized = d.copy()\n",
" for k, v in d.items():\n",
" \n",
" if k.startswith('.'):\n",
" # ensure contents of .zattrs and .zarray are python dictionaries\n",
" sanitized[k] = json.loads(v)\n",
" # TODO should we also convert the byte range values stored under chunk keys to python lists? e.g. 'time/0': ['air.nc', 7757515, 11680]\n",
" \n",
" return sanitized"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "d45ec421-4193-429b-a350-6d1b5252d7ed",
"metadata": {},
"outputs": [],
"source": [
"from typing import Self\n",
"\n",
"\n",
"class KerchunkArray:\n",
" \"\"\"\n",
" Virtual representation of kerchunk reference dict for a single zarr array.\n",
"\n",
" Implements subset of array API standard such that it can be wrapped by xarray.\n",
" Doesn't try to store zarr array name, attrs or ARRAY_DIMENSIONS, as instead we'll store those on a wrapping xarray object.\n",
"\n",
" This could be reimplemented using either:\n",
" - the kerchunk.VirtualZarrStore idea in https://github.com/fsspec/kerchunk/issues/375, \n",
" - the Zarr \"Chunk Manifest\" idea in https://github.com/fsspec/kerchunk/issues/377#issuecomment-1765416207\n",
" \"\"\"\n",
"\n",
" _arr_refs: ArrRefs\n",
" \n",
" def __init__(self, arr_refs: ArrRefs) -> None:\n",
" \"\"\"Construct from an existing reference dict\"\"\"\n",
" self._arr_refs = arr_refs\n",
"\n",
" @property\n",
" def arr_refs(self) -> ArrRefs:\n",
" \"\"\"Stores the section of zarr json corresponding to just one array\"\"\"\n",
" return self._arr_refs\n",
" \n",
" @property\n",
" def chunks(self) -> tuple[int]:\n",
" # TODO do we even need this? The way I implemented concat below I don't think we really do...\n",
" return tuple(self.arr_refs['.zarray']['chunks'])\n",
"\n",
" @property\n",
" def dtype(self) -> np.dtype:\n",
" dtype_str = self.arr_refs['.zarray']['dtype']\n",
" return np.dtype(dtype_str)\n",
" \n",
" @property\n",
" def shape(self) -> tuple[int, ...]:\n",
" # TODO should this point to the chunks attribute of .zarray instead?\n",
" return tuple(int(l) for l in list(self.arr_refs['.zarray']['shape']))\n",
"\n",
" @property\n",
" def ndim(self) -> int:\n",
" return len(self.shape)\n",
"\n",
" @property\n",
" def size(self) -> int:\n",
" return np.prod(self.shape)\n",
"\n",
" @property\n",
" def T(self) -> Self:\n",
" raise NotImplementedError()\n",
"\n",
" def __repr__(self) -> str:\n",
" return f\"KerchunkArray<shape={self.shape}, dtype={self.dtype}, chunks={self.chunks}>\"\n",
"\n",
" def _repr_inline_(self, max_width):\n",
" \"\"\"\n",
" Format to a single line with at most max_width characters. Used by xarray.\n",
" \"\"\"\n",
" return self.__repr__()\n",
"\n",
" def __getitem__(self, key, /) -> Self:\n",
" \"\"\"\n",
" Only supports extremely limited indexing.\n",
" \n",
" I only added this method because xarray will apparently attempt to index into its lazy indexing classes even if the operation would be a no-op anyway.\n",
" \"\"\"\n",
" from xarray.core.indexing import BasicIndexer\n",
" \n",
" if isinstance(key, BasicIndexer) and key.tuple == ((slice(None),) * self.ndim):\n",
" # no-op\n",
" return self\n",
" else:\n",
" # TODO if the slicing happened to align perfectly with on-disk chunks then we _could_ support that too\n",
" raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "a09bbbb8-086f-450d-85b0-8f2475d58425",
"metadata": {},
"source": [
"## Use `KerchunkArray` to perform concatenation"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "34f11946-36af-4c08-8f49-69729f16b5f0",
"metadata": {},
"outputs": [],
"source": [
"d1 = ref_dict_from_file('air1.nc')"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "c7c69ec5-a7e6-4467-a0dc-7a1d9a8ce0fe",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'version': 1,\n",
" 'refs': {'.zgroup': '{\"zarr_format\":2}',\n",
" '.zattrs': '{\"Conventions\":\"COARDS\",\"description\":\"Data is from NMC initialized reanalysis\\\\n(4x\\\\/day). These are the 0.9950 sigma level values.\",\"platform\":\"Model\",\"references\":\"http:\\\\/\\\\/www.esrl.noaa.gov\\\\/psd\\\\/data\\\\/gridded\\\\/data.ncep.reanalysis.html\",\"title\":\"4x daily NMC reanalysis (1948)\"}',\n",
" 'air/.zarray': '{\"chunks\":[1460,25,53],\"compressor\":null,\"dtype\":\"<i2\",\"fill_value\":null,\"filters\":null,\"order\":\"C\",\"shape\":[1460,25,53],\"zarr_format\":2}',\n",
" 'air/.zattrs': '{\"GRIB_id\":11,\"GRIB_name\":\"TMP\",\"_ARRAY_DIMENSIONS\":[\"time\",\"lat\",\"lon\"],\"actual_range\":[185.16000366210938,322.1000061035156],\"dataset\":\"NMC Reanalysis\",\"level_desc\":\"Surface\",\"long_name\":\"4xDaily Air temperature at sigma level 995\",\"parent_stat\":\"Other\",\"precision\":2,\"scale_factor\":0.01,\"statistic\":\"Individual Obs\",\"units\":\"degK\",\"var_desc\":\"Air temperature\"}',\n",
" 'air/0.0.0': ['air1.nc', 15419, 3869000],\n",
" 'lat/.zarray': '{\"chunks\":[25],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[25],\"zarr_format\":2}',\n",
" 'lat/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lat\"],\"axis\":\"Y\",\"long_name\":\"Latitude\",\"standard_name\":\"latitude\",\"units\":\"degrees_north\"}',\n",
" 'lat/0': ['air1.nc', 5179, 100],\n",
" 'lon/.zarray': '{\"chunks\":[53],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[53],\"zarr_format\":2}',\n",
" 'lon/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lon\"],\"axis\":\"X\",\"long_name\":\"Longitude\",\"standard_name\":\"longitude\",\"units\":\"degrees_east\"}',\n",
" 'lon/0': ['air1.nc', 5279, 212],\n",
" 'time/.zarray': '{\"chunks\":[1460],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[1460],\"zarr_format\":2}',\n",
" 'time/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"time\"],\"calendar\":\"standard\",\"long_name\":\"Time\",\"standard_name\":\"time\",\"units\":\"hours since 1800-01-01\"}',\n",
" 'time/0': ['air1.nc', 3888515, 5840]}}"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d1"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "cfb620ca-f4a3-4e42-b49e-0e925a904ff1",
"metadata": {},
"outputs": [],
"source": [
"arr_refs1 = fully_decode(extract_array_refs(d1, 'air')[0])"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "11878c47-9aeb-47a8-b2fc-b719fdd88584",
"metadata": {},
"outputs": [],
"source": [
"karr1 = KerchunkArray(arr_refs1)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "1dda943c-d276-4f1f-a601-f4f60b49304a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [1460, 25, 53],\n",
" 'zarr_format': 2},\n",
" '0.0.0': ['air1.nc', 15419, 3869000]}"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr1.arr_refs"
]
},
{
"cell_type": "markdown",
"id": "369d4447-7328-4cdc-b4d7-2a3146f73089",
"metadata": {},
"source": [
"Notice that the KerchunkArray does not know the name of the zarr array it represents."
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "711ab153-5dc4-4db2-9d8f-5fdd0f8e8b83",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(1460, 25, 53)"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr1.shape"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "162b253b-6c9e-41d8-99b1-56c5b8458be0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('int16')"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr1.dtype"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "35eabb38-7f2c-46b7-9792-b073943405e9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr1.ndim"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "47c186db-a259-4b98-82f6-643a2fe5db4d",
"metadata": {},
"outputs": [],
"source": [
"d2 = ref_dict_from_file('air2.nc')\n",
"arr_refs2 = fully_decode(extract_array_refs(d2, 'air')[0])\n",
"karr2 = KerchunkArray(arr_refs2)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "ed91d501-26ef-4d58-9511-9851fe684555",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [1460, 25, 53],\n",
" 'zarr_format': 2},\n",
" '0.0.0': ['air2.nc', 15419, 3869000]}"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr2.arr_refs"
]
},
{
"cell_type": "markdown",
"id": "cf3ddcbf-3c1f-4b1d-8a18-6aa87cc42f08",
"metadata": {},
"source": [
"Now let's check what the result of merging these dicts is supposed to be, by comparing against what `MultiZarrToZarr` produced"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "43446d02-5170-494c-b4a8-46bc7cd3ceb7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'{\"chunks\":[1460,25,53],\"compressor\":null,\"dtype\":\"<i2\",\"fill_value\":null,\"filters\":null,\"order\":\"C\",\"shape\":[2920,25,53],\"zarr_format\":2}'"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_refs['refs']['air/.zarray']"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "9b77d28f-da6a-4e1f-80cd-1c71b3211f46",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'{\"GRIB_id\":11,\"GRIB_name\":\"TMP\",\"_ARRAY_DIMENSIONS\":[\"time\",\"lat\",\"lon\"],\"actual_range\":[185.16000366210938,322.1000061035156],\"dataset\":\"NMC Reanalysis\",\"level_desc\":\"Surface\",\"long_name\":\"4xDaily Air temperature at sigma level 995\",\"parent_stat\":\"Other\",\"precision\":2,\"scale_factor\":0.01,\"statistic\":\"Individual Obs\",\"units\":\"degK\",\"var_desc\":\"Air temperature\"}'"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_refs['refs']['air/.zattrs']"
]
},
{
"cell_type": "markdown",
"id": "74a09231-2c13-4e0b-9381-c2193750cffa",
"metadata": {},
"source": [
"(Again it's annoying that kerchunk leaves these entries as a complicated string instead of converting each to a dict - see https://github.com/fsspec/kerchunk/issues/415)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "443ff857-592d-4dad-95b9-10fbc8bed69d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['air1.nc', 15419, 3869000]"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_refs['refs']['air/0.0.0']"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "733aef7a-af4c-40fd-a8be-c5ad634a1117",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['air2.nc', 15419, 3869000]"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_refs['refs']['air/1.0.0']"
]
},
{
"cell_type": "markdown",
"id": "483ef306-295c-482f-a1ca-f7ebf57e26f4",
"metadata": {},
"source": [
"My understanding is that these last two represent byte ranges within specific files stores on the supplied fsspec filesystem."
]
},
{
"cell_type": "markdown",
"id": "0f1bec5a-ec97-4dfe-a7f9-65e9abe2428f",
"metadata": {},
"source": [
"Now we know how to define an array-level concatenation function for `KerchunkArray` objects.\n",
"\n",
"(We won't worry about the `.zattrs` for now)"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "985486ca-43fd-4323-87eb-667725c827d5",
"metadata": {},
"outputs": [],
"source": [
"def concat(arrays: tuple[KerchunkArray, ...] | list[KerchunkArray], /, *, axis: int | None = 0) -> KerchunkArray:\n",
" \"\"\"\n",
" Concatenate KerchunkArrays by merging their reference dicts.\n",
"\n",
" The signature of this function is array API compliant, so it can be called by `xarray.concat`.\n",
" \"\"\"\n",
" if axis is None:\n",
" raise NotImplementedError(\n",
" \"If axis=None the array API requires flattening, which is a reshape, which I don't think we can implement on a KerchunkArray.\"\n",
" )\n",
"\n",
" concatenated_array_refs = _concat_arr_reference_dicts(\n",
" [arr.arr_refs for arr in arrays],\n",
" axis=axis,\n",
" )\n",
"\n",
" return KerchunkArray(concatenated_array_refs)\n",
"\n",
"\n",
"def _concat_arr_reference_dicts(arr_refs_list: list[ArrRefs], axis: int) -> ArrRefs:\n",
" \"\"\"\n",
" Internals of this are adapted from the internals of `kerchunk.combine.concatenate_arrays`.\n",
" We couldn't simply use that function directly because it acts on store/group-level reference dicts, not array-level reference dicts.\n",
" \n",
" This is the minimum I needed to get this one example to work - expect it to break on practically anything else!\n",
" \"\"\"\n",
" key_seperator = '.'\n",
" \n",
" arr_refs_out = {}\n",
"\n",
" def _replace(l: list, i: int, v) -> list:\n",
" l = l.copy()\n",
" l[i] = v\n",
" return l\n",
"\n",
" n_files = len(arr_refs_list)\n",
"\n",
" chunks_offset = 0\n",
" for i, arr_refs in enumerate(arr_refs_list):\n",
" zarray = arr_refs['.zarray']\n",
" shape = zarray[\"shape\"]\n",
" chunks = zarray[\"chunks\"]\n",
" n_chunks, rem = divmod(shape[axis], chunks[axis])\n",
" n_chunks += rem > 0\n",
"\n",
" if i == 0:\n",
" base_shape = _replace(shape, axis, None)\n",
" base_chunks = chunks\n",
" # result_* were previously modified in-place \n",
" # but using .copy() here fixes some kind of scope/in-place bug where \n",
" # chunks_offset accumulates each time this entire function is run, \n",
" # when it should be reset to zero\n",
" result_zarray = zarray.copy()\n",
" result_shape = shape.copy()\n",
" else:\n",
" result_shape[axis] += shape[axis]\n",
" \n",
" # Safety checks\n",
" check_arrays = False\n",
" if check_arrays:\n",
" # TODO there's a subtlety here - kerchunk optionally checks that read chunk shapes make sense during the concatenation (if the check_arrays kwarg is True)\n",
" # We can't pass arbitrary kwargs down to array_api.concat, so xarray should probably instead do this when the xr.Variable object is created?\n",
" raise NotImplementedError()\n",
" \n",
" # Referencing the offset chunks\n",
" for key in arr_refs.keys():\n",
" if key.startswith(\".z\"):\n",
" # only look at keys for chunks, ignore .zattrs etc.\n",
" continue\n",
" parts = key.split(key_seperator)\n",
" parts[axis] = str(int(parts[axis]) + chunks_offset)\n",
" key2 = key_seperator.join(parts)\n",
" arr_refs_out[key2] = arr_refs[key]\n",
"\n",
" chunks_offset += n_chunks\n",
"\n",
" result_zarray['shape'] = result_shape # needed this to make up for not altering dicts in-place\n",
" arr_refs_out[\".zarray\"] = result_zarray\n",
"\n",
" return arr_refs_out"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "2206740b-bd43-43f5-a554-9a8f3ba02dc9",
"metadata": {},
"outputs": [],
"source": [
"karr_full = concat([karr1, karr2], axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "5afcd1c4-aca8-47d1-a320-734964a7b536",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)>"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr_full"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "02bcb361-8bb3-488a-8517-71e071043291",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'0.0.0': ['air1.nc', 15419, 3869000],\n",
" '1.0.0': ['air2.nc', 15419, 3869000],\n",
" '.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [2920, 25, 53],\n",
" 'zarr_format': 2}}"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr_full.arr_refs"
]
},
{
"cell_type": "markdown",
"id": "5b60ab00-b172-4ac2-b70b-33e427f579eb",
"metadata": {},
"source": [
"That worked! At least for that one variable."
]
},
{
"cell_type": "markdown",
"id": "dab3375a-ecf6-48b1-af14-9199b976e8d1",
"metadata": {},
"source": [
"Let's make an array_api namespace for `KerchunkArray` and add concat to it:"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "cdd2a1f5-92fc-4797-ad97-cf3dd0ca75e9",
"metadata": {},
"outputs": [],
"source": [
"class ArrayAPI:\n",
" @staticmethod\n",
" def concat(arrays: list[KerchunkArray], /, *, axis=0) -> KerchunkArray:\n",
" return concat(arrays, axis=axis)\n",
"\n",
" @staticmethod\n",
" def astype(x: KerchunkArray, dtype: np.dtype, /, *, copy: bool = True) -> KerchunkArray:\n",
" \"\"\"Needed because xarray will call this even when it's a no-op\"\"\"\n",
" if dtype != x.dtype:\n",
" raise NotImplementedError()\n",
" else:\n",
" return x\n",
"\n",
" @staticmethod\n",
" def asarray(\n",
" obj, /, *, dtype=None, device=None, copy=None,\n",
" ) -> KerchunkArray:\n",
" \"\"\"Needed because xarray will call this even when it's a no-op\"\"\"\n",
" a = obj\n",
" \n",
" # from dask.asarray\n",
" if isinstance(a, KerchunkArray):\n",
" return a\n",
" elif type(a).__module__.split(\".\")[0] == \"xarray\" and hasattr(\n",
" a, \"data\"\n",
" ): # pragma: no cover\n",
" return asarray(a.data)\n",
" else:\n",
" raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "b3aeebfe-a74d-4173-a99c-7c8ac1eab656",
"metadata": {},
"outputs": [],
"source": [
"KerchunkArray.__array_namespace__ = ArrayAPI"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "afafcd8e-a317-492a-91b4-6b3302c843c6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function __main__.ArrayAPI.concat(arrays: list[__main__.KerchunkArray], /, *, axis=0) -> __main__.KerchunkArray>"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"karr1.__array_namespace__().concat"
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "270d0490-aea1-429b-ab86-11655388dead",
"metadata": {},
"outputs": [],
"source": [
"# TODO this probably shouldn't pretend to follow the array API standard when in reality it will only ever support a tiny subset of it\n",
"# It would probably be better to provide access to concat via defining `__array_function__` instead of `__array_namespace__`"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "06c7159a-8287-4d4c-b94e-aaf556bcf5c7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from xarray.core.utils import is_duck_array\n",
"\n",
"is_duck_array(karr1)"
]
},
{
"cell_type": "markdown",
"id": "b8e36849-875c-4f99-8d31-ffdeec7911b1",
"metadata": {},
"source": [
"## Use xarray to wrap the `KerchunkArrays`"
]
},
{
"cell_type": "markdown",
"id": "a3e2fd5c-72b7-447a-8fb2-f82c56a62290",
"metadata": {},
"source": [
"Now we need a way to get from a netCDF file on disk to an `xarray.Dataset` object containing multiple `KerchunkArray`s, with the correct `dims` and `attrs`."
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "f37a0f19-5cc7-41da-8cb2-99e83fac41e5",
"metadata": {},
"outputs": [],
"source": [
"from xarray.backends import BackendArray\n",
"\n",
"\n",
"class KerchunkBackendArray(KerchunkArray, BackendArray):\n",
" \"\"\"Using this prevents xarray from wrapping the KerchunkArray in ExplicitIndexingAdapter etc.\"\"\"\n",
" ...\n",
"\n",
"\n",
"def open_dataset_as_kerchunkarrays(\n",
" filepath: str,\n",
" drop_variables=None,\n",
") -> xr.Dataset[KerchunkArray]: # the xr.Dataset type isn't actually a generic but this indicates what we're trying to do with this function\n",
" \"\"\"\n",
" Open a netCDF4 file as a set of KerchunkArrays, including variable names, dimensions, and attrs.\n",
"\n",
" It's important that we avoid creating any IndexVariables, as our KerchunkArray object doesn't actually contain a collection that can be turned into a pandas.Index.\n",
" \"\"\"\n",
"\n",
" # this is the only place we actually need to use kerchunk directly\n",
" ds_refs = SingleHdf5ToZarr(filepath, inline_threshold=300).translate()\n",
" \n",
" var_names = find_var_names(ds_refs)\n",
"\n",
" if drop_variables is not None:\n",
" # TODO could easily do this by dropping keys from the references dict\n",
" raise NotImplementedError()\n",
"\n",
" vars = {}\n",
" for var_name in var_names:\n",
" arr_refs, zattrs = extract_array_refs(ds_refs, var_name)\n",
" arr_refs = fully_decode(arr_refs)\n",
" zattrs = json.loads(zattrs)\n",
" karr = KerchunkBackendArray(arr_refs)\n",
" dims = get_dims(zattrs)\n",
" \n",
" vars[var_name] = xr.Variable(data=karr, dims=dims, attrs=zattrs)\n",
"\n",
" data_vars, coords = separate_coords(vars)\n",
"\n",
" ds_attrs = fully_decode(ds_refs['refs'])['.zattrs']\n",
" \n",
" ds = xr.Dataset(\n",
" data_vars, \n",
" coords=coords,\n",
" #indexes={}, # this kwarg does exist in later versions of xarray\n",
" attrs=ds_attrs\n",
" )\n",
"\n",
" # TODO we should probably also use ds.set_close() to tell xarray how to close the file we opened\n",
" \n",
" return ds\n",
"\n",
"\n",
"def get_dims(zattrs: ZAttrs) -> list[str]:\n",
" array_dimensions = zattrs['_ARRAY_DIMENSIONS']\n",
" # TODO what if this attribute doesn't exist?\n",
" return array_dimensions\n",
"\n",
"\n",
"def separate_coords(vars: dict[str, xr.Variable]) -> tuple[dict[str, xr.Variable], xr.Coordinates]:\n",
" \"\"\"\n",
" Try to generate a set of coordinates that won't cause xarray to automatically build a pandas.Index for the 1D coordinates.\n",
" \n",
" I thought this should be easy but it was actually really hard - in the end I had to checkout xarray v2023.08.0, the last one before #8107 was merged.\n",
" \"\"\"\n",
"\n",
" coord_names = [] # this would normally come from CF decoding, let's hope the fact we're skipping that doesn't cause any problems...\n",
" \n",
" # split data and coordinate variables (promote dimension coordinates)\n",
" data_vars = {}\n",
" coord_vars = {}\n",
" for name, var in vars.items():\n",
" if name in coord_names or var.dims == (name,):\n",
" # use workaround to avoid creating IndexVariables described here https://github.com/pydata/xarray/pull/8107#discussion_r1311214263\n",
" if len(var.dims) == 1:\n",
" dim1d, *_ = var.dims\n",
" coord_vars[name] = (dim1d, var.data)\n",
" else:\n",
" coord_vars[name] = var\n",
" else:\n",
" data_vars[name] = var\n",
" \n",
" # this is stolen from https://github.com/pydata/xarray/pull/8051\n",
" # needed otherwise xarray errors whilst trying to turn the KerchunkArrays for the 1D coordinate variables into indexes\n",
" # but it doesn't appear to work with `main` since #8107, which is why the workaround above is needed\n",
" # EDIT: actually even the workaround doesn't work - to avoid creating indexes I had to checkout xarray v2023.08.0, the last one before #8107 was merged\n",
" set_indexes = False\n",
" if set_indexes:\n",
" coords = coord_vars\n",
" else:\n",
" # explict Coordinates object with no index passed\n",
" coords = xr.Coordinates(coord_vars, indexes={})\n",
"\n",
" return data_vars, coords"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "684a5d49-5bc2-4ac7-8784-16ba8aed6492",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Coordinates:\n",
" lat (lat) float32 KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;\n",
" lon (lon) float32 KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;\n",
" time (time) float32 KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;\n",
"Data variables:\n",
" air (time, lat, lon) int16 KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;\n",
"Attributes:\n",
" Conventions: COARDS\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...\n",
" title: 4x daily NMC reanalysis (1948)</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-108400f9-aee8-4004-a30a-13953b3de52a' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-108400f9-aee8-4004-a30a-13953b3de52a' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span>time</span>: 2920</li><li><span>lat</span>: 25</li><li><span>lon</span>: 53</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-e3d71a04-ccd5-4ded-b3ad-e4492ff278bc' class='xr-section-summary-in' type='checkbox' checked><label for='section-e3d71a04-ccd5-4ded-b3ad-e4492ff278bc' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;</div><input id='attrs-cb98b595-72bb-4dbe-a084-7a30258bbde6' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-cb98b595-72bb-4dbe-a084-7a30258bbde6' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-c4c590a8-05cb-4a44-a94d-2898997b6caf' class='xr-var-data-in' type='checkbox'><label for='data-c4c590a8-05cb-4a44-a94d-2898997b6caf' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;</div><input id='attrs-d79bdf8e-c3b7-49cc-b962-e95d2f431b95' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-d79bdf8e-c3b7-49cc-b962-e95d2f431b95' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-5e861217-47ec-4c9d-bb15-86d13aeac002' class='xr-var-data-in' type='checkbox'><label for='data-5e861217-47ec-4c9d-bb15-86d13aeac002' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;</div><input id='attrs-86070b95-4e8d-41ac-8816-dd73910d1a07' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-86070b95-4e8d-41ac-8816-dd73910d1a07' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-13bf72d1-d73a-4244-94ee-fe7ac8e0dc72' class='xr-var-data-in' type='checkbox'><label for='data-13bf72d1-d73a-4244-94ee-fe7ac8e0dc72' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-00e1c393-a0e1-449c-871c-6615645e7315' class='xr-section-summary-in' type='checkbox' checked><label for='section-00e1c393-a0e1-449c-871c-6615645e7315' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>int16</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;</div><input id='attrs-f93b4c78-2b04-43c8-a84a-ca725e9805d1' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-f93b4c78-2b04-43c8-a84a-ca725e9805d1' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-bfcfffb3-cd4f-4019-89e2-334be4ae9537' class='xr-var-data-in' type='checkbox'><label for='data-bfcfffb3-cd4f-4019-89e2-334be4ae9537' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>_ARRAY_DIMENSIONS :</span></dt><dd>[&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]</dd><dt><span>actual_range :</span></dt><dd>[185.16000366210938, 322.1000061035156]</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>scale_factor :</span></dt><dd>0.01</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-afb4a654-b982-403a-8680-2e8094562943' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-afb4a654-b982-403a-8680-2e8094562943' class='xr-section-summary' title='Expand/collapse section'>Indexes: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'></ul></div></li><li class='xr-section-item'><input id='section-ce54ac4b-e665-48d0-8196-46b6d135a585' class='xr-section-summary-in' type='checkbox' checked><label for='section-ce54ac4b-e665-48d0-8196-46b6d135a585' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Coordinates:\n",
" lat (lat) float32 KerchunkArray<shape=(25,), dtype=float32, chunks=(25,)>\n",
" lon (lon) float32 KerchunkArray<shape=(53,), dtype=float32, chunks=(53,)>\n",
" time (time) float32 KerchunkArray<shape=(2920,), dtype=float32, chunks=(2920,)>\n",
"Data variables:\n",
" air (time, lat, lon) int16 KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)>\n",
"Attributes:\n",
" Conventions: COARDS\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...\n",
" title: 4x daily NMC reanalysis (1948)"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"open_dataset_as_kerchunkarrays('air.nc')"
]
},
{
"cell_type": "markdown",
"id": "331a5f94-7570-40b7-87ba-27d85534f25e",
"metadata": {},
"source": [
"Haha!"
]
},
{
"cell_type": "markdown",
"id": "c7b3ab37-ecdd-4e15-a3ea-9cd3e62bbcc6",
"metadata": {},
"source": [
"Each `xr.DataArray` has the correct `_ARRAY_DIMENSIONS`, `.zattrs`, and name read from the file by kerchunk"
]
},
{
"cell_type": "code",
"execution_count": 54,
"id": "33d6933e-716b-41a1-b48d-60469626d6d2",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.DataArray &#x27;air&#x27; (time: 2920, lat: 25, lon: 53)&gt;\n",
"KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;\n",
"Coordinates:\n",
" lat (lat) float32 KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;\n",
" lon (lon) float32 KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;\n",
" time (time) float32 KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;\n",
"Attributes: (12/13)\n",
" GRIB_id: 11\n",
" GRIB_name: TMP\n",
" _ARRAY_DIMENSIONS: [&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]\n",
" actual_range: [185.16000366210938, 322.1000061035156]\n",
" dataset: NMC Reanalysis\n",
" level_desc: Surface\n",
" ... ...\n",
" parent_stat: Other\n",
" precision: 2\n",
" scale_factor: 0.01\n",
" statistic: Individual Obs\n",
" units: degK\n",
" var_desc: Air temperature</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.DataArray</div><div class='xr-array-name'>'air'</div><ul class='xr-dim-list'><li><span>time</span>: 2920</li><li><span>lat</span>: 25</li><li><span>lon</span>: 53</li></ul></div><ul class='xr-sections'><li class='xr-section-item'><div class='xr-array-wrap'><input id='section-4d7128da-56d1-425d-b082-cdd386a54574' class='xr-array-in' type='checkbox' checked><label for='section-4d7128da-56d1-425d-b082-cdd386a54574' title='Show/hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-array-preview xr-preview'><span>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;</span></div><div class='xr-array-data'><pre>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;</pre></div></div></li><li class='xr-section-item'><input id='section-bcda8c60-e984-4312-b1e2-31016301b13d' class='xr-section-summary-in' type='checkbox' checked><label for='section-bcda8c60-e984-4312-b1e2-31016301b13d' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;</div><input id='attrs-07ee9592-3e0e-4994-82b3-5acf631ae781' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-07ee9592-3e0e-4994-82b3-5acf631ae781' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-0d26cdca-e81c-4e01-acb6-9a4d784a4700' class='xr-var-data-in' type='checkbox'><label for='data-0d26cdca-e81c-4e01-acb6-9a4d784a4700' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;</div><input id='attrs-24f25341-059a-40ba-9354-454ed64349a8' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-24f25341-059a-40ba-9354-454ed64349a8' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-59ae0aea-0fdd-4769-b177-c8151ff03c6a' class='xr-var-data-in' type='checkbox'><label for='data-59ae0aea-0fdd-4769-b177-c8151ff03c6a' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;</div><input id='attrs-71acac4e-ee1c-4edf-8323-da924ea0e035' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-71acac4e-ee1c-4edf-8323-da924ea0e035' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-3592739d-025f-4fd0-8f37-5acf76970070' class='xr-var-data-in' type='checkbox'><label for='data-3592739d-025f-4fd0-8f37-5acf76970070' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-9568509e-1a93-4222-a91a-788bcebbe680' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-9568509e-1a93-4222-a91a-788bcebbe680' class='xr-section-summary' title='Expand/collapse section'>Indexes: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'></ul></div></li><li class='xr-section-item'><input id='section-37ce31d0-33a1-4207-8601-43a6f7df6005' class='xr-section-summary-in' type='checkbox' ><label for='section-37ce31d0-33a1-4207-8601-43a6f7df6005' class='xr-section-summary' >Attributes: <span>(13)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>_ARRAY_DIMENSIONS :</span></dt><dd>[&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]</dd><dt><span>actual_range :</span></dt><dd>[185.16000366210938, 322.1000061035156]</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>scale_factor :</span></dt><dd>0.01</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.DataArray 'air' (time: 2920, lat: 25, lon: 53)>\n",
"KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)>\n",
"Coordinates:\n",
" lat (lat) float32 KerchunkArray<shape=(25,), dtype=float32, chunks=(25,)>\n",
" lon (lon) float32 KerchunkArray<shape=(53,), dtype=float32, chunks=(53,)>\n",
" time (time) float32 KerchunkArray<shape=(2920,), dtype=float32, chunks=(2920,)>\n",
"Attributes: (12/13)\n",
" GRIB_id: 11\n",
" GRIB_name: TMP\n",
" _ARRAY_DIMENSIONS: ['time', 'lat', 'lon']\n",
" actual_range: [185.16000366210938, 322.1000061035156]\n",
" dataset: NMC Reanalysis\n",
" level_desc: Surface\n",
" ... ...\n",
" parent_stat: Other\n",
" precision: 2\n",
" scale_factor: 0.01\n",
" statistic: Individual Obs\n",
" units: degK\n",
" var_desc: Air temperature"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"open_dataset_as_kerchunkarrays('air.nc')['air']"
]
},
{
"cell_type": "code",
"execution_count": 55,
"id": "3cbb4d9b-8f6a-44ea-a579-5bb78cf76e78",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)>"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"open_dataset_as_kerchunkarrays('air.nc')['air'].variable._data"
]
},
{
"cell_type": "markdown",
"id": "d8162203-7684-4329-bec1-f0004689a81c",
"metadata": {},
"source": [
"We can make opening the file with kerchunk like this more convenient for the user by writing a [custom xarray backend](https://docs.xarray.dev/en/stable/internals/how-to-add-new-backend.html)."
]
},
{
"cell_type": "code",
"execution_count": 56,
"id": "807335f2-3a97-4f3d-a7d8-b863dd8905be",
"metadata": {},
"outputs": [],
"source": [
"from xarray.backends import BackendEntrypoint"
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "3b5e197a-7ab6-4de6-b37a-d59ee3589489",
"metadata": {},
"outputs": [],
"source": [
"class KerchunkBackendEntrypoint(BackendEntrypoint):\n",
" def open_dataset(\n",
" self,\n",
" filename_or_obj,\n",
" *,\n",
" drop_variables=None,\n",
" # other backend specific keyword arguments\n",
" ):\n",
" return open_dataset_as_kerchunkarrays(filename_or_obj)\n",
" \n",
" description = \"Open netCDF4 files as KerchunkArray objects.\""
]
},
{
"cell_type": "markdown",
"id": "6913ebaf-5c99-4e77-ae36-d0916da8d662",
"metadata": {},
"source": [
"Now we can just do this"
]
},
{
"cell_type": "code",
"execution_count": 58,
"id": "c7c9b14e-d308-466d-8fc1-d55c074fe51b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Coordinates:\n",
" lat (lat) float32 KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;\n",
" lon (lon) float32 KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;\n",
" time (time) float32 KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;\n",
"Data variables:\n",
" air (time, lat, lon) int16 KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;\n",
"Attributes:\n",
" Conventions: COARDS\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...\n",
" title: 4x daily NMC reanalysis (1948)</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-53aa9241-99de-4dbc-8863-18ce27b20e9c' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-53aa9241-99de-4dbc-8863-18ce27b20e9c' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span>time</span>: 2920</li><li><span>lat</span>: 25</li><li><span>lon</span>: 53</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-e5236b51-69fa-46bc-b4b6-ffcced542684' class='xr-section-summary-in' type='checkbox' checked><label for='section-e5236b51-69fa-46bc-b4b6-ffcced542684' class='xr-section-summary' >Coordinates: <span>(3)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>lat</span></div><div class='xr-var-dims'>(lat)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;</div><input id='attrs-229ba436-1364-4546-af5d-88e139c10839' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-229ba436-1364-4546-af5d-88e139c10839' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-a7b4272d-277b-4719-aad0-ee422a8d24cd' class='xr-var-data-in' type='checkbox'><label for='data-a7b4272d-277b-4719-aad0-ee422a8d24cd' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(25,), dtype=float32, chunks=(25,)&gt;</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>lon</span></div><div class='xr-var-dims'>(lon)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;</div><input id='attrs-ac66ffb7-cc40-4604-aa83-41c1c0a88d70' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-ac66ffb7-cc40-4604-aa83-41c1c0a88d70' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-92f364b7-f4fe-44f4-aa54-7acf3030bc69' class='xr-var-data-in' type='checkbox'><label for='data-92f364b7-f4fe-44f4-aa54-7acf3030bc69' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(53,), dtype=float32, chunks=(53,)&gt;</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>time</span></div><div class='xr-var-dims'>(time)</div><div class='xr-var-dtype'>float32</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;</div><input id='attrs-141f7f27-268e-4b71-8398-722970033496' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-141f7f27-268e-4b71-8398-722970033496' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-b312015e-1243-4494-b52b-81e022782d38' class='xr-var-data-in' type='checkbox'><label for='data-b312015e-1243-4494-b52b-81e022782d38' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(2920,), dtype=float32, chunks=(2920,)&gt;</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-5b0837d4-3934-4fc8-ab46-e6924356a2ca' class='xr-section-summary-in' type='checkbox' checked><label for='section-5b0837d4-3934-4fc8-ab46-e6924356a2ca' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>int16</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;</div><input id='attrs-44f90405-0e55-425b-964c-2d2f828e2860' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-44f90405-0e55-425b-964c-2d2f828e2860' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-5220b00d-e10f-4897-b30a-409b4b0af49c' class='xr-var-data-in' type='checkbox'><label for='data-5220b00d-e10f-4897-b30a-409b4b0af49c' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>_ARRAY_DIMENSIONS :</span></dt><dd>[&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]</dd><dt><span>actual_range :</span></dt><dd>[185.16000366210938, 322.1000061035156]</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>scale_factor :</span></dt><dd>0.01</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)&gt;</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-9f10be1c-12d9-4ef0-a82c-d79495a5f2bb' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-9f10be1c-12d9-4ef0-a82c-d79495a5f2bb' class='xr-section-summary' title='Expand/collapse section'>Indexes: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'></ul></div></li><li class='xr-section-item'><input id='section-9c7fddf7-6302-4ccc-a74f-591979cb6b39' class='xr-section-summary-in' type='checkbox' checked><label for='section-9c7fddf7-6302-4ccc-a74f-591979cb6b39' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Coordinates:\n",
" lat (lat) float32 KerchunkArray<shape=(25,), dtype=float32, chunks=(25,)>\n",
" lon (lon) float32 KerchunkArray<shape=(53,), dtype=float32, chunks=(53,)>\n",
" time (time) float32 KerchunkArray<shape=(2920,), dtype=float32, chunks=(2920,)>\n",
"Data variables:\n",
" air (time, lat, lon) int16 KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)>\n",
"Attributes:\n",
" Conventions: COARDS\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...\n",
" title: 4x daily NMC reanalysis (1948)"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xr.open_dataset('air.nc', engine=KerchunkBackendEntrypoint, cache=False)"
]
},
{
"cell_type": "markdown",
"id": "55eb7b07-6981-45a0-b471-731b93ef8e7a",
"metadata": {},
"source": [
"huh that repr didn't work..."
]
},
{
"cell_type": "code",
"execution_count": 59,
"id": "ac5b3757-f669-47a9-aa34-3c207fc82297",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)>"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xr.open_dataset('air.nc', engine=KerchunkBackendEntrypoint, cache=False)['air'].variable._data"
]
},
{
"cell_type": "markdown",
"id": "b8d6b109-6d86-4c23-9439-377ed772651f",
"metadata": {},
"source": [
"I don't know how to get rid of this CopyOnWriteArray that xarray adds."
]
},
{
"cell_type": "code",
"execution_count": 60,
"id": "78f1288d-1d72-4ad9-bff8-2344b9388921",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(2920, 25, 53)>"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xr.open_dataset('air.nc', engine=KerchunkBackendEntrypoint, cache=False)['air'].variable.data"
]
},
{
"cell_type": "markdown",
"id": "a5b6cfce-1352-4230-95a2-515e4ea0e32e",
"metadata": {},
"source": [
"But so long as we have defined `KerchunkArray.__getitem__` it doesn't seem to matter (beyond the repr not being easily visible)..."
]
},
{
"cell_type": "markdown",
"id": "8a72f09c-08c1-429c-bbc1-4793e1ff42e9",
"metadata": {},
"source": [
"## Use xarray to perform concatenation"
]
},
{
"cell_type": "code",
"execution_count": 61,
"id": "5e30e814-effa-4d08-bf5d-c71cdca5114e",
"metadata": {},
"outputs": [],
"source": [
"ds1_kc = xr.open_dataset('air1.nc', engine=KerchunkBackendEntrypoint, cache=False)\n",
"ds2_kc = xr.open_dataset('air2.nc', engine=KerchunkBackendEntrypoint, cache=False)"
]
},
{
"cell_type": "code",
"execution_count": 62,
"id": "8b5e44eb-6f02-4282-b7cf-aeb29a78dbdb",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [1460, 25, 53],\n",
" 'zarr_format': 2},\n",
" '0.0.0': ['air1.nc', 15419, 3869000]}"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds1_kc['air'].variable.data.arr_refs"
]
},
{
"cell_type": "code",
"execution_count": 63,
"id": "a0d5a6d2-840d-4c3e-93d8-f3c552065f35",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [1460, 25, 53],\n",
" 'zarr_format': 2},\n",
" '0.0.0': ['air2.nc', 15419, 3869000]}"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds2_kc['air'].variable.data.arr_refs"
]
},
{
"cell_type": "code",
"execution_count": 64,
"id": "d090a4ad-b6e4-44b7-a128-710d5ad65680",
"metadata": {},
"outputs": [
{
"ename": "RecursionError",
"evalue": "maximum recursion depth exceeded while calling a Python object",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[64], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mxr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconcat\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mds1_kc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mair\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mds1_kc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mair\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mtime\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcoords\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mminimal\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcompat\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43moverride\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/concat.py:240\u001b[0m, in \u001b[0;36mconcat\u001b[0;34m(objs, dim, data_vars, coords, compat, positions, fill_value, join, combine_attrs)\u001b[0m\n\u001b[1;32m 235\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 236\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcompat=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcompat\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m invalid: must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mbroadcast_equals\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mequals\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124midentical\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mno_conflicts\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m or \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moverride\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 237\u001b[0m )\n\u001b[1;32m 239\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(first_obj, DataArray):\n\u001b[0;32m--> 240\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_dataarray_concat\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 241\u001b[0m \u001b[43m \u001b[49m\u001b[43mobjs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 242\u001b[0m \u001b[43m \u001b[49m\u001b[43mdim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 243\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata_vars\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 244\u001b[0m \u001b[43m \u001b[49m\u001b[43mcoords\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcoords\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 245\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompat\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcompat\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 246\u001b[0m \u001b[43m \u001b[49m\u001b[43mpositions\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpositions\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 247\u001b[0m \u001b[43m \u001b[49m\u001b[43mfill_value\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfill_value\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 248\u001b[0m \u001b[43m \u001b[49m\u001b[43mjoin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjoin\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 249\u001b[0m \u001b[43m \u001b[49m\u001b[43mcombine_attrs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcombine_attrs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 250\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 251\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(first_obj, Dataset):\n\u001b[1;32m 252\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _dataset_concat(\n\u001b[1;32m 253\u001b[0m objs,\n\u001b[1;32m 254\u001b[0m dim\u001b[38;5;241m=\u001b[39mdim,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 261\u001b[0m combine_attrs\u001b[38;5;241m=\u001b[39mcombine_attrs,\n\u001b[1;32m 262\u001b[0m )\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/concat.py:712\u001b[0m, in \u001b[0;36m_dataarray_concat\u001b[0;34m(arrays, dim, data_vars, coords, compat, positions, fill_value, join, combine_attrs)\u001b[0m\n\u001b[1;32m 709\u001b[0m arr \u001b[38;5;241m=\u001b[39m cast(T_DataArray, arr\u001b[38;5;241m.\u001b[39mrename(name))\n\u001b[1;32m 710\u001b[0m datasets\u001b[38;5;241m.\u001b[39mappend(arr\u001b[38;5;241m.\u001b[39m_to_temp_dataset())\n\u001b[0;32m--> 712\u001b[0m ds \u001b[38;5;241m=\u001b[39m \u001b[43m_dataset_concat\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 713\u001b[0m \u001b[43m \u001b[49m\u001b[43mdatasets\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 714\u001b[0m \u001b[43m \u001b[49m\u001b[43mdim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 715\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata_vars\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 716\u001b[0m \u001b[43m \u001b[49m\u001b[43mcoords\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 717\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompat\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 718\u001b[0m \u001b[43m \u001b[49m\u001b[43mpositions\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 719\u001b[0m \u001b[43m \u001b[49m\u001b[43mfill_value\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfill_value\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 720\u001b[0m \u001b[43m \u001b[49m\u001b[43mjoin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjoin\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 721\u001b[0m \u001b[43m \u001b[49m\u001b[43mcombine_attrs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcombine_attrs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 722\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 724\u001b[0m merged_attrs \u001b[38;5;241m=\u001b[39m merge_attrs([da\u001b[38;5;241m.\u001b[39mattrs \u001b[38;5;28;01mfor\u001b[39;00m da \u001b[38;5;129;01min\u001b[39;00m arrays], combine_attrs)\n\u001b[1;32m 726\u001b[0m result \u001b[38;5;241m=\u001b[39m arrays[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39m_from_temp_dataset(ds, name)\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/concat.py:648\u001b[0m, in \u001b[0;36m_dataset_concat\u001b[0;34m(datasets, dim, data_vars, coords, compat, positions, fill_value, join, combine_attrs)\u001b[0m\n\u001b[1;32m 644\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01min\u001b[39;00m result_vars:\n\u001b[1;32m 645\u001b[0m \u001b[38;5;66;03m# preserves original variable order\u001b[39;00m\n\u001b[1;32m 646\u001b[0m result_vars[name] \u001b[38;5;241m=\u001b[39m result_vars\u001b[38;5;241m.\u001b[39mpop(name)\n\u001b[0;32m--> 648\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mtype\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mdatasets\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresult_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mattrs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mresult_attrs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 650\u001b[0m absent_coord_names \u001b[38;5;241m=\u001b[39m coord_names \u001b[38;5;241m-\u001b[39m \u001b[38;5;28mset\u001b[39m(result\u001b[38;5;241m.\u001b[39mvariables)\n\u001b[1;32m 651\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m absent_coord_names:\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/dataset.py:685\u001b[0m, in \u001b[0;36mDataset.__init__\u001b[0;34m(self, data_vars, coords, attrs)\u001b[0m\n\u001b[1;32m 682\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(coords, Dataset):\n\u001b[1;32m 683\u001b[0m coords \u001b[38;5;241m=\u001b[39m coords\u001b[38;5;241m.\u001b[39m_variables\n\u001b[0;32m--> 685\u001b[0m variables, coord_names, dims, indexes, _ \u001b[38;5;241m=\u001b[39m \u001b[43mmerge_data_and_coords\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 686\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcoords\u001b[49m\n\u001b[1;32m 687\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 689\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_attrs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mdict\u001b[39m(attrs) \u001b[38;5;28;01mif\u001b[39;00m attrs \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 690\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_close \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/dataset.py:416\u001b[0m, in \u001b[0;36mmerge_data_and_coords\u001b[0;34m(data_vars, coords)\u001b[0m\n\u001b[1;32m 412\u001b[0m coords \u001b[38;5;241m=\u001b[39m create_coords_with_default_indexes(coords, data_vars)\n\u001b[1;32m 414\u001b[0m \u001b[38;5;66;03m# exclude coords from alignment (all variables in a Coordinates object should\u001b[39;00m\n\u001b[1;32m 415\u001b[0m \u001b[38;5;66;03m# already be aligned together) and use coordinates' indexes to align data_vars\u001b[39;00m\n\u001b[0;32m--> 416\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmerge_core\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 417\u001b[0m \u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mdata_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcoords\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 418\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompat\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mbroadcast_equals\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 419\u001b[0m \u001b[43m \u001b[49m\u001b[43mjoin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mouter\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 420\u001b[0m \u001b[43m \u001b[49m\u001b[43mexplicit_coords\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mtuple\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mcoords\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 421\u001b[0m \u001b[43m \u001b[49m\u001b[43mindexes\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcoords\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mxindexes\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 422\u001b[0m \u001b[43m \u001b[49m\u001b[43mpriority_arg\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 423\u001b[0m \u001b[43m \u001b[49m\u001b[43mskip_align_args\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 424\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/merge.py:717\u001b[0m, in \u001b[0;36mmerge_core\u001b[0;34m(objects, compat, join, combine_attrs, priority_arg, explicit_coords, indexes, fill_value, skip_align_args)\u001b[0m\n\u001b[1;32m 714\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m pos, obj \u001b[38;5;129;01min\u001b[39;00m skip_align_objs:\n\u001b[1;32m 715\u001b[0m aligned\u001b[38;5;241m.\u001b[39minsert(pos, obj)\n\u001b[0;32m--> 717\u001b[0m collected \u001b[38;5;241m=\u001b[39m \u001b[43mcollect_variables_and_indexes\u001b[49m\u001b[43m(\u001b[49m\u001b[43maligned\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindexes\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexes\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 718\u001b[0m prioritized \u001b[38;5;241m=\u001b[39m _get_priority_vars_and_indexes(aligned, priority_arg, compat\u001b[38;5;241m=\u001b[39mcompat)\n\u001b[1;32m 719\u001b[0m variables, out_indexes \u001b[38;5;241m=\u001b[39m merge_collected(\n\u001b[1;32m 720\u001b[0m collected, prioritized, compat\u001b[38;5;241m=\u001b[39mcompat, combine_attrs\u001b[38;5;241m=\u001b[39mcombine_attrs\n\u001b[1;32m 721\u001b[0m )\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/merge.py:358\u001b[0m, in \u001b[0;36mcollect_variables_and_indexes\u001b[0;34m(list_of_mappings, indexes)\u001b[0m\n\u001b[1;32m 355\u001b[0m indexes_\u001b[38;5;241m.\u001b[39mpop(name, \u001b[38;5;28;01mNone\u001b[39;00m)\n\u001b[1;32m 356\u001b[0m append_all(coords_, indexes_)\n\u001b[0;32m--> 358\u001b[0m variable \u001b[38;5;241m=\u001b[39m \u001b[43mas_variable\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvariable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mname\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 359\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m name \u001b[38;5;129;01min\u001b[39;00m indexes:\n\u001b[1;32m 360\u001b[0m append(name, variable, indexes[name])\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/variable.py:161\u001b[0m, in \u001b[0;36mas_variable\u001b[0;34m(obj, name)\u001b[0m\n\u001b[1;32m 154\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[1;32m 155\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mVariable \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m: unable to convert object into a variable without an \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexplicit list of dimensions: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mobj\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 157\u001b[0m )\n\u001b[1;32m 159\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m name \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01min\u001b[39;00m obj\u001b[38;5;241m.\u001b[39mdims \u001b[38;5;129;01mand\u001b[39;00m obj\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 160\u001b[0m \u001b[38;5;66;03m# automatically convert the Variable into an Index\u001b[39;00m\n\u001b[0;32m--> 161\u001b[0m obj \u001b[38;5;241m=\u001b[39m \u001b[43mobj\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_index_variable\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m obj\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/variable.py:622\u001b[0m, in \u001b[0;36mVariable.to_index_variable\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 620\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mto_index_variable\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m IndexVariable:\n\u001b[1;32m 621\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return this variable as an xarray.IndexVariable\"\"\"\u001b[39;00m\n\u001b[0;32m--> 622\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mIndexVariable\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 623\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dims\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_data\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_attrs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_encoding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfastpath\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\n\u001b[1;32m 624\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/variable.py:2891\u001b[0m, in \u001b[0;36mIndexVariable.__init__\u001b[0;34m(self, dims, data, attrs, encoding, fastpath)\u001b[0m\n\u001b[1;32m 2889\u001b[0m \u001b[38;5;66;03m# Unlike in Variable, always eagerly load values into memory\u001b[39;00m\n\u001b[1;32m 2890\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_data, PandasIndexingAdapter):\n\u001b[0;32m-> 2891\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_data \u001b[38;5;241m=\u001b[39m \u001b[43mPandasIndexingAdapter\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_data\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/indexing.py:1478\u001b[0m, in \u001b[0;36mPandasIndexingAdapter.__init__\u001b[0;34m(self, array, dtype)\u001b[0m\n\u001b[1;32m 1475\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, array: pd\u001b[38;5;241m.\u001b[39mIndex, dtype: DTypeLike \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 1476\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mxarray\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcore\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mindexes\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m safe_cast_to_index\n\u001b[0;32m-> 1478\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39marray \u001b[38;5;241m=\u001b[39m \u001b[43msafe_cast_to_index\u001b[49m\u001b[43m(\u001b[49m\u001b[43marray\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m dtype \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 1481\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dtype \u001b[38;5;241m=\u001b[39m get_valid_numpy_dtype(array)\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/indexes.py:473\u001b[0m, in \u001b[0;36msafe_cast_to_index\u001b[0;34m(array)\u001b[0m\n\u001b[1;32m 463\u001b[0m emit_user_level_warning(\n\u001b[1;32m 464\u001b[0m (\n\u001b[1;32m 465\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m`pandas.Index` does not support the `float16` dtype.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 469\u001b[0m category\u001b[38;5;241m=\u001b[39m\u001b[38;5;167;01mDeprecationWarning\u001b[39;00m,\n\u001b[1;32m 470\u001b[0m )\n\u001b[1;32m 471\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdtype\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfloat64\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m--> 473\u001b[0m index \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mIndex(\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43masarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43marray\u001b[49m\u001b[43m)\u001b[49m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 475\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _maybe_cast_to_cftimeindex(index)\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/indexing.py:455\u001b[0m, in \u001b[0;36mExplicitlyIndexed.__array__\u001b[0;34m(self, dtype)\u001b[0m\n\u001b[1;32m 453\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__array__\u001b[39m(\u001b[38;5;28mself\u001b[39m, dtype: np\u001b[38;5;241m.\u001b[39mtyping\u001b[38;5;241m.\u001b[39mDTypeLike \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m np\u001b[38;5;241m.\u001b[39mndarray:\n\u001b[1;32m 454\u001b[0m \u001b[38;5;66;03m# Leave casting to an array up to the underlying array type.\u001b[39;00m\n\u001b[0;32m--> 455\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43masarray\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_duck_array\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/indexing.py:455\u001b[0m, in \u001b[0;36mExplicitlyIndexed.__array__\u001b[0;34m(self, dtype)\u001b[0m\n\u001b[1;32m 453\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__array__\u001b[39m(\u001b[38;5;28mself\u001b[39m, dtype: np\u001b[38;5;241m.\u001b[39mtyping\u001b[38;5;241m.\u001b[39mDTypeLike \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m np\u001b[38;5;241m.\u001b[39mndarray:\n\u001b[1;32m 454\u001b[0m \u001b[38;5;66;03m# Leave casting to an array up to the underlying array type.\u001b[39;00m\n\u001b[0;32m--> 455\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43masarray\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_duck_array\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m)\u001b[49m\n",
" \u001b[0;31m[... skipping similar frames: ExplicitlyIndexed.__array__ at line 455 (733 times)]\u001b[0m\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/core/indexing.py:455\u001b[0m, in \u001b[0;36mExplicitlyIndexed.__array__\u001b[0;34m(self, dtype)\u001b[0m\n\u001b[1;32m 453\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__array__\u001b[39m(\u001b[38;5;28mself\u001b[39m, dtype: np\u001b[38;5;241m.\u001b[39mtyping\u001b[38;5;241m.\u001b[39mDTypeLike \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m np\u001b[38;5;241m.\u001b[39mndarray:\n\u001b[1;32m 454\u001b[0m \u001b[38;5;66;03m# Leave casting to an array up to the underlying array type.\u001b[39;00m\n\u001b[0;32m--> 455\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m np\u001b[38;5;241m.\u001b[39masarray(\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_duck_array\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m, dtype\u001b[38;5;241m=\u001b[39mdtype)\n",
"File \u001b[0;32m~/Documents/Work/Code/xarray/xarray/backends/common.py:169\u001b[0m, in \u001b[0;36mBackendArray.get_duck_array\u001b[0;34m(self, dtype)\u001b[0m\n\u001b[1;32m 168\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_duck_array\u001b[39m(\u001b[38;5;28mself\u001b[39m, dtype: np\u001b[38;5;241m.\u001b[39mtyping\u001b[38;5;241m.\u001b[39mDTypeLike \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[0;32m--> 169\u001b[0m key \u001b[38;5;241m=\u001b[39m indexing\u001b[38;5;241m.\u001b[39mBasicIndexer((\u001b[38;5;28mslice\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m),) \u001b[38;5;241m*\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mndim\u001b[49m)\n\u001b[1;32m 170\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m[key]\n",
"Cell \u001b[0;32mIn[28], line 44\u001b[0m, in \u001b[0;36mKerchunkArray.ndim\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m 43\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mndim\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mint\u001b[39m:\n\u001b[0;32m---> 44\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mshape\u001b[49m)\n",
"Cell \u001b[0;32mIn[28], line 40\u001b[0m, in \u001b[0;36mKerchunkArray.shape\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mshape\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mtuple\u001b[39m[\u001b[38;5;28mint\u001b[39m, \u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m]:\n\u001b[1;32m 39\u001b[0m \u001b[38;5;66;03m# TODO should this point to the chunks attribute of .zarray instead?\u001b[39;00m\n\u001b[0;32m---> 40\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mtuple\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43ml\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43ml\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43marr_refs\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m.zarray\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mshape\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
"Cell \u001b[0;32mIn[28], line 40\u001b[0m, in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mshape\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mtuple\u001b[39m[\u001b[38;5;28mint\u001b[39m, \u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m]:\n\u001b[1;32m 39\u001b[0m \u001b[38;5;66;03m# TODO should this point to the chunks attribute of .zarray instead?\u001b[39;00m\n\u001b[0;32m---> 40\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mtuple\u001b[39m(\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43ml\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m l \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mlist\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39marr_refs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.zarray\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mshape\u001b[39m\u001b[38;5;124m'\u001b[39m]))\n",
"\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded while calling a Python object"
]
}
],
"source": [
"xr.concat([ds1_kc['air'], ds1_kc['air']], dim='time', coords='minimal', compat='override')"
]
},
{
"cell_type": "markdown",
"id": "35c8e0cd-6093-4d38-8888-7eafa7392efb",
"metadata": {},
"source": [
"Okay so it doesn't work with dataarrays because it keeps trying to (unnecessarily) construct an index."
]
},
{
"cell_type": "markdown",
"id": "b1356c35-61b4-4b19-ba0c-5bc0aee7df63",
"metadata": {},
"source": [
"Variables don't have indexes, does it work if we concatenate those?"
]
},
{
"cell_type": "code",
"execution_count": 65,
"id": "515f2ad8-3fb4-4f14-8105-8bc34fe1d9ca",
"metadata": {},
"outputs": [],
"source": [
"result = xr.Variable.concat([ds1_kc['air'].variable, ds2_kc['air'].variable], dim='time')"
]
},
{
"cell_type": "code",
"execution_count": 66,
"id": "d00a2038-3e39-4613-82f1-95c3b0c79a2c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Variable (time: 2920, lat: 25, lon: 53)&gt;\n",
"KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)&gt;\n",
"Attributes: (12/13)\n",
" GRIB_id: 11\n",
" GRIB_name: TMP\n",
" _ARRAY_DIMENSIONS: [&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]\n",
" actual_range: [185.16000366210938, 322.1000061035156]\n",
" dataset: NMC Reanalysis\n",
" level_desc: Surface\n",
" ... ...\n",
" parent_stat: Other\n",
" precision: 2\n",
" scale_factor: 0.01\n",
" statistic: Individual Obs\n",
" units: degK\n",
" var_desc: Air temperature</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Variable</div><div class='xr-array-name'></div><ul class='xr-dim-list'><li><span>time</span>: 2920</li><li><span>lat</span>: 25</li><li><span>lon</span>: 53</li></ul></div><ul class='xr-sections'><li class='xr-section-item'><div class='xr-array-wrap'><input id='section-402ab5ca-9762-42da-b7ba-c7347cd07235' class='xr-array-in' type='checkbox' checked><label for='section-402ab5ca-9762-42da-b7ba-c7347cd07235' title='Show/hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-array-preview xr-preview'><span>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)&gt;</span></div><div class='xr-array-data'><pre>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)&gt;</pre></div></div></li><li class='xr-section-item'><input id='section-88d7e72d-4054-4df4-994a-b25b34955f29' class='xr-section-summary-in' type='checkbox' ><label for='section-88d7e72d-4054-4df4-994a-b25b34955f29' class='xr-section-summary' >Attributes: <span>(13)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>_ARRAY_DIMENSIONS :</span></dt><dd>[&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]</dd><dt><span>actual_range :</span></dt><dd>[185.16000366210938, 322.1000061035156]</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>scale_factor :</span></dt><dd>0.01</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Variable (time: 2920, lat: 25, lon: 53)>\n",
"KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)>\n",
"Attributes: (12/13)\n",
" GRIB_id: 11\n",
" GRIB_name: TMP\n",
" _ARRAY_DIMENSIONS: ['time', 'lat', 'lon']\n",
" actual_range: [185.16000366210938, 322.1000061035156]\n",
" dataset: NMC Reanalysis\n",
" level_desc: Surface\n",
" ... ...\n",
" parent_stat: Other\n",
" precision: 2\n",
" scale_factor: 0.01\n",
" statistic: Individual Obs\n",
" units: degK\n",
" var_desc: Air temperature"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result"
]
},
{
"cell_type": "code",
"execution_count": 67,
"id": "b39d33b5-38a6-4b1b-83df-df59b829d649",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'0.0.0': ['air1.nc', 15419, 3869000],\n",
" '1.0.0': ['air2.nc', 15419, 3869000],\n",
" '.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [2920, 25, 53],\n",
" 'zarr_format': 2}}"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result.data.arr_refs"
]
},
{
"cell_type": "markdown",
"id": "64c6d2b2-8039-486a-ac18-9b6d4b1ddd23",
"metadata": {},
"source": [
"Excellent!"
]
},
{
"cell_type": "markdown",
"id": "6d708af5-786e-4008-8716-a38512031546",
"metadata": {},
"source": [
"NOTE FOR XARRAY DEVS: I went down a big rabbit hole with xarray internals. \n",
"\n",
"We want to use the xarray BackendEntrypoint system instead of just `open_dataset_as_kerchunkarrays`, because that's the only way we can point `xr.open_mfdataset` at a glob of files. Unfortunately `xr.open_dataset` (called by `open_mfdataset`) does some things silently which caused problems. Specifically it doesn't just call `KerchunkBackendEntrypoint.open_dataset`, it also then calls `xarray.backends.api._protect_dataset_variables_inplace` on the dataset. This _always_ wraps the data inside an xarray class called `indexing.CopyOnWriteArray`, even though I would rather in this case that not happen, because I know I'm not going to be using any of the normal write methods (i.e. `to_netcdf` etc.). It would perhaps be better if as a backend developer I could opt out of using the `indexing.CopyOnWriteArray` class.\n",
"\n",
"If I do not manually comment out the line `data = indexing.CopyOnWriteArray(variable._data)` in `_protect_dataset_variables_inplace` , I end up with a RecursionError during concatenation, which is something to do with xarray seeing the `CopyOnWriteArray` and thinking it should use `np.concatenate`, when what it should do is see the array API namespace of the wrapped array and call `xp.concat`. It's likely that this could be avoided if I designed the `KerchunkArray` class differently, but I'm stuck as to exactly what I need to do. And even then I still want to get rid of `CopyOnWriteArray`."
]
},
{
"cell_type": "markdown",
"id": "78da9b14-8cdc-42f0-9246-684a934155b7",
"metadata": {},
"source": [
"## Serializing the result"
]
},
{
"cell_type": "markdown",
"id": "b6ffc186-3b87-4159-9056-5a85ad59eee0",
"metadata": {},
"source": [
"Okay let's pretend for a second that that did work properly (as I think it should be possible to make it work). What would the result look like?"
]
},
{
"cell_type": "markdown",
"id": "51b6fdfd-a0c6-4c92-9064-ee992aeec164",
"metadata": {},
"source": [
"We already successfully concatenated the `KerchunkArray`, so we can mock up the result as something like"
]
},
{
"cell_type": "code",
"execution_count": 68,
"id": "7d485057-b11c-4532-aa05-0637380cebed",
"metadata": {},
"outputs": [],
"source": [
"ds_full_mocked = xr.Dataset(data_vars={'air': result}, attrs=ds.attrs)"
]
},
{
"cell_type": "code",
"execution_count": 69,
"id": "c4bb4596-fbfa-42ad-ade3-839b70edfac8",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body[data-theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block !important;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-index-preview {\n",
" grid-column: 2 / 5;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data,\n",
".xr-index-data-in:checked ~ .xr-index-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-index-name div,\n",
".xr-index-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data,\n",
".xr-index-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2,\n",
".xr-no-icon {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'>&lt;xarray.Dataset&gt;\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Dimensions without coordinates: time, lat, lon\n",
"Data variables:\n",
" air (time, lat, lon) int16 KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)&gt;\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...</pre><div class='xr-wrap' style='display:none'><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-4a5318f4-5fd7-4746-af91-7d2b733722b3' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-4a5318f4-5fd7-4746-af91-7d2b733722b3' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span>time</span>: 2920</li><li><span>lat</span>: 25</li><li><span>lon</span>: 53</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-84b3afd7-4d0f-4464-855d-219a56f31f6d' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-84b3afd7-4d0f-4464-855d-219a56f31f6d' class='xr-section-summary' title='Expand/collapse section'>Coordinates: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'></ul></div></li><li class='xr-section-item'><input id='section-cdd3b081-6e9b-4669-a5cf-a1f81e7501cf' class='xr-section-summary-in' type='checkbox' checked><label for='section-cdd3b081-6e9b-4669-a5cf-a1f81e7501cf' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>air</span></div><div class='xr-var-dims'>(time, lat, lon)</div><div class='xr-var-dtype'>int16</div><div class='xr-var-preview xr-preview'>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)&gt;</div><input id='attrs-9b708505-cb1c-41e8-92c4-0acc5930c832' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-9b708505-cb1c-41e8-92c4-0acc5930c832' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-93bc603d-b71a-480b-8b19-d2ba86b713cc' class='xr-var-data-in' type='checkbox'><label for='data-93bc603d-b71a-480b-8b19-d2ba86b713cc' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>GRIB_id :</span></dt><dd>11</dd><dt><span>GRIB_name :</span></dt><dd>TMP</dd><dt><span>_ARRAY_DIMENSIONS :</span></dt><dd>[&#x27;time&#x27;, &#x27;lat&#x27;, &#x27;lon&#x27;]</dd><dt><span>actual_range :</span></dt><dd>[185.16000366210938, 322.1000061035156]</dd><dt><span>dataset :</span></dt><dd>NMC Reanalysis</dd><dt><span>level_desc :</span></dt><dd>Surface</dd><dt><span>long_name :</span></dt><dd>4xDaily Air temperature at sigma level 995</dd><dt><span>parent_stat :</span></dt><dd>Other</dd><dt><span>precision :</span></dt><dd>2</dd><dt><span>scale_factor :</span></dt><dd>0.01</dd><dt><span>statistic :</span></dt><dd>Individual Obs</dd><dt><span>units :</span></dt><dd>degK</dd><dt><span>var_desc :</span></dt><dd>Air temperature</dd></dl></div><div class='xr-var-data'><pre>KerchunkArray&lt;shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)&gt;</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-d3438a3c-ff76-4ccd-bebc-8cf6af8d83f8' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-d3438a3c-ff76-4ccd-bebc-8cf6af8d83f8' class='xr-section-summary' title='Expand/collapse section'>Indexes: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'></ul></div></li><li class='xr-section-item'><input id='section-9c2f2f4f-f4a2-4c49-92a2-15d83f3fb677' class='xr-section-summary-in' type='checkbox' checked><label for='section-9c2f2f4f-f4a2-4c49-92a2-15d83f3fb677' class='xr-section-summary' >Attributes: <span>(5)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'><dt><span>Conventions :</span></dt><dd>COARDS</dd><dt><span>title :</span></dt><dd>4x daily NMC reanalysis (1948)</dd><dt><span>description :</span></dt><dd>Data is from NMC initialized reanalysis\n",
"(4x/day). These are the 0.9950 sigma level values.</dd><dt><span>platform :</span></dt><dd>Model</dd><dt><span>references :</span></dt><dd>http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html</dd></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (time: 2920, lat: 25, lon: 53)\n",
"Dimensions without coordinates: time, lat, lon\n",
"Data variables:\n",
" air (time, lat, lon) int16 KerchunkArray<shape=(2920, 25, 53), dtype=int16, chunks=(1460, 25, 53)>\n",
"Attributes:\n",
" Conventions: COARDS\n",
" title: 4x daily NMC reanalysis (1948)\n",
" description: Data is from NMC initialized reanalysis\\n(4x/day). These a...\n",
" platform: Model\n",
" references: http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly..."
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds_full_mocked"
]
},
{
"cell_type": "markdown",
"id": "9a91a2bf-3d02-481b-9dec-32b4b4480b2a",
"metadata": {},
"source": [
"When opened from netCDF this has `dtype=float32`, so there is some kind of issue with CF encoding probably (i.e. that we didn't do any). "
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "a203c20c-f752-4365-88e1-c13832d3e4c9",
"metadata": {},
"outputs": [],
"source": [
"def recreate_zarr_refs(ds: xr.Dataset[KerchunkArray]) -> StoreRefs:\n",
" ds_refs = {\n",
" 'version': 1,\n",
" 'refs': {\n",
" '.zgroup': '{\"zarr_format\":2}'\n",
" }\n",
" }\n",
"\n",
" ds_refs['.zattrs'] = ds.attrs\n",
"\n",
" for name, var in ds.variables.items():\n",
" arr_refs = var.data.arr_refs\n",
" for key in arr_refs:\n",
" ds_refs['refs'][f'{name}/{key}'] = arr_refs[key]\n",
" \n",
" zattrs = var.attrs\n",
" ds_refs['refs'][f'{name}/.zattrs'] = zattrs\n",
"\n",
" return ds_refs"
]
},
{
"cell_type": "code",
"execution_count": 71,
"id": "5c236146-998b-4b00-b0b3-40692fa31018",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'version': 1,\n",
" 'refs': {'.zgroup': '{\"zarr_format\":2}',\n",
" 'air/0.0.0': ['air1.nc', 15419, 3869000],\n",
" 'air/1.0.0': ['air2.nc', 15419, 3869000],\n",
" 'air/.zarray': {'chunks': [1460, 25, 53],\n",
" 'compressor': None,\n",
" 'dtype': '<i2',\n",
" 'fill_value': None,\n",
" 'filters': None,\n",
" 'order': 'C',\n",
" 'shape': [2920, 25, 53],\n",
" 'zarr_format': 2},\n",
" 'air/.zattrs': {'GRIB_id': 11,\n",
" 'GRIB_name': 'TMP',\n",
" '_ARRAY_DIMENSIONS': ['time', 'lat', 'lon'],\n",
" 'actual_range': [185.16000366210938, 322.1000061035156],\n",
" 'dataset': 'NMC Reanalysis',\n",
" 'level_desc': 'Surface',\n",
" 'long_name': '4xDaily Air temperature at sigma level 995',\n",
" 'parent_stat': 'Other',\n",
" 'precision': 2,\n",
" 'scale_factor': 0.01,\n",
" 'statistic': 'Individual Obs',\n",
" 'units': 'degK',\n",
" 'var_desc': 'Air temperature'}},\n",
" '.zattrs': {'Conventions': 'COARDS',\n",
" 'title': '4x daily NMC reanalysis (1948)',\n",
" 'description': 'Data is from NMC initialized reanalysis\\n(4x/day). These are the 0.9950 sigma level values.',\n",
" 'platform': 'Model',\n",
" 'references': 'http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.html'}}"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"recreate_zarr_refs(ds_full_mocked)"
]
},
{
"cell_type": "markdown",
"id": "29c55b1b-50d0-46d4-ad6b-40136dc793be",
"metadata": {},
"source": [
"That's supposed to match `full_refs` (which we obtained the standard `MultiZarrToZarr` way at the start)"
]
},
{
"cell_type": "code",
"execution_count": 72,
"id": "a0599ec7-8a45-4827-ada5-617a6daf5c22",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"{'version': 1,\n",
" 'refs': {'.zgroup': '{\"zarr_format\":2}',\n",
" 'time/.zarray': '{\\n \"chunks\": [\\n 2920\\n ],\\n \"compressor\": {\\n \"id\": \"zstd\",\\n \"level\": 1\\n },\\n \"dtype\": \"<f4\",\\n \"fill_value\": \"NaN\",\\n \"filters\": null,\\n \"order\": \"C\",\\n \"shape\": [\\n 2920\\n ],\\n \"zarr_format\": 2\\n}',\n",
" 'time/0': 'base64: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',\n",
" 'time/.zattrs': '{\\n \"_ARRAY_DIMENSIONS\": [\\n \"time\"\\n ],\\n \"calendar\": \"standard\",\\n \"long_name\": \"Time\",\\n \"standard_name\": \"time\",\\n \"units\": \"hours since 1800-01-01\"\\n}',\n",
" '.zattrs': '{\"Conventions\":\"COARDS\",\"description\":\"Data is from NMC initialized reanalysis\\\\n(4x\\\\/day). These are the 0.9950 sigma level values.\",\"platform\":\"Model\",\"references\":\"http:\\\\/\\\\/www.esrl.noaa.gov\\\\/psd\\\\/data\\\\/gridded\\\\/data.ncep.reanalysis.html\",\"title\":\"4x daily NMC reanalysis (1948)\"}',\n",
" 'air/.zarray': '{\"chunks\":[1460,25,53],\"compressor\":null,\"dtype\":\"<i2\",\"fill_value\":null,\"filters\":null,\"order\":\"C\",\"shape\":[2920,25,53],\"zarr_format\":2}',\n",
" 'air/.zattrs': '{\"GRIB_id\":11,\"GRIB_name\":\"TMP\",\"_ARRAY_DIMENSIONS\":[\"time\",\"lat\",\"lon\"],\"actual_range\":[185.16000366210938,322.1000061035156],\"dataset\":\"NMC Reanalysis\",\"level_desc\":\"Surface\",\"long_name\":\"4xDaily Air temperature at sigma level 995\",\"parent_stat\":\"Other\",\"precision\":2,\"scale_factor\":0.01,\"statistic\":\"Individual Obs\",\"units\":\"degK\",\"var_desc\":\"Air temperature\"}',\n",
" 'air/0.0.0': ['air1.nc', 15419, 3869000],\n",
" 'lat/.zarray': '{\"chunks\":[25],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[25],\"zarr_format\":2}',\n",
" 'lat/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lat\"],\"axis\":\"Y\",\"long_name\":\"Latitude\",\"standard_name\":\"latitude\",\"units\":\"degrees_north\"}',\n",
" 'lat/0': ['air1.nc', 5179, 100],\n",
" 'lon/.zarray': '{\"chunks\":[53],\"compressor\":null,\"dtype\":\"<f4\",\"fill_value\":\"NaN\",\"filters\":null,\"order\":\"C\",\"shape\":[53],\"zarr_format\":2}',\n",
" 'lon/.zattrs': '{\"_ARRAY_DIMENSIONS\":[\"lon\"],\"axis\":\"X\",\"long_name\":\"Longitude\",\"standard_name\":\"longitude\",\"units\":\"degrees_east\"}',\n",
" 'lon/0': ['air1.nc', 5279, 212],\n",
" 'air/1.0.0': ['air2.nc', 15419, 3869000]}}"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"full_refs"
]
},
{
"cell_type": "markdown",
"id": "d099e34b-f015-445c-af37-818771a45438",
"metadata": {},
"source": [
"Okay we're pretty freaking close now - if we just saved this out it should hopefully have achieved basically the same thing as `MultiZarrToZarr`, but using xarray API."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d8a4d2ed-18a8-41ac-b254-3020ad71f59f",
"metadata": {},
"outputs": [],
"source": [
"def kerchunk_ds_to_json(ds: xr.Dataset[KerchunkArray], out_filepath) -> None:\n",
" \n",
" with fs2.open(out_filepath, 'wb') as f:\n",
" f.write(ujson.dumps(ds_refs).encode());"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aa421b36-b929-4692-b909-51034cba2ad8",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment