Skip to content

Commit

Permalink
[BUG, MRG] Fix how montage is set in ieeg locate gui (#11421)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexrockhill authored Jan 18, 2023
1 parent 4afeceb commit 6306265
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
1 change: 1 addition & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Bugs
- Fix bug where channel names were not properly sanitized in :func:`mne.write_evokeds` and related functions (:gh:`11399` by `Eric Larson`_)
- Fix bug where splash screen would not always disappear (:gh:`11398` by `Eric Larson`_)
- Fix bug where having a different combination of volumes loaded into ``freeview`` caused different affines to be returned by :func:`mne.read_lta` for the same Linear Transform Array (LTA) (:gh:`11402` by `Alex Rockhill`_)
- Fix how :class:`mne.channels.DigMontage` is set when using :func:`mne.gui.locate_ieeg` so that :func:`mne.Info.get_montage` works and does not return ``None`` (:gh:`11421` by `Alex Rockhill`_)

API changes
~~~~~~~~~~~
Expand Down
22 changes: 16 additions & 6 deletions mne/gui/_ieeg_locate.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from matplotlib.colors import LinearSegmentedColormap

from ..channels import make_dig_montage
from ._core import SliceBrowser
from ..surface import _voxel_neighbors
from ..transforms import apply_trans, _get_trans, invert_transform
Expand Down Expand Up @@ -84,6 +85,13 @@ def __init__(self, info, trans, aligned_ct, subject=None,
# load data, apply trans
self._head_mri_t = _get_trans(trans, 'head', 'mri')[0]
self._mri_head_t = invert_transform(self._head_mri_t)

# ensure channel positions in head
montage = info.get_montage()
if montage and montage.get_positions()['coord_frame'] != 'head':
raise RuntimeError('Channel positions in the ``info`` object must '
'be in the "head" coordinate frame.')

# load channels, convert from m to mm
self._chs = {name: apply_trans(self._head_mri_t, ch['loc'][:3]) * 1000
for name, ch in zip(info.ch_names, info['chs'])}
Expand Down Expand Up @@ -198,12 +206,14 @@ def _save_ch_coords(self, info=None, verbose=None):
logger.info('Saving channel positions to `info`')
if info is None:
info = self._info
with info._unlock():
for name, ch in zip(info.ch_names, info['chs']):
loc = ch['loc'].copy()
loc[:3] = apply_trans(
self._mri_head_t, self._chs[name] / 1000) # mm->m
ch['loc'] = loc
montage = info.get_montage()
montage_kwargs = montage.get_positions() if montage else \
dict(ch_pos=dict(), coord_frame='head')
for ch in info['chs']:
# surface RAS-> head and mm->m
montage_kwargs['ch_pos'][ch['ch_name']] = apply_trans(
self._mri_head_t, self._chs[ch['ch_name']].copy() / 1000)
info.set_montage(make_dig_montage(**montage_kwargs))

def _plot_ch_images(self):
img_delta = 0.5
Expand Down
22 changes: 20 additions & 2 deletions mne/gui/tests/test_ieeg_locate.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,25 @@ def test_ieeg_elec_locate_io(renderer_interactive_pyvistaqt):
import nibabel as nib
import mne.gui
info = mne.create_info([], 1000)
aligned_ct = nib.MGHImage(np.zeros((256, 256, 256), dtype=np.float32),
np.eye(4))

# fake as T1 so that aligned
aligned_ct = nib.load(op.join(subjects_dir, subject, 'mri', 'brain.mgz'))

trans = mne.transforms.Transform('head', 'mri')
with pytest.raises(ValueError,
match='No channels found in `info` to locate'):
mne.gui.locate_ieeg(info, trans, aligned_ct, subject, subjects_dir)

info = mne.create_info(['test'], 1000, 'seeg')
montage = mne.channels.make_dig_montage(
{'test': [0, 0, 0]}, coord_frame='mri')
with pytest.warns(RuntimeWarning, match='nasion not found'):
info.set_montage(montage)
with pytest.raises(RuntimeError,
match='must be in the "head" coordinate frame'):
with pytest.warns(RuntimeWarning, match='`pial` surface not found'):
mne.gui.locate_ieeg(info, trans, aligned_ct, subject, subjects_dir)


@requires_version('sphinx_gallery')
@testing.requires_testing_data
Expand Down Expand Up @@ -194,4 +206,10 @@ def test_ieeg_elec_locate_display(renderer_interactive_pyvistaqt,
assert 'mip' in gui._images
assert 'mip_chs' in gui._images
assert len(gui._lines_2D) == 1 # LAMY only has one contact

# check montage
montage = raw.get_montage()
assert montage is not None
assert_allclose(montage.get_positions()['ch_pos']['LAMY 1'],
[0.00726235, 0.01713514, 0.04167233], atol=0.01)
gui.close()
2 changes: 1 addition & 1 deletion mne/viz/topomap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1781,7 +1781,7 @@ def plot_evoked_topomap(
kwargs.update(vlim=_vlim)
axes.append(plt.subplot(gs[1, :-1]))
slider = Slider(axes[-1], 'Time', evoked.times[0], evoked.times[-1],
times[0], valfmt='%1.2fs')
valinit=times[0], valfmt='%1.2fs')
slider.vline.remove() # remove initial point indicator
func = _merge_ch_data if merge_channels else lambda x: x
changed_callback = partial(_slider_changed, ax=axes[0],
Expand Down

0 comments on commit 6306265

Please sign in to comment.