2025, Nov 26 01:00
Map NumPy x, y, z to Anatomy in NIfTI: NiBabel Affine, RAS Codes, and MSD Task 01
Align NumPy axes with anatomical X, Y, Z in NIfTI using NiBabel. Read shapes, affines and RAS codes to avoid flipped imaging and validate MSD Task 01 volumes.
Understanding which array axes correspond to anatomical x, y, and z in 3D/4D neuroimaging volumes is a common stumbling block. With MSD Task 01 (Brain Segmentation) data in NIfTI format and NiBabel, the shape and affine tell you what you need, but only if you read them in the right order.
Example that surfaces the question
The following snippet loads a volume and prints the essentials. The shape and affine match the case where the array has three spatial axes plus a fourth dimension.
import nibabel as nbl
file_path = "/kaggle/input/msd-dataset-task-1-brain-tumour segmentation/Task01_BrainTumour/imagesTr/BRATS_001.nii"
vol_nii = nbl.load(file_path)
print("File:", file_path)
print("Shape:", vol_nii.shape)
print("Data type:", vol_nii.get_data_dtype())
print("Voxel spacing:", vol_nii.header.get_zooms())
print("Affine matrix:\n", vol_nii.affine)
File: /kaggle/input/msd-dataset-task-1-brain-tumour-segmentation/Task01_BrainTumour/imagesTr/BRATS_001.nii
Shape: (240, 240, 155, 4)
Data type: float32
Voxel spacing: (1.0, 1.0, 1.0, 1.0)
Affine matrix:
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
What the axes actually mean
In NumPy, x, y, z map to the first, second, and third array axes, respectively. In anatomy, the conventional interpretation is x for left/right, y for front/back, and z for top/bottom. Those anatomical directions are defined by the affine and the orientation codes it implies. A common convention is RAS, where the positive axes point Right, Anterior, and Superior. Different scanners or preprocessing steps may choose different conventions, which is why reading the affine is essential.
NiBabel’s documentation on Coordinate Systems and Affines and Working with NIfTI Images is an excellent reference when reconciling array indices with anatomical orientation.
A practical way to inspect axes and orientation
A quick visualization helps build intuition about which dimension you are slicing. The following example mirrors the approach above: load, pick the first volume from a 4D array, and show center slices for each NumPy axis.
import numpy as np
import nibabel as nbl
import matplotlib.pyplot as plt
src_path = "/kaggle/input/msd-dataset-task-1-brain-tumour segmentation/Task01_BrainTumour/imagesTr/BRATS_001.nii"
nii_obj = nbl.load(src_path)
arr_4d = nii_obj.get_fdata() # x, y, z, t (time most likely with neuroimaging)
vol_3d = arr_4d[..., 0] # use the first 3D volume
cx, cy, cz = (np.array(vol_3d.shape[:3]) // 2).tolist()
def render_planes(planes, names=("x", "y", "z")):
fig, axs = plt.subplots(1, len(planes))
for idx, plane in enumerate(planes):
axs[idx].imshow(plane.T, cmap="gray", origin="lower")
axs[idx].set_title(f"Numpy axis {names[idx]}")
plt.suptitle("Center slices for image")
planes = [vol_3d[cx, :, :], vol_3d[:, cy, :], vol_3d[:, :, cz]]
render_planes(planes)
plt.show()
To see the orientation labels that the affine implies, query them directly:
# Affine matrix
print(nii_obj.affine)
# Orientation codes (e.g., RAS)
print(nbl.aff2axcodes(nii_obj.affine))
Why the confusion happens
The array order alone tells you which axis is first, second, and third, but not the anatomical meaning of increasing indices along those axes. The affine is the bridge between voxel indices and real-world space, and from it NiBabel can infer orientation codes. A 4D shape like (240, 240, 155, 4) is thus read as x, y, z, and a fourth dimension, with the spatial orientation determined by the affine.
Dataset note that helps
The dataset’s paper for the Medical Segmentation Decathlon states:
“All images were transposed (without resampling) to the most approximate right-anterior-superior coordinate frame, ensuring the data matrix x-y-z direction was consistent (using fslreorient2std) and converted to the NIFTI radiological standard.”
Given that statement and the code above, you can treat the first three axes of the loaded array as x, y, and z, and use the affine plus orientation codes to confirm the directionality.
Why this is important
Mislabeled axes or ignored orientation can silently flip anatomy, ruin downstream analysis, or mislead visual inspection. Verifying shape, affine, and orientation codes before you proceed reduces this risk, especially when moving between tools or datasets that might not share the same defaults.
Takeaways
Read shape and affine together. In NumPy terms, the first three axes are x, y, and z; use NiBabel’s aff2axcodes to interpret their anatomical directions. When in doubt, visualize center slices along each axis to validate your mental model. If you are working with this MSD task, the dataset note about RAS alignment and consistent x–y–z direction is a useful guidepost, and the short checks above keep you on solid ground.