Getting started#
Installing#
pip install larmor-dmri
The viewer needs pip install "larmor-dmri[viewer]". Install has the details: uv, building
from source and GPUs.
The example data#
This page works on the simulated brain of the ISMRM 2015 Tractography Challenge, one of the
example datasets: diffusion images at 2 mm with one b=0 image and 32 directions at b=1000
s/mm^2, and a T1-like image. fetch_ismrm2015() downloads it once (41 MB) into a cache
folder. The lines below save the diffusion image with its gradient table in the current folder, as a MIF file,
which holds the table in its header, and copy the T1-like image beside it:
import shutil
from larmor.data import fetch_ismrm2015
from larmor.io import load_dwi, save_volume
files = fetch_ismrm2015()
dwi, gtab = load_dwi(files["dwi"], files["bvals"], files["bvecs"])
save_volume(dwi, "dwi.mif", gradients=gtab)
shutil.copy(files["t1"], "t1.nii.gz")
Save them as a script, get_data.py, and run it with python get_data.py. Please cite the dataset if you use it:
Maier-Hein KH et al. The challenge of mapping the human connectome based on diffusion tractography. Nature
Communications 8 (2017) 1349.
A first command-line run#
The command line, lar, lists its commands with lar --help, and each command its options with
lar <command> --help; the command-line reference describes them all. A short summary of a file:
lar info dwi.mif
prints its shape, voxel size, orientation and affine, and for this file the number of b=0 images and the shells. A brain mask, then the DTI maps inside it:
lar mask dwi.mif mask.nii.gz
lar dti dwi.mif dti -m mask.nii.gz
lar dti writes dti_fa.nii.gz, dti_md.nii.gz, dti_ad.nii.gz, dti_rd.nii.gz and dti_pe.nii.gz. A
command does not overwrite existing files unless given --force.
A first Python script#
The same in Python: the mask from the mean b=0 image, the tensor fit, and the mean FA of the white matter.
from larmor.dwi import DTIModel, create_brain_mask, mean_b0
from larmor.io import load_dwi, save_volume
dwi, gtab = load_dwi("dwi.mif")
mask = create_brain_mask(mean_b0(dwi, gtab))
fit = DTIModel().fit(dwi, gtab, mask=mask)
print(f"Mean FA where it is above 0.3: {fit.fa[fit.fa > 0.3].mean():.2f}")
save_volume(dwi.with_data(fit.fa), "fa.nii.gz")
The user guide has a page for each task, with its Python and command-line versions, and the gallery has longer examples, each with its output and images.
A first viewer session#
The viewer, BrainViewer, opens with lar bv. Files are given by category, each option repeated for several
files; here the T1-like image as a volume and the FA map as an overlay over it:
lar bv -v t1.nii.gz -o dti_fa.nii.gz
The Layers panel on the left lists the loaded items, and the Options panel on the right sets the options of the selected one, such as its colormap and opacity. Clicking or dragging in a 2D view moves the crosshair there. The viewer’s guide describes the window, and its other pages each kind of item.
From Python, view opens the same window on paths or on objects already in memory, without copying them:
from larmor.io import load_volume
from larmor.viewer import view
t1 = load_volume("t1.nii.gz")
viewer = view(volumes=t1, overlays="dti_fa.nii.gz")
It returns when the window is closed. In IPython or Jupyter, run %gui qt first and pass block=False to keep
working while the window is open; viewer then changes what it shows (viewer.set(...), viewer.load(...)).
A Viewer also draws screenshots with no window, for scripts and servers without a display; the
gallery shows the viewer’s features this way:
from larmor.viewer import Category, Viewer, ViewKind
viewer = Viewer()
viewer.load("t1.nii.gz", Category.VOLUMES)
viewer.load("dti_fa.nii.gz", Category.OVERLAYS)
viewer.screenshot(ViewKind.AXIAL, "axial.png", size=(600, 600))
Files can also be opened with File > Open, whose file-type choice is the category, or dragged from the file manager onto a category in the Layers panel.
Using the viewer on a Linux server#
On a remote Linux server, connect with X forwarding, ssh -X (MobaXterm on Windows does this by default), and run
lar bv there: the server’s GPU draws the views and only the finished images travel to your screen. If dragging
feels slow, turn on Lower resolution while moving in the Settings panel.
Qt needs some X libraries that servers often lack. When one is missing, lar bv names it and the package to
install. With
administrator rights, on Debian or Ubuntu:
sudo apt install libxcb1 libx11-6 libx11-xcb1 libsm6 libice6 libxkbcommon0 libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-util1 libxcb-xinerama0 libxcb-xkb1 libxcb-randr0 libxcb-shape0 libxcb-xfixes0 libxcb-sync1 libxcb-shm0 libxcb-glx0 libxcb-render0
Without administrator rights, download the same packages into a folder in your home directory and unpack them there:
mkdir -p ~/.local/qt-libs && cd ~/.local/qt-libs && for p in libxcb1 libx11-6 libx11-xcb1 libsm6 libice6 libxkbcommon0 libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-util1 libxcb-xinerama0 libxcb-xkb1 libxcb-randr0 libxcb-shape0 libxcb-xfixes0 libxcb-sync1 libxcb-shm0 libxcb-glx0 libxcb-render0; do apt download $p; done; for f in *.deb; do dpkg -x $f .; done
Then start the viewer with the folder on the library path:
LD_LIBRARY_PATH=$HOME/.local/qt-libs/usr/lib/x86_64-linux-gnu lar bv
Driving the viewer from an agent#
An agent (Claude Code, or any client of the Model Context Protocol, MCP) can drive a running viewer: load files, change options, move the cursor, turn the cameras and take screenshots. Start the viewer with its MCP server:
lar bv --mcp
or turn on Serve agents in the Settings panel. The viewer prints the server’s URL and a token:
Serving agents (MCP) at http://127.0.0.1:8765/mcp
Token: 9f3K...
The server listens on this computer only, and refuses any request without the token, so other users of a shared server cannot reach it. The token stays the same across restarts until New token in Settings replaces it. Give both to the agent; for Claude Code, once:
claude mcp add --transport http Larmor http://127.0.0.1:8765/mcp --header "Authorization: Bearer 9f3K..."
Each of the viewer’s actions is one tool, described by its docstring, and the scene tool lists the loaded
items and their ids. --mcp-port (or the port in Settings) changes the port from 8765.
When the agent runs on another computer than the viewer, forward the port over SSH from the agent’s computer,
with the same port on both sides (the server only answers at its own port), and keep the URL as it is. Paths
given to tools (load, screenshot) are on the viewer’s computer, not the agent’s.
ssh -L 8765:127.0.0.1:8765 user@server