Skip to content

Commit

Permalink
Allow retrieval of channel names via make_1020_channel_selections()
Browse files Browse the repository at this point in the history
Fixes #11597
  • Loading branch information
hoechenberger committed Apr 17, 2023
1 parent 5024b32 commit 69abd8b
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 22 deletions.
1 change: 1 addition & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Enhancements
- Improve performance of raw data browsing with many annotations (:gh:`11614` by `Eric Larson`_)
- Add support for :func:`mne.preprocessing.maxwell_filter` with gradient-compensated CTF data, e.g., for tSSS-only mode (:gh:`10554` by `Eric Larson`_)
- Add support for eyetracking data using :func:`mne.io.read_raw_eyelink` (:gh:`11152` by `Dominik Welke`_ and `Scott Huberty`_)
- :func:`mne.channels.make_1020_channel_selections` gained a new parameter, ``return_ch_names``, to allow for easy retrieval of EEG channel names corresponding to the left, right, and midline portions of the montage (:gh:`11632` by `Richard Höchenberger`_)

Bugs
~~~~
Expand Down
9 changes: 3 additions & 6 deletions examples/preprocessing/contralateral_referencing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
contralateral EEG reference.
"""

import numpy as np
import mne

ssvep_folder = mne.datasets.ssvep.data_path()
Expand All @@ -31,11 +30,9 @@
})

# this splits electrodes into 3 groups; left, midline, and right
ch_indices = mne.channels.make_1020_channel_selections(raw.info)

# convert indices to names
orig_names = np.array(raw.ch_names)
ch_names = {key: orig_names[idxs].tolist() for key, idxs in ch_indices.items()}
ch_names = mne.channels.make_1020_channel_selections(
raw.info, return_ch_names=True
)

# remove the ref channels from the lists of to-be-rereferenced channels
ch_names['Left'].remove('M1')
Expand Down
45 changes: 29 additions & 16 deletions mne/channels/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -1837,31 +1837,39 @@ def _get_ch_info(info):


@fill_doc
def make_1020_channel_selections(info, midline="z"):
"""Return dict mapping from ROI names to lists of picks for 10/20 setups.
This passes through all channel names, and uses a simple heuristic to
separate channel names into three Region of Interest-based selections:
Left, Midline and Right. The heuristic is that channels ending on any of
the characters in ``midline`` are filed under that heading, otherwise those
ending in odd numbers under "Left", those in even numbers under "Right".
Other channels are ignored. This is appropriate for 10/20 files, but not
for other channel naming conventions.
If an info object is provided, lists are sorted from posterior to anterior.
def make_1020_channel_selections(info, midline="z", *, return_ch_names=False):
"""Map hemisphere names to corresponding EEG channel names or indices.
This function uses a simple heuristic to separate channel names into three
Region of Interest-based selections: ``Left``, ``Midline`` and ``Right``.
The heuristic is that any of the channel names ending
with odd numbers are filed under ``Left``; those ending with even numbers
are filed under ``Right``; and those ending with the character(s) specified
in ``midline`` are filed under ``Midline``. Other channels are ignored.
This is appropriate for 10/20, 10/10, 10/05, …, sensor arrangements, but
not for other naming conventions.
Parameters
----------
%(info_not_none)s If possible, the channel lists will be sorted
posterior-to-anterior; otherwise they default to the order specified in
``info["ch_names"]``.
%(info_not_none)s If channel locations are present, the channel lists will
be sorted from posterior to anterior; otherwise, the order specified in
``info["ch_names"]`` will be kept.
midline : str
Names ending in any of these characters are stored under the
``Midline`` key. Defaults to 'z'. Note that capitalization is ignored.
``Midline`` key. Defaults to ``'z'``. Capitalization is ignored.
return_ch_names : bool
Whether to return channel names instead of channel indices.
.. versionadded:: 1.4.0
Returns
-------
selections : dict
A dictionary mapping from ROI names to lists of picks (integers).
A dictionary mapping from region of interest name to a list of channel
indices (if ``return_ch_names=False``) or to a list of channel names
(if ``return_ch_names=True``).
"""
_validate_type(info, "info")

Expand Down Expand Up @@ -1891,6 +1899,11 @@ def make_1020_channel_selections(info, midline="z"):
selections = {selection: np.array(picks)[pos[picks, 1].argsort()]
for selection, picks in selections.items()}

# convert channel indices to names if requested
if return_ch_names:
for selection, ch_indices in selections.items():
selections[selection] = [info.ch_names[idx] for idx in ch_indices]

return selections


Expand Down
5 changes: 5 additions & 0 deletions mne/channels/tests/test_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ def test_1020_selection():
for channel, roi in zip(fz_c3_c4, ("Midline", "Left", "Right")):
assert channel in sels[roi]

# ensure returning channel names works as expected
sels_names = make_1020_channel_selections(raw.info, return_ch_names=True)
for selection, ch_names in sels_names.items():
assert ch_names == [raw.ch_names[idx] for idx in sels[selection]]


@testing.requires_testing_data
def test_find_ch_adjacency():
Expand Down

0 comments on commit 69abd8b

Please sign in to comment.