Skip to content

Fix landmark alignment case sensitivity and improve visualization (#84)#132

Merged
emiddell merged 4 commits intodevfrom
norm_landmarks
Feb 13, 2026
Merged

Fix landmark alignment case sensitivity and improve visualization (#84)#132
emiddell merged 4 commits intodevfrom
norm_landmarks

Conversation

@orabe
Copy link

@orabe orabe commented Jan 24, 2026

This PR resolves issue #84 by adding case-insensitive landmark name normalization and improving landmark visualization in 3D montage plots.

Changes

1. New Function: normalize_landmarks_labels

Location: landmarks.py

Maps alternative landmark names to canonical labels with case-insensitive matching:

"Nz": ["NASION", "Nasion", "nasion", "nas", "Nas", "NAS"],
"Iz": ["INION", "Inion", "inion", "ini", "Ini", "INI"],
"LPA": ["LPA_L", "lpa", "left ear", "Left Ear", "LEFT EAR", "LE", "left", "Left", "L"],
"RPA": ["RPA_R", "rpa", "right ear", "Right Ear", "RIGHT EAR", "RE", "right", "Right", "R"],
"Cz": ["CZ", "cz", "vertex", "Vertex", "VERTEX"]

Handles duplicates by keeping canonical labels and dropping alternatives.

2. Enhanced plot_montage3D Function

Location: montage.py

New Parameter: landmarks: list[str] | None

  • None (default): Shows all available canonical registration landmarks (Nz, Iz, LPA, RPA, Cz)
  • list[str]: Shows specified landmarks only
  • []: Shows no landmarks

Fixes and Improvements:

  • Default changed from Nz-only to all 5 registration landmarks
  • Fixed PointType enum comparison bug
  • Larger landmark markers (s=50)
  • Legend positioned outside plot to avoid overlap

3. Testing

Added 12 tests in test_landmarks.py:

  • 4 normalization tests (alternatives, duplicates, preservation, empty data)
  • 8 plotting smoke tests (modes, defaults, filtering)

All tests pass:

pytest tests/test_landmarks.py -v
# 12 passed in 4.45s

4. Documentation

  • Added CHANGELOG entries

Example

from cedalion.geometry.landmarks import normalize_landmarks_labels
from cedalion.vis.anatomy.montage import plot_montage3D

# Normalize landmarks before registration
geo3d = normalize_landmarks_labels(geo3d)

# Visualize with default (all canonical landmarks)
plot_montage3D(rec["amp"], geo3d)

# Or customize
plot_montage3D(rec["amp"], geo3d, landmarks=["Nz", "Cz"])

Fixes #84

- Add normalize_landmarks_labels() for case-insensitive landmark mapping
- Support common naming conventions (nasion, left ear, vertex, etc.)
- Enhance plot_montage3D with landmarks parameter
- Fix PointType enum comparison bug
- Change default to show all 5 registration landmarks
- Add 12 comprehensive tests
Copy link
Contributor

@emiddell emiddell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @orabe!
I changed the logic of normalize_landmarks_labels in case of ambiguities. Instead of dropping duplicates it will raise an error and the user has to sort it out.

@emiddell emiddell merged commit 8dec70d into dev Feb 13, 2026
8 checks passed
@emiddell emiddell deleted the norm_landmarks branch February 13, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants