XREXPR: Xarray Expression Rewriter
Imagine you have an xarray dataset that you want to do some analysis on. You might write something like this:
%%timeit
ds.mean(dim="lat").mean(dim="lon").isel(time=0).compute()
193 ms ± 49.6 ms per loop (mean ± std. dev. of 5 runs, 5 loops each)
However, it would be a lot faster if you instead wrote:
ds.isel(time=0).mean(dim="lat").mean(dim="lon").compute()
925 μs ± 401 μs per loop (mean ± std. dev. of 5 runs, 5 loops each)
In this instance, just reordering the operations makes a ~200x performance difference. We can see that these two expressions are equivalent, but unfortunately, xarray can't automatically reorder them for us (yet?).
from xarray.testing import assert_equal
assert_equal(
ds.isel(time=0).mean(dim="lat").mean(dim="lon"),
ds.mean(dim="lat").mean(dim="lon").isel(time=0),
)
# Does not raise an AssertionError
That's where xrexpr comes in. Importing it registers a .plan accessor on every
Dataset. Chain your operations off ds.plan exactly as you would off ds — but
instead of running eagerly, each call is recorded. Calling .collect() optimises the
recorded plan (reordering and merging where it's provably safe) and replays it:
import xrexpr # registers the ``.plan`` accessor
result = ds.plan.mean(dim="lat").mean(dim="lon").isel(time=0).collect()
(.compute() is a synonym for .collect(), if that's the terminal your fingers reach for.)
xrexpr pushes the isel in front of the reductions for you, so .collect() runs the
fast ordering while you keep writing the readable one. The result is exactly what the
eager chain would have produced:
assert_equal(result, ds.mean(dim="lat").mean(dim="lon").isel(time=0)).compute()
Seeing the rewrite
Use .explain() to see the optimised plan without running it:
>>> print(ds.plan.mean(dim="lat").mean(dim="lon").isel(time=0).explain())
plan (3 ops):
1. isel(time=0)
2. mean(dim='lat')
3. mean(dim='lon')
The isel has been hoisted to the front — that's the reorder that buys the speed-up.
How it optimises
xrexpr records each call as a normalised operation against a cheap logical schema
(dims and sizes, never the array data), then rewrites the plan to a fixpoint with a few
local, result-preserving rules:
- merge consecutive
isel/selselections into a single indexer; - push a selection left past any reduction (
mean,sum,std, ...) whose dims it doesn't touch, so the reduction scans a smaller array.
A selection that indexes a dimension a reduction has already removed can never run — for
example ds.plan.mean(dim="lon").isel(lon=0) — so xrexpr raises
InvalidExpressionError at .collect() (or .explain()) instead of failing deep inside
xarray:
from xrexpr import InvalidExpressionError
try:
ds.plan.mean(dim="lon").isel(lon=0).collect()
except InvalidExpressionError:
...
Scans (cumsum, cumprod, diff) are order-sensitive, so a selection on the scanned
dimension is left exactly where you put it.
This package is just making its way out of the proof-of-concept stage, so expect some issues. It is also unlikely to support the full range of xarray operations for some time. If it doesn't do anything for you, please open an issue!
Release files for xrexpr 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| xrexpr-0.1.1.tar.gz | 40.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xrexpr-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:54.7 kB
Release files / xrexpr-0.1.1.tar.gz
| Download URL | xrexpr-0.1.1.tar.gz |
|---|---|
| Size | 40.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
604da66c67081e9b98146095b6ec3aeb8a09b42e59d5f02c6b46826ede003c33
|
|
BLAKE2b-256 checksum How to use checksums |
e542df0513fce5883a0786b89058d078ccb8296025d4adc08cf3fc0756848f8a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.
Transparency logRelease files / xrexpr-0.1.1-py3-none-any.whl
| Download URL | xrexpr-0.1.1-py3-none-any.whl |
|---|---|
| Size | 14.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2f088fa842092b6d7e678d57bd5c42b3d51ab8a344b0859bbb5aacaab0eeb83
|
|
BLAKE2b-256 checksum How to use checksums |
b65acdda0b37f4184f6a9a9d98e03b28b814c4229c910dc9fcaf8baa7d262170
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.
Transparency log