diff --git a/docs/source/changelog.md b/docs/source/changelog.md index a363a1d..cc651e8 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -1,6 +1,18 @@ # Change Log -## v0.10.0 (2025 Feb 19) +## v0.11.0 (2026 Jul 20) +### New features +* Add `linalg.default_dims` context manager {pull}`91` + +### Maintenance and fixes +* Fix `linalg.matrix_transpose` to support inputs with MultiIndex {pull}`90` +* Misc fixes to linalg accessor {pull}`90` + +### Documentation +* Update Code of Conduct and reporting link {pull}`95` +* Add example to Dask support page {pull}`97` + +## v0.10.0 (2026 Feb 19) ### Maintenance and fixes * Remove leftover print in `pinv` {pull}`87` * Update minimum dependency versions {pull}`88` diff --git a/docs/source/tutorials/dask_support.ipynb b/docs/source/tutorials/dask_support.ipynb new file mode 100644 index 0000000..bd90157 --- /dev/null +++ b/docs/source/tutorials/dask_support.ipynb @@ -0,0 +1,1476 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "84bf8d8e-0536-4673-82be-55b6897627d6", + "metadata": {}, + "source": [ + "# Dask support\n", + "Like xarray, xarray-einstats also aims to support using their functions on\n", + "NumPy or Dask backed xarray objects.\n", + "\n", + "Functions in xarray-einstats should support Dask backed xarray objects.\n", + "But Dask support is still not extensively tested.\n", + "If you have issues using Dask backed xarray objects please open an [issue](https://github.com/arviz-devs/xarray-einstats)\n", + "\n", + "Dask support within xarray-einstats requires explicit activation by users, exactly like it happens with {func}`xarray.apply_ufunc`.\n", + "In fact, what is happening is xarray-einstats forwards any unrecognized keyword argument (e.g. `dask` or `dask_gufunc_kwargs`) to `apply_ufunc`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b373d879-c129-4441-9186-d4f98ddcb699", + "metadata": {}, + "outputs": [], + "source": [ + "import dask.array as da\n", + "import xarray as xr\n", + "from xarray_einstats import linalg\n", + "\n", + "xr.set_options(display_expand_data=False);" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e3daba12-78f5-473f-b9fc-71665434ec34", + "metadata": {}, + "outputs": [], + "source": [ + "matrix_batch = xr.DataArray(da.random.normal(size=(1000, 77, 77), chunks=\"auto\"), dims=[\"batch\", \"dim1\", \"dim2\"])" + ] + }, + { + "cell_type": "markdown", + "id": "724165af-0437-423f-8c22-3c0f5980eb52", + "metadata": {}, + "source": [ + "Trying to use xarray-einstats functions directly on Dask arrays triggers an error:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "02bdc253-ff87-4481-979a-1db478f093d4", + "metadata": { + "deletable": true, + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-output" + ] + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "apply_ufunc encountered a chunked array on an argument, but handling for chunked arrays has not been enabled. Either set the ``dask`` argument or load your data into memory first with ``.load()`` or ``.compute()``", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m linalg.norm(matrix_batch, dims=[\u001b[33m\"dim1\"\u001b[39m, \u001b[33m\"dim2\"\u001b[39m])\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Documents/repos_oss/xarray-einstats/src/xarray_einstats/linalg.py:801\u001b[39m, in \u001b[36mnorm\u001b[39m\u001b[34m(da, dims, ord, **kwargs)\u001b[39m\n\u001b[32m 799\u001b[39m in_dims = dims\n\u001b[32m 800\u001b[39m norm_kwargs[\u001b[33m\"\u001b[39m\u001b[33maxis\u001b[39m\u001b[33m\"\u001b[39m] = (-\u001b[32m2\u001b[39m, -\u001b[32m1\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m801\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mxr\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mapply_ufunc\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 802\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mnp\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mlinalg\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mnorm\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mda\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43minput_core_dims\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m[\u001b[39;49m\u001b[30;43min_dims\u001b[39;49m\u001b[30;43m]\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mnorm_kwargs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\n\u001b[32m 803\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/bin/miniforge3/envs/general/lib/python3.14/site-packages/xarray/computation/apply_ufunc.py:1267\u001b[39m, in \u001b[36mapply_ufunc\u001b[39m\u001b[34m(func, input_core_dims, output_core_dims, exclude_dims, vectorize, join, dataset_join, dataset_fill_value, keep_attrs, kwargs, dask, output_dtypes, output_sizes, meta, dask_gufunc_kwargs, on_missing_core_dim, *args)\u001b[39m\n\u001b[32m 1265\u001b[39m \u001b[38;5;66;03m# feed DataArray apply_variable_ufunc through apply_dataarray_vfunc\u001b[39;00m\n\u001b[32m 1266\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(a, DataArray) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m args):\n\u001b[32m-> \u001b[39m\u001b[32m1267\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mapply_dataarray_vfunc\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 1268\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mvariables_vfunc\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1269\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1270\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43msignature\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43msignature\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1271\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mjoin\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mjoin\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1272\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mexclude_dims\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mexclude_dims\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1273\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mkeep_attrs\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mkeep_attrs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 1274\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 1275\u001b[39m \u001b[38;5;66;03m# feed Variables directly through apply_variable_ufunc\u001b[39;00m\n\u001b[32m 1276\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(a, Variable) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m args):\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/bin/miniforge3/envs/general/lib/python3.14/site-packages/xarray/computation/apply_ufunc.py:312\u001b[39m, in \u001b[36mapply_dataarray_vfunc\u001b[39m\u001b[34m(func, signature, join, exclude_dims, keep_attrs, *args)\u001b[39m\n\u001b[32m 307\u001b[39m result_coords, result_indexes = build_output_coords_and_indexes(\n\u001b[32m 308\u001b[39m args, signature, exclude_dims, combine_attrs=keep_attrs\n\u001b[32m 309\u001b[39m )\n\u001b[32m 311\u001b[39m data_vars = [\u001b[38;5;28mgetattr\u001b[39m(a, \u001b[33m\"\u001b[39m\u001b[33mvariable\u001b[39m\u001b[33m\"\u001b[39m, a) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m args]\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m result_var = \u001b[30;43mfunc\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mdata_vars\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 314\u001b[39m out: \u001b[38;5;28mtuple\u001b[39m[DataArray, ...] | DataArray\n\u001b[32m 315\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m signature.num_outputs > \u001b[32m1\u001b[39m:\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/bin/miniforge3/envs/general/lib/python3.14/site-packages/xarray/computation/apply_ufunc.py:741\u001b[39m, in \u001b[36mapply_variable_ufunc\u001b[39m\u001b[34m(func, signature, exclude_dims, dask, output_dtypes, vectorize, keep_attrs, dask_gufunc_kwargs, *args)\u001b[39m\n\u001b[32m 739\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28many\u001b[39m(is_chunked_array(array) \u001b[38;5;28;01mfor\u001b[39;00m array \u001b[38;5;129;01min\u001b[39;00m input_data):\n\u001b[32m 740\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m dask == \u001b[33m\"\u001b[39m\u001b[33mforbidden\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m741\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 742\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mapply_ufunc encountered a chunked array on an \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 743\u001b[39m \u001b[33m\"\u001b[39m\u001b[33margument, but handling for chunked arrays has not \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 744\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mbeen enabled. Either set the ``dask`` argument \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 745\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mor load your data into memory first with \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 746\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m``.load()`` or ``.compute()``\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 747\u001b[39m )\n\u001b[32m 748\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m dask == \u001b[33m\"\u001b[39m\u001b[33mparallelized\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 749\u001b[39m chunkmanager = get_chunked_array_type(*input_data)\n", + "\u001b[31mValueError\u001b[39m: apply_ufunc encountered a chunked array on an argument, but handling for chunked arrays has not been enabled. Either set the ``dask`` argument or load your data into memory first with ``.load()`` or ``.compute()``" + ] + } + ], + "source": [ + "linalg.norm(matrix_batch, dims=[\"dim1\", \"dim2\"])" + ] + }, + { + "cell_type": "markdown", + "id": "298e23b9-d271-4e68-a2c2-02dd661eb8bc", + "metadata": { + "deletable": true, + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "We need to allow dask inputs through `dask=\"allowed\"` or `dask=\"parallelized\"`. In general, `allowed` is preferred, but it only works if there is a Dask implementation of the requested function available, `parallelized` works in most cases but is usually slower and still not a silver bullet. Consequently, xarray-einstats does not set the `dask` argument automatically when the input is a dask array, and finding which of the two will work and be better might require a bit of trial an error an also be dependent on the Dask version available.\n", + "\n", + "Here is one example with `linalg.norm` for which both alternatives work:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b03c96a5-23b7-4fde-8ee9-b56911559a19", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Array Chunk
Bytes 7.81 kiB 7.81 kiB
Shape (1000,) (1000,)
Dask graph 1 chunks in 6 graph layers
Data type float64 numpy.ndarray
\n", + "
\n", + " \n", + "\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " 1000\n", + " 1\n", + "\n", + "
" + ], + "text/plain": [ + "dask.array" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "norms = linalg.norm(matrix_batch, dims=[\"dim1\", \"dim2\"], dask=\"allowed\")\n", + "norms.data" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "3287e425-a7da-4756-87d9-1b9b43e7bad5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'normal-758a57bb75ed3127c94212c3e83a5ed8' (batch: 1000)> Size: 8kB\n",
+       "77.07 77.61 76.86 77.53 77.99 77.22 76.9 ... 77.92 78.03 77.96 76.6 77.31 76.26\n",
+       "Dimensions without coordinates: batch
" + ], + "text/plain": [ + " Size: 8kB\n", + "77.07 77.61 76.86 77.53 77.99 77.22 76.9 ... 77.92 78.03 77.96 76.6 77.31 76.26\n", + "Dimensions without coordinates: batch" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "norms.compute()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b19b98df-3256-443f-b6e4-6501d76b6bc1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'normal-758a57bb75ed3127c94212c3e83a5ed8' (batch: 1000)> Size: 8kB\n",
+       "77.07 77.61 76.86 77.53 77.99 77.22 76.9 ... 77.92 78.03 77.96 76.6 77.31 76.26\n",
+       "Dimensions without coordinates: batch
" + ], + "text/plain": [ + " Size: 8kB\n", + "77.07 77.61 76.86 77.53 77.99 77.22 76.9 ... 77.92 78.03 77.96 76.6 77.31 76.26\n", + "Dimensions without coordinates: batch" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "linalg.norm(matrix_batch, dims=[\"dim1\", \"dim2\"], dask=\"parallelized\").compute()" + ] + }, + { + "cell_type": "markdown", + "id": "0d03e25c-c592-414e-869f-efd2bf033dc1", + "metadata": {}, + "source": [ + ":::{seealso}\n", + "{ref}`Xarray documentation `\n", + "\n", + "[Dask examples](https://examples.dask.org/xarray.html)\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c336f026-9460-4ee8-bbd4-d3343ae4ddcb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Last updated: Mon, 20 Jul 2026\n", + "\n", + "Python implementation: CPython\n", + "Python version : 3.14.6\n", + "IPython version : 9.15.0\n", + "\n", + "dask : 2026.7.1\n", + "xarray : 2026.7.0\n", + "xarray_einstats: 0.11.0\n", + "\n", + "Watermark: 2.6.0\n", + "\n" + ] + } + ], + "source": [ + "%load_ext watermark\n", + "%watermark -n -u -v -iv -w" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb4ffe5e-7f62-4523-8974-d5db0f26aaa0", + "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.14.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/tutorials/dask_support.md b/docs/source/tutorials/dask_support.md deleted file mode 100644 index 044b770..0000000 --- a/docs/source/tutorials/dask_support.md +++ /dev/null @@ -1,13 +0,0 @@ -# Dask support -Like xarray, xarray-einstats also aims to support using their functions on -NumPy or Dask backed xarray objects. - -Functions in xarray-einstats should support Dask backed xarray objects. -But Dask support is still not extensively tested. -If you have issues using Dask backed xarray objects please open an [issue](https://github.com/arviz-devs/xarray-einstats) - -:::{seealso} -{ref}`Xarray documentation ` - -[Dask examples](https://examples.dask.org/xarray.html) -::: diff --git a/docs/source/tutorials/einops-basics-port.ipynb b/docs/source/tutorials/einops-basics-port.ipynb index 5424e55..4e8398c 100644 --- a/docs/source/tutorials/einops-basics-port.ipynb +++ b/docs/source/tutorials/einops-basics-port.ipynb @@ -187,6 +187,7 @@ " min-width: 300px;\n", " max-width: 700px;\n", " line-height: 1.6;\n", + " padding-bottom: 4px;\n", "}\n", "\n", ".xr-text-repr-fallback {\n", @@ -197,8 +198,11 @@ ".xr-header {\n", " padding-top: 6px;\n", " padding-bottom: 6px;\n", - " margin-bottom: 4px;\n", + "}\n", + "\n", + ".xr-header {\n", " border-bottom: solid 1px var(--xr-border-color);\n", + " margin-bottom: 4px;\n", "}\n", "\n", ".xr-header > div,\n", @@ -209,20 +213,15 @@ "}\n", "\n", ".xr-obj-type,\n", - ".xr-obj-name,\n", - ".xr-group-name {\n", + ".xr-obj-name {\n", " margin-left: 2px;\n", " margin-right: 10px;\n", "}\n", "\n", - ".xr-group-name::before {\n", - " content: \"📁\";\n", - " padding-right: 0.3em;\n", - "}\n", - "\n", - ".xr-group-name,\n", - ".xr-obj-type {\n", + ".xr-obj-type,\n", + ".xr-group-box-contents > label {\n", " color: var(--xr-font-color2);\n", + " display: block;\n", "}\n", "\n", ".xr-sections {\n", @@ -237,28 +236,39 @@ " display: contents;\n", "}\n", "\n", - ".xr-section-item input {\n", - " display: inline-block;\n", + ".xr-section-item > input,\n", + ".xr-group-box-contents > input,\n", + ".xr-array-wrap > input {\n", + " display: block;\n", " opacity: 0;\n", " height: 0;\n", " margin: 0;\n", "}\n", "\n", - ".xr-section-item input + label {\n", + ".xr-section-item > input + label,\n", + ".xr-var-item > input + label {\n", " color: var(--xr-disabled-color);\n", - " border: 2px solid transparent !important;\n", "}\n", "\n", - ".xr-section-item input:enabled + label {\n", + ".xr-section-item > input:enabled + label,\n", + ".xr-var-item > input:enabled + label,\n", + ".xr-array-wrap > input:enabled + label,\n", + ".xr-group-box-contents > input:enabled + label {\n", " cursor: pointer;\n", " color: var(--xr-font-color2);\n", "}\n", "\n", - ".xr-section-item input:focus + label {\n", - " border: 2px solid var(--xr-font-color0) !important;\n", + ".xr-section-item > input:focus-visible + label,\n", + ".xr-var-item > input:focus-visible + label,\n", + ".xr-array-wrap > input:focus-visible + label,\n", + ".xr-group-box-contents > input:focus-visible + label {\n", + " outline: auto;\n", "}\n", "\n", - ".xr-section-item input:enabled + label:hover {\n", + ".xr-section-item > input:enabled + label:hover,\n", + ".xr-var-item > input:enabled + label:hover,\n", + ".xr-array-wrap > input:enabled + label:hover,\n", + ".xr-group-box-contents > input:enabled + label:hover {\n", " color: var(--xr-font-color0);\n", "}\n", "\n", @@ -266,11 +276,25 @@ " grid-column: 1;\n", " color: var(--xr-font-color2);\n", " font-weight: 500;\n", + " white-space: nowrap;\n", + "}\n", + "\n", + ".xr-section-summary > em {\n", + " font-weight: normal;\n", + "}\n", + "\n", + ".xr-span-grid {\n", + " grid-column-end: -1;\n", "}\n", "\n", ".xr-section-summary > span {\n", " display: inline-block;\n", - " padding-left: 0.5em;\n", + " padding-left: 0.3em;\n", + "}\n", + "\n", + ".xr-group-box-contents > input:checked + label > span {\n", + " display: inline-block;\n", + " padding-left: 0.6em;\n", "}\n", "\n", ".xr-section-summary-in:disabled + label {\n", @@ -298,7 +322,8 @@ "}\n", "\n", ".xr-section-summary,\n", - ".xr-section-inline-details {\n", + ".xr-section-inline-details,\n", + ".xr-group-box-contents > label {\n", " padding-top: 4px;\n", "}\n", "\n", @@ -307,20 +332,29 @@ "}\n", "\n", ".xr-section-details {\n", - " display: none;\n", " grid-column: 1 / -1;\n", " margin-top: 4px;\n", " margin-bottom: 5px;\n", "}\n", "\n", + ".xr-section-summary-in ~ .xr-section-details {\n", + " display: none;\n", + "}\n", + "\n", ".xr-section-summary-in:checked ~ .xr-section-details {\n", " display: contents;\n", "}\n", "\n", + ".xr-children {\n", + " display: inline-grid;\n", + " grid-template-columns: 100%;\n", + " grid-column: 1 / -1;\n", + " padding-top: 4px;\n", + "}\n", + "\n", ".xr-group-box {\n", " display: inline-grid;\n", - " grid-template-columns: 0px 20px auto;\n", - " width: 100%;\n", + " grid-template-columns: 0px 30px auto;\n", "}\n", "\n", ".xr-group-box-vline {\n", @@ -334,13 +368,43 @@ " grid-column-start: 2;\n", " grid-row-start: 1;\n", " height: 1em;\n", - " width: 20px;\n", + " width: 26px;\n", " border-bottom: 0.2em solid;\n", " border-color: var(--xr-border-color);\n", "}\n", "\n", ".xr-group-box-contents {\n", " grid-column-start: 3;\n", + " padding-bottom: 4px;\n", + "}\n", + "\n", + ".xr-group-box-contents > label::before {\n", + " content: \"📂\";\n", + " padding-right: 0.3em;\n", + "}\n", + "\n", + ".xr-group-box-contents > input:checked + label::before {\n", + " content: \"📁\";\n", + "}\n", + "\n", + ".xr-group-box-contents > input:checked + label {\n", + " padding-bottom: 0px;\n", + "}\n", + "\n", + ".xr-group-box-contents > input:checked ~ .xr-sections {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-group-box-contents > input + label > span {\n", + " display: none;\n", + "}\n", + "\n", + ".xr-group-box-ellipsis {\n", + " font-size: 1.4em;\n", + " font-weight: 900;\n", + " color: var(--xr-font-color2);\n", + " letter-spacing: 0.15em;\n", + " cursor: default;\n", "}\n", "\n", ".xr-array-wrap {\n", @@ -574,7 +638,7 @@ "Dimensions: (batch: 6, height: 96, width: 96, channel: 3)\n", "Dimensions without coordinates: batch, height, width, channel\n", "Data variables:\n", - " ims (batch, height, width, channel) float64 1MB 1.0 0.902 ... 0.8039" ], "text/plain": [ " Size: 32B\n", @@ -6232,19 +6936,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "Last updated: Thu, 19 Feb 2026\n", + "Last updated: Mon, 20 Jul 2026\n", "\n", "Python implementation: CPython\n", - "Python version : 3.13.9\n", - "IPython version : 9.7.0\n", + "Python version : 3.14.6\n", + "IPython version : 9.15.0\n", "\n", - "xarray_einstats: 0.10.0\n", - "xarray : 2025.11.0\n", + "xarray_einstats: 0.11.0\n", + "xarray : 2026.7.0\n", "\n", - "matplotlib : 3.10.8\n", - "numpy : 2.3.5\n", - "scipy : 1.16.3\n", - "xarray_einstats: 0.10.0\n", + "matplotlib : 3.11.1\n", + "numpy : 2.5.1\n", + "scipy : 1.18.0\n", + "xarray_einstats: 0.11.0\n", "\n", "Watermark: 2.6.0\n", "\n" @@ -6281,7 +6985,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.9" + "version": "3.14.6" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 2f7f2dc..4d5f0d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", @@ -28,8 +27,8 @@ classifiers = [ dynamic = ["version"] dependencies = [ "numpy>=2.0", - "scipy>=1.13", - "xarray>=2024.02.0", + "scipy>=1.14", + "xarray>=2024.07.0", ] [tool.flit.module] diff --git a/src/xarray_einstats/__init__.py b/src/xarray_einstats/__init__.py index 1b6da71..a08eff6 100644 --- a/src/xarray_einstats/__init__.py +++ b/src/xarray_einstats/__init__.py @@ -19,7 +19,7 @@ "EinopsAccessor", ] -__version__ = "0.10.0" +__version__ = "0.11.0" def sort(da, dim, kind=None, stable=None, **kwargs):