Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: missing channels/fiducials can be np.nan #11634

Merged
merged 5 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mne/channels/montage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1656,7 +1656,8 @@ def compute_native_head_t(montage, *, on_missing='warn', verbose=None):
else:
fid_keys = ('nasion', 'lpa', 'rpa')
for key in fid_keys:
if fid_coords[key] is None:
this_coord = fid_coords[key]
if this_coord is None or np.any(np.isnan(this_coord)):
msg = (
f'Fiducial point {key} not found, assuming identity '
f'{_verbose_frames[coord_frame]} to head transformation')
Expand Down
46 changes: 46 additions & 0 deletions mne/channels/tests/test_montage.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,52 @@ def test_set_dig_montage():
[6., 7., 8., 42., 42., 42.]])


def test_set_dig_montage_with_nan_positions():
"""Test that fiducials are not NaN.

Test that setting a montage with some NaN positions does not produce
NaN fiducials.
"""
def _ensure_fid_not_nan(info, ch_pos):
montage_kwargs = dict(ch_pos=dict(), coord_frame='head')
for ch_idx, ch in enumerate(info.ch_names):
montage_kwargs['ch_pos'][ch] = ch_pos[ch_idx]

new_montage = make_dig_montage(**montage_kwargs)
info = info.copy()
info.set_montage(new_montage)

recovered_montage = info.get_montage()
fid_coords, coord_frame = _get_fid_coords(
recovered_montage.dig, raise_error=False)

for fid_coord in fid_coords.values():
if fid_coord is not None:
assert not np.isnan(fid_coord).any()

return fid_coords, coord_frame

channels = list('ABCDEF')
info = create_info(channels, 1000, ch_types='seeg')

# if all positions are NaN, the fiducials should not be NaN, but None
ch_pos = [info['chs'][ch_idx]['loc'][:3]
for ch_idx in range(len(channels))]
fid_coords, coord_frame = _ensure_fid_not_nan(info, ch_pos)
for fid_coord in fid_coords.values():
assert fid_coord is None
assert coord_frame is None

# if some positions are not NaN, the fiducials should be a non-NaN array
ch_pos[0] = np.array([1., 1.5, 1.])
ch_pos[1] = np.array([2., 1.5, 1.5])
ch_pos[2] = np.array([1.25, 1., 1.25])
fid_coords, coord_frame = _ensure_fid_not_nan(info, ch_pos)
for fid_coord in fid_coords.values():
assert isinstance(fid_coord, np.ndarray)
assert coord_frame == FIFF.FIFFV_COORD_HEAD


@testing.requires_testing_data
def test_fif_dig_montage(tmp_path):
"""Test FIF dig montage support."""
Expand Down
3 changes: 2 additions & 1 deletion mne/io/_digitization.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ def _ensure_fiducials_head(dig):
if radius is None:
radius = [
np.linalg.norm(d['r']) for d in dig
if d['coord_frame'] == FIFF.FIFFV_COORD_HEAD]
if d['coord_frame'] == FIFF.FIFFV_COORD_HEAD
and not np.isnan(d['r']).any()]
if not radius:
return # can't complete, no head points
radius = np.mean(radius)
Expand Down