From 0d8f46934d524253b2bcb154460ac9ef17556ac5 Mon Sep 17 00:00:00 2001 From: Mathieu Scheltienne Date: Tue, 14 Jun 2022 15:10:04 +0200 Subject: [PATCH] MRG: Automatically selects EEG channels when plotting bridged electrodes on topomap (#10753) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- doc/changes/latest.inc | 2 ++ mne/viz/tests/test_topomap.py | 10 +++++++++- mne/viz/topomap.py | 26 +++++++++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/doc/changes/latest.inc b/doc/changes/latest.inc index 6a598463670..1636efbcc11 100644 --- a/doc/changes/latest.inc +++ b/doc/changes/latest.inc @@ -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`_) diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 2946513d4a8..3124b82e43e 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -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 @@ -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.""" diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index e8233e68d27..6db57b5c7e1 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -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 @@ -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 @@ -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)} ' @@ -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: