Alignment Methods¶
1. Objective¶
Alignment estimates where each reference observation lies in each non-reference modality coordinate system.
For a target modality \(T\), the aligned coordinates are stored as:
and written to the reference AnnData as:
This matrix is the direct input for registration. When the annotation modality is not the reference, it is also the input for annotation transfer.
2. Implemented strategies¶
manual¶
Interactive browser-based direct mapping (DirectMappingAligner + DirectMappingAlignmentGUI).
- The GUI displays the moving reference layer over the fixed target layer.
- The reference layer is transformed as a whole: translation, rotation, scaling, horizontal/vertical flip, corner dragging (one corner moves, the other three stay) and edge dragging (the two corners of that edge move together).
- The GUI keeps a
gl-matrixmat3per layer. Translation, rotation, scaling and flips compose onto the moving layer's matrix; a corner or edge drag replaces it with the homography that maps the layer's four original corners onto their dragged positions, solved by DLT with \(H_{33}=1\) (gui_src/alignment/src/utils/matrix.ts::computeHomography). - On confirmation the GUI posts
transform_matrix, the column-major serialization of
[ M = M_\text{reference}^{-1}\, M_\text{target} ]
which maps moving-layer coordinates into the fixed layer's frame
(gui_src/alignment/src/utils/export.ts).
- DirectMappingAligner._parse_alignment_result reshapes it column-first, applies it to the full
\(N_R\times2\) coordinate array in homogeneous coordinates and divides by \(w\), so the persisted
mapping is projective and covers every spot, not only the ones drawn in the browser. The per-spot
spots list in the same payload is a fallback used only when no matrix is present; the
corner_pixels payload of the image→image case carries no matrix and is consumed directly.
- No matrix is fitted from user-placed landmarks.
Internal naming
In DirectMappingAligner the constructor argument named reference_modality is given the pipeline's non-reference modality (the fixed frame), and target_modality is given the pipeline's reference modality (the moving layer). The orchestrator deliberately swaps them (_run_alignment), so the class-internal vocabulary is inverted relative to the pipeline terms used throughout this page. This page uses pipeline terms: reference = moving, target = fixed.
pre_aligned¶
No GUI. The pipeline copies the reference's native obsm['spatial'] unchanged into the pair-specific
aligned key obsm['{target_name}_spatial'].
This is valid only when those coordinates are already expressed in the target frame.
Current config validation additionally enforces:
- reference modality is spot-based (
msiorst) - at most one non-reference modality uses
pre_aligned
3. Data pathways by modality pair¶
What the GUI returns depends on the reference (moving) modality type; whether the result is stored as coordinates or a crop depends on the target (fixed) modality type. The pathways, written as (reference type → target type), are:
- spot → spot and spot → image: the GUI returns the transform mapping the reference spots into
the target frame; the mapped coordinates are stored as
obsm['{target_name}_spatial']on the reference's aligned AnnData. This covers the normal configurations, including a spot reference (msi/st) aligned against a microscopy or Raman image. - image → image: the GUI returns the reference image's four corners mapped into the target frame
(
corner_pixels)._save_image_to_imagetakes their bounding box, clamps it to the target image, and writes that crop of the target image as the OME-TIFF output. - image → spot: not supported. Configuration validation (Step 9c in
utils.py::parse_config) rejects an image-based reference whenever a spot-based non-reference modality is present, so the pipeline stops before preprocessing. The corresponding branch inDirectMappingAligner.align_datasetremains as a defensive guard: it logs an error and returns no aligned output.
4. Coordinate scaling¶
When the fixed target modality is an image, GUI interaction runs on its lowest OME-TIFF pyramid level, and the mapped coordinates (which are expressed in the target's coordinate space) are rescaled back to full resolution before persistence. If
- \((H_0, W_0)\): full-resolution dimensions of the target image
- \((H_L, W_L)\): displayed-level dimensions
then scale factors are:
Mapped GUI coordinates are rescaled component-wise before persistence:
In code the factors are stored row-major as [H₀/H_L, W₀/W_L] (y-scale first), and applied as
x *= factors[1], y *= factors[0]. For spot payloads, coordinates are already in physical space
and scaling factors are 1.
The factors are those of the fixed target layer, which is the frame \(M\) maps into (§2), so the two steps compose: \(M\) lands the reference in the target's displayed-level frame, and the factors lift that to the target's full resolution.
4b. Display coarsening for large spot sets¶
A spot layer with more than _SPATIAL_CAP (100,000) observations is aggregated for display:
_spatial_bin_assignment assigns each spot to one of at most 100,000 uniform bins, and one
marker per occupied bin is sent to the browser at the bin's cell centre. It is the same routine and
cap the preprocessing clustering uses
(MSI §6b, ST §3.6),
so both stages build the identical grid. The reported spot size
becomes the grid pitch, so bins tile without gaps; axes with zero extent fall back to the real
uns['spot_size']. Each bin takes the majority cluster label and majority foreground flag of its
members.
The aggregation is display-only. The full \(N_R\times2\) coordinate array stays on the backend and the confirmed matrix is applied to all of it, so the persisted mapping covers every original spot. No binned value is written to any output.
5. GUI image representation details¶
For image modalities, display payload construction (_image_to_rgb_uint8) is:
- dynamic range normalization to uint8
- channel arrangement to HWC
- 1-channel → replicated RGB
- 2-channel → zero-padded third channel
- 3-channel → unchanged
- 4+ channels → NMF reduction to 3 components
For the 4+-channel case the pixel-by-channel matrix \(V\in\mathbb{R}_{\ge0}^{P\times C}\) is factorized
as \(V \approx WH\) with \(W\in\mathbb{R}_{\ge0}^{P\times3}\), \(H\in\mathbb{R}_{\ge0}^{3\times C}\) by
non-negative matrix factorization (init='nndsvda', fixed seed), minimizing
\(\lVert V-WH\rVert_F^2\); the three \(W\) components are mapped to RGB. This conversion is for
visualization only; alignment outputs are stored as coordinates/crops.
6. Output artifacts¶
Spot-reference alignment outputs¶
The aligned file is written on the reference modality and named after it. For a spot-based reference (the normal case), per sample:
It is built from the reference's preprocessed AnnData, so it contains the reference-native obsm['spatial'] plus, for each target it was aligned against, the pair key:
This key holds the reference coordinates expressed in that target (non-reference) modality's space. Multiple targets accumulate as multiple keys on the same reference AnnData.
Merged:
Image-reference alignment outputs¶
When an image-based reference is aligned against an image target, the target image is cropped to the region covered by the reference and saved as a per-sample OME-TIFF (zlib), carrying the target modality's name:
No merged file is produced for this pathway. DirectMappingAligner._aligned_output_path is the single
source of truth for both output names and is used by the writers and by every cache check.
7. Caching semantics¶
Alignment is skipped when the expected aligned outputs are already present. Cache validity is checked per sample:
- spot outputs: the aligned
.h5adexists and containsobsm['{target_name}_spatial'](read withh5py, without loading the AnnData); - image outputs: the aligned
.ome.tiffexists.
_compute_force_flags in orchestrator.py re-runs a pair when any of the following is true:
alignment_force_recomputing on the non-reference modality, processing_settings.force_recomputing
on the reference modality, or processing_settings.force_recomputing on that non-reference modality.
The same disjunction is OR-ed into that modality's registration force flag.