Welcome! xmris is built on a strict “xarray in, xarray out” philosophy. Our goal is to make MR imaging and spectroscopy processing functional, robust, and N-dimensional.
To keep the codebase clean and the documentation pristine, we follow a modern “docs-as-tests” pipeline using MyST, quartodoc, and uv.
Step 1: Write the Standalone Function¶
Functions live in specific, nested domain modules (e.g., xmris.processing.fid, xmris.vendor.bruker). Respect the physical domain: if an operation is a frequency-domain manipulation, it belongs in xmris.processing.phase or fourier, not mixed into time-domain FID scripts.
Xarray First: The first argument must be
da: xr.DataArray. Always return a newxr.DataArray.Use the
DEFAULTSConfig: Never hardcode dimension or attribute names. Default your signature arguments toNoneand fall back to the globalDEFAULTSobject fromxmris.config.Data Lineage (Crucial): Always pass along existing coordinates and attributes. Append new processing parameters to the
.attrsdictionary to preserve the processing history.Type Hinting & Docstrings: Fully type-hint signatures and use standard NumPy format docstrings. These are the source of truth for our online API docs generated by
quartodoc.
from xmris.config import DEFAULTS
def my_func(da: xr.DataArray, dim: str | None = None, my_param: float = 1.0) -> xr.DataArray:
"""Description for the API docs."""
# 0. Fallback to global config
dim = dim or DEFAULTS.time.dim
# ... mathematical operations ...
# 1. Update data
da_new = da.copy(data=new_vals)
# 2. Preserve lineage by logging new parameters
new_attrs = da.attrs.copy()
new_attrs.update({"my_param_used": my_param})
return da_new.assign_attrs(new_attrs)
Step 2: Register the Accessor¶
Expose your function through the .xmr namespace in src/xmris/accessor.py. This allows users to chain methods cleanly: da.xmr.fft().xmr.my_func(). Ensure the method signature matches your standalone function exactly.
Step 3: Create the Tutorial-Test (Jupytext)¶
We don’t use standard test_*.py files. Your tutorials are the test suite. Create a Python script in notebooks/ using the Jupytext percent format (# %%).
Explain & Demonstrate: Explain the math/physics and show the function in action with
matplotlib.Verify Math & Metadata: Use
assertstatements to prove the math is correct, but also assert that dimensions, coordinates, and attributes were preserved.Hide Tests: Add
# %% tags=["remove-cell"]to assertion cells. This ensurespytest --nbmakechecks them during CI/CD, but the generated website stays clean for readers.
Step 4: Update the Build Pipeline¶
API Docs: Run
uv run docs-api. This triggersquartodocto scrape your new function’s docstring into the API Reference.Navigation: Add your new tutorial to the
navsection inmyst.yml.Verify Build: Run
uv run docsto ensure the site renders correctly.
Step 5: Tests¶
Run tests: Run
uv run pytestto run all notebooks in testmode usingnbmake.