Skip to main content
fid_showpiece_logo_always_light

A modern, N-dimensional, xarray-based toolbox for Magnetic Resonance Imaging and Spectroscopy.

MyST GitHub Pages Deploy Tests codecov
uv Ruff Python Versions License: BSD 3-Clause

MR data tends to arrive as a bare array plus a pile of numbers you have to keep in your head: which axis is time, how wide the sweep was, what zero means. xmris keeps all of that on the data itself. Your FID stays a plain xarray DataArray — axes named, time in seconds, metadata riding along — and the physics is one accessor away.

spectrum = fid.xmr.to_spectrum().xmr.autophase().xmr.to_ppm()

There is no custom class to learn. Every xarray habit you have keeps working, a whole grid of voxels goes through the same call as a single one, and the spectrum that comes out still knows its ppm axis.

Start with the documentation

andrewendlinger.github.io/xmris

That is where the package really lives. Every tutorial page is a live notebook: the plots and numbers you see come from the code right above them, re-run on every pull request. New here? Basics walks the FID → spectrum → ppm round trip from scratch; Concepts explains why xmris is fussy about names and metadata.

Quick start

The shortest path to something you can look at: simulate_fid hands you a signal that already carries the metadata the physics needs.

import xmris  # importing registers the .xmr accessor on every xarray object

fid = xmris.simulate_fid(
    amplitudes=[1.0, 0.4],
    chemical_shifts=[0.0, 5.2],  # ppm
    reference_frequency=120.66,  # MHz, the Larmor frequency of your nucleus
    n_points=1024,
)

spectrum = (
    fid
    .xmr.apodize_exp(lb=5.0)
    .xmr.zero_fill(target_points=2048)
    .xmr.to_spectrum()
    .xmr.autophase()
    .xmr.to_ppm()
)

print(spectrum.dims)                         # ('chemical_shift',)
print(round(spectrum.attrs["phase_p0"], 2))  # 2.17 — autophase wrote down what it applied

Got your own data? Then you build the DataArray yourself. Four steps, no magic:

import numpy as np
import xarray as xr
import xmris

# Step 1 — the time axis. Space it by your dwell time (here: a 4000 Hz sweep,
# so 1/4000 s per point). This axis alone sets the frequency axis later on —
# there is no separate sweep-width setting to keep in sync.
time = np.arange(1024) / 4000.0  # seconds

# Step 2 — your samples. Any complex array works; here, one fake peak
# 250 Hz off centre, decaying. Stack three copies to play three voxels.
signal = np.exp(2j * np.pi * 250.0 * time - time / 0.05)
data = np.stack([signal, 0.5 * signal, 0.25 * signal])  # (voxel, time)

# Step 3 — wrap it up. Name the dims, attach the time axis, and add the
# two facts only you can know:
fid = xr.DataArray(
    data,
    dims=["voxel", "time"],
    coords={"time": time},
    attrs={
        "reference_frequency": 120.66,  # MHz — your Larmor frequency
        "carrier_ppm": 0.0,             # which ppm sits at 0 Hz (1H water: 4.7)
    },
)

# Step 4 — done. The whole toolbox now works, all voxels at once:
spectrum = fid.xmr.to_spectrum()
print(spectrum.coords["frequency"].values[[0, -1]].tolist())  # [-2000.0, 1996.09375]

ppm = spectrum.xmr.to_ppm()
print(ppm.dims)  # ('voxel', 'chemical_shift')

The 4000 Hz you put into the time axis is the 4000 Hz you get back. Forget reference_frequency or carrier_ppm and to_ppm tells you, by name, before it does any maths — Hz and ppm takes it from here.

What is in the box

  • Processing — zero filling, exponential and Lorentz-to-Gauss apodization, manual and automatic phasing, asymmetric-least-squares baseline correction, FID ↔ spectrum, Hz ↔ ppm.
  • Vendor data — Bruker ParaVision arrays and their parameter dicts become a fully labelled FID, digital-filter group delay included: the one that puts a phase roll through everything if you forget it.
  • Fitting — AMARES quantification via pyAMARES, returning a Dataset with your signal, the fit and the residual aligned.
  • Plots and widgets — matplotlib helpers, plus sliders you can drag to phase, apodize, or scroll through a stack of spectra.

And what is not: xmris is a 0.x package, the MRS side is ahead of the imaging side, Bruker is the only vendor loader so far, and full MRSI grids — lazy, chunked, sitting on an anatomical image — are still to come. Core xmris will not do image reconstruction. The roadmap says what is shipped, what is moving, and what is still being argued about.

Install

pip install xmris             # or: uv add xmris
pip install "xmris[fitting]"  # adds AMARES quantification

Fitting is an extra because deep in its dependencies sits hlsvdpro, which ships no arm64 wheel; the pyamares-xmris repackage on PyPI adds the marker that skips it on Apple Silicon, so the install works there too. All else is in the bare install. Python 3.10 – 3.13.

Contributing

Issues and pull requests are welcome. uv sync --all-extras --dev then uv run test gets you a working checkout; the setup steps, the architecture contract and one page per kind of change are in the contributor guide.

Changelog

Upgrading? The changelog records what changed in each release. There is no CHANGELOG.md here — it is a rendered page, so every entry can link the issue, the pull request, and the docs behind it.

License

xmris is BSD 3-Clause — see LICENSE. Use it, build on it, ship it, paid work or not; just keep the notice.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xmris-0.7.0.tar.gz (109.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xmris-0.7.0-py3-none-any.whl (134.6 kB view details)

Uploaded Python 3

File details

Details for the file xmris-0.7.0.tar.gz.

File metadata

  • Download URL: xmris-0.7.0.tar.gz
  • Upload date:
  • Size: 109.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for xmris-0.7.0.tar.gz
Algorithm Hash digest
SHA256 f62dd5ce3beef4c4ef09488975ee88ae1cf4cb7a34544da36f745b4c73fcc239
MD5 7b19b493990b2decfc8b63bc4ffef3ec
BLAKE2b-256 a5b3016f27e7c7ceb20302e1e7a5bcc662af5267533cb41e177d43cd556a80d4

See more details on using hashes here.

File details

Details for the file xmris-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: xmris-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 134.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for xmris-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 32185f99a12269df24147b8e998508521ab6d7a4c7c52abffc27a6c25f092fba
MD5 22f81c0218dc36604c11b7f106522ca1
BLAKE2b-256 c5e666abb9f962c06b4eff4a40e9c0bddd459ddd7c499bf477def6e9128c4940

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 files

0.6.1

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page