Skip to content

Commit

Permalink
MRG: Automatically selects EEG channels when plotting bridged electro…
Browse files Browse the repository at this point in the history
…des on topomap (mne-tools#10753)

* add support for instance with more than 1 channel type

* add entry to changelog

* add notes [skip ci]

* update gh id

* fix doc

* fix sphere issue

* better

* Make docstring more concise & add See Also

Co-authored-by: Richard Höchenberger <[email protected]>
  • Loading branch information
Mathieu Scheltienne and hoechenberger authored Jun 14, 2022
1 parent 74edf16 commit 0d8f469
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
2 changes: 2 additions & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ Bugs

- In :class:`mne.Report`, some figures would have an undesired border added to the edges; this has now been resolved (:gh:`10730` by `Richard Höchenberger`_)

- Fix selection of EEG channels and selected sphere when plotting bridged electrodes with :func:`mne.viz.plot_bridged_electrodes` (:gh:`10753` by `Mathieu Scheltienne`_)

API and behavior changes
~~~~~~~~~~~~~~~~~~~~~~~~
- When creating BEM surfaces via :func:`mne.bem.make_watershed_bem` and :func:`mne.bem.make_flash_bem`, the ``copy`` parameter now defaults to ``True``. This means that instead of creating symbolic links inside the FreeSurfer subject's ``bem`` folder, we now create "actual" files. This should avoid troubles when sharing files across different operating systems and file systems (:gh:`10531` by `Richard Höchenberger`_)
Expand Down
10 changes: 9 additions & 1 deletion mne/viz/tests/test_topomap.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
from mne.io.proj import make_eeg_average_ref_proj, Projection
from mne.io import read_raw_fif, read_info, RawArray
from mne.io.constants import FIFF
from mne.io.pick import pick_info, channel_indices_by_type
from mne.io.pick import pick_info, channel_indices_by_type, _picks_to_idx
from mne.io.compensator import get_current_comp
from mne.channels import (read_layout, make_dig_montage, make_standard_montage,
find_ch_adjacency)
from mne.datasets import testing
from mne.preprocessing import compute_bridged_electrodes
from mne.time_frequency.tfr import AverageTFR

from mne.viz import plot_evoked_topomap, plot_projs_topomap, topomap
Expand Down Expand Up @@ -730,6 +731,13 @@ def test_plot_bridged_electrodes():
with pytest.raises(RuntimeError, match='Expected'):
plot_bridged_electrodes(info, bridged_idx, np.zeros((5, 6, 7)))

# test with multiple channel types
raw = read_raw_fif(raw_fname, preload=True)
picks = _picks_to_idx(raw.info, "eeg")
raw._data[picks[0]] = raw._data[picks[1]] # artificially bridge electrodes
bridged_idx, ed_matrix = compute_bridged_electrodes(raw)
plot_bridged_electrodes(raw.info, bridged_idx, ed_matrix)


def test_plot_ch_adjacency():
"""Test plotting of adjacency matrix."""
Expand Down
26 changes: 17 additions & 9 deletions mne/viz/topomap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2727,8 +2727,12 @@ def plot_bridged_electrodes(info, bridged_idx, ed_matrix, title=None,
bridged_idx : list of tuple
The indices of channels marked as bridged with each bridged
pair stored as a tuple.
ed_matrix : ndarray of float, shape (n_channels, n_channels)
Can be generated via
:func:`mne.preprocessing.compute_bridged_electrodes`.
ed_matrix : array of float, shape (n_channels, n_channels)
The electrical distance matrix for each pair of EEG electrodes.
Can be generated via
:func:`mne.preprocessing.compute_bridged_electrodes`.
title : str
A title to add to the plot.
topomap_args : dict | None
Expand All @@ -2738,17 +2742,24 @@ def plot_bridged_electrodes(info, bridged_idx, ed_matrix, title=None,
-------
fig : instance of matplotlib.figure.Figure
The topoplot figure handle.
See Also
--------
mne.preprocessing.compute_bridged_electrodes
"""
import matplotlib.pyplot as plt
if topomap_args is None:
topomap_args = dict()
else:
topomap_args = topomap_args.copy() # don't change original
picks = pick_types(info, eeg=True)
topomap_args.setdefault('image_interp', 'nearest')
topomap_args.setdefault('cmap', 'summer_r')
topomap_args.setdefault('names', info.ch_names)
topomap_args.setdefault('names', pick_info(info, picks).ch_names)
topomap_args.setdefault('show_names', True)
topomap_args.setdefault('contours', False)
sphere = topomap_args['sphere'] if 'sphere' in topomap_args \
else _check_sphere(None)
if 'axes' not in topomap_args:
fig, ax = plt.subplots()
topomap_args['axes'] = ax
Expand All @@ -2757,9 +2768,6 @@ def plot_bridged_electrodes(info, bridged_idx, ed_matrix, title=None,
# handle colorbar here instead of in plot_topomap
colorbar = topomap_args.pop('colorbar') if \
'colorbar' in topomap_args else True
# use sphere to find positions
sphere = topomap_args['sphere'] if 'sphere' in topomap_args else None
picks = pick_types(info, eeg=True)
if ed_matrix.shape[1:] != (picks.size, picks.size):
raise RuntimeError(
f'Expected {(ed_matrix.shape[0], picks.size, picks.size)} '
Expand All @@ -2770,13 +2778,13 @@ def plot_bridged_electrodes(info, bridged_idx, ed_matrix, title=None,
for epo_idx in range(ed_matrix.shape[0]):
ed_matrix[epo_idx][tril_idx] = ed_matrix[epo_idx].T[tril_idx]
elec_dists = np.median(np.nanmin(ed_matrix, axis=1), axis=0)
pos = _find_topomap_coords(info, picks, sphere=sphere)
im, cn = plot_topomap(elec_dists, info, **topomap_args)
im, cn = plot_topomap(elec_dists, pick_info(info, picks), **topomap_args)
fig = im.figure if fig is None else fig
# add bridged connections
for idx0, idx1 in bridged_idx:
im.axes.plot([pos[idx0][0], pos[idx1][0]],
[pos[idx0][1], pos[idx1][1]], color='r')
pos = _find_topomap_coords(info, [idx0, idx1], sphere=sphere)
im.axes.plot([pos[0, 0], pos[1, 0]],
[pos[0, 1], pos[1, 1]], color='r')
if title is not None:
im.axes.set_title(title)
if colorbar:
Expand Down

0 comments on commit 0d8f469

Please sign in to comment.