Plot a topographic map with all channel names and with a mask

Is there a way to plot a topographic map with all channel names and with a mask provided to highlight specific sensors with a different plotting style?

from mne.datasets import sample
from mne.io import read_raw_fif
from mne.viz import plot_topomap


directory = sample.data_path() / "MEG" / "sample"
fname = directory / "sample_audvis_raw.fif"
raw = read_raw_fif(fname, preload=False)
raw.pick_types(eeg=True, exclude=[]).crop(0, 5)
raw.load_data()
data = raw.get_data()[:, 101]

plot_topomap(data, raw.info, show_names=True, names=raw.ch_names)

Screenshot 2022-06-16 at 11.46.31

But with a mask:

import numpy as np

from mne.datasets import sample
from mne.io import read_raw_fif
from mne.viz import plot_topomap


directory = sample.data_path() / "MEG" / "sample"
fname = directory / "sample_audvis_raw.fif"
raw = read_raw_fif(fname, preload=False)
raw.pick_types(eeg=True, exclude=[]).crop(0, 5)
raw.load_data()
data = raw.get_data()[:, 101]

mask = np.zeros(len(raw.ch_names))
for ch in raw.info["bads"]:
    mask[raw.ch_names.index(ch)] = 1
mask.astype(bool)

plot_topomap(data, raw.info, show_names=True, names=raw.ch_names, mask=mask)

Screenshot 2022-06-16 at 11.48.15

It looks intended as per the docstring of the show_names argument:

If mask is not None, only significant sensors will be shown.

Maybe the ‘easiest’ way would be to plot first without a mask and then overlay a mask on the matplotlib axes… anyone has a better idea before I go this way?

just to be sure I understand: what you want isn’t shown in either of those images, right? You want to show all sensor names, but have a few of them (determined by mask) in bold font, or larger font, or another color, or something like that? Would it be too hard to iterate through list(axes.texts) and e.g. .set_color('red') on each one whose .get_text() matches the channels you want to mask?

In other words, is a one-off figure for a paper, or is this a general enough use case that we should support it? What if the style of highlighting is not to all users’ tastes, do we need to expose color, opacity, family, weight, and size params?

1 Like

You got it perfectly right. I’ll give a try to your suggestion. I am not super familiar with the matplotlib API, and finding the sensors’ symbols to change the settings and redraw the figure is not super straightforward.

One-time or missing feature, that’s an open discussion. For the mask, my goal was to find bridged EEG electrodes and plot them with mne.viz.plot_bridged_electrodes — MNE 1.1.dev0 documentation
For each group of N bridged electrodes, I wanted to retain 1 electrode and mark as bad for interpolation N-1 electrodes; and for visualization, I wanted to add a mask with the electrodes set as bad. It would help to visualize the different rules/logic I could add.

It’s a special case, and I don’t think the mask is that used anyway… but I think the mne.viz.plot_topomap could use a bit of love, e.g. the arguments names and show_names are not straightforward to use (and overall the mix between pos as an array and as an Info is making a mess out of the arguments).

I find this convincing as a use case, and am generally in favor of visualization methods designed to help users diagnose or detect problems with their data (such as bridged electrodes).

Go for it. I’m still a bit unsure about exposing the channel label styling in the public API though… but it’s not clear to me if that’s what you want to do, or if instead you want to improve plot_bridged_electrodes to visualize things differently than the current “red connecting lines” approach.

1 Like