Repository: mne-tools/mne-python

Issue:
GSN montage electrode naming
#### Describe the bug
When reading file with an HydroCel Geodesic Sensor Net montage, `set_montage()` returns an error if the electrodes are not correctly named. Unfortunately, the indicated error message is incorrect and does not help to fix the naming scheme.

#### Steps to reproduce
I'm using MAMEM EEG dataset 1 for SSVEP, a publicly available data. The example code below download 60 MB of data and try to apply the expected naming scheme. It generates an error.
```
import wfdb

from mne import create_info
from mne.channels import make_standard_montage
from mne.io import RawArray
from mne.datasets.utils import _get_path

import glob
import os
import numpy as np

subj = "dataset1/S001a"
wfdb.io.dl_database('mssvepdb', './', [subj],
                    annotators='win', overwrite=False)
record = wfdb.rdrecord(subj)
data = record.p_signal.T
n_samples, n_channels, n_trials = record.sig_len, 256, 23
ch_types = ['eeg']*256
sfreq = 250
ch_names = ["{}-{}".format(s, i) if s == "EEG" else s
            for i, s in enumerate(record.sig_name)]
info = create_info(ch_names, sfreq, ch_types)
raw = RawArray(data, info, verbose=False)
montage = make_standard_montage('GSN-HydroCel-256')

try:
    # Raise an error
    raw.set_montage(montage)
except ValueError as err:
    # Point out missing channels: ['EEG-0', 'F8', 'EEG-2', 'EEG-3', ...
    # even if they are correctly defined
    print("Channels are: ", ch_names)
    raise(err)

# in fact, this montage requires channels named ['E1', 'E2', 'E3', ...
ch_names = ["E{}".format(i+1) for i in range(0, 256)]
raw.set_montage(montage)
```

#### Expected results
The montage should work with the following naming scheme: `ch_names = ['EEG-0', 'F8', 'EEG-2', 'EEG-3', 'EEG-4', 'EEG-5', 'EEG-6', ...` 


#### Actual results
The montage works with a different naming scheme: `ch_names = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', ...` that is not easy to find.

#### Additional information
```
Platform:      macOS-10.16-x86_64-i386-64bit
Python:        3.6.10 |Anaconda, Inc.| (default, Mar 25 2020, 18:53:43)  [GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)]
Executable:    /Users/sylchev/anaconda3/bin/python
CPU:           i386: 4 cores
Memory:        8.0 GB

mne:           0.22.0
numpy:         1.18.1 {blas=mkl_rt, lapack=mkl_rt}
scipy:         1.4.1
matplotlib:    3.1.3 {backend=Qt5Agg}

sklearn:       0.22.1
numba:         0.51.2
nibabel:       Not found
nilearn:       Not found
dipy:          Not found
cupy:          Not found
pandas:        1.1.3
mayavi:        Not found
pyvista:       Not found
vtk:           Not found
```



Discussion:
you wrote:

ch_names = [
    "{}-{}".format(s, i) if s == "EEG" else s
    for i, s in enumerate(record.sig_name)
]

just for the example?

montage do require a match with channel names.
Was that unexpected for you?

On this [MAMEM dataset](https://www.mamem.eu/results/datasets/), the channels are named : `['EEG', 'F8', 'EEG', 'EEG', 'EEG', 'EEG', 'EEG', ...]
when trying to apply the GSN-256 montage, I have the following error : 
```
ValueError: DigMontage is only a subset of info. There are 256 channel positions not present in the DigMontage. The required channels are:

['EEG-0', 'F8', 'EEG-2', 'EEG-3', 'EEG-4', 'EEG-5', 'EEG-6', 'EEG-7', 'EEG-8', 'EEG-9', 'EEG-10', 'EEG-11', 'EEG-12', 'EEG-13', 'EEG-14', 'EEG-15', 'EEG-16', 'FP2', 'EEG-18', 'EEG-19', 'Fz', 'EEG-21', 'EEG-22', 'EEG-23', 'EEG-24', 'EEG-25', 'EEG-26', 'EEG-27', 'EEG-28', 'EEG-29', 'NAS', 'EEG-31', 'EEG-32', 'EEG-33', 'EEG-34', 'F3', 'Fp1', 'EEG-37', 'EEG-38', 'EEG-39', 'EEG-40', 'EEG-41', 'EEG-42', 'EEG-43', 'EEG-44', 'EEG-45', 'F7', 'EEG-47', 'EEG-48', 'EEG-49', 'EEG-50', 'EEG-51', 'EEG-52', 'EEG-53', 'EEG-54', 'EEG-55', 'EEG-56', 'EEG-57', 'EEG-58', 'EEG-59', 'EEG-60', 'EEG-61', 'EEG-62', 'EEG-63', 'EEG-64', 'EEG-65', 'EEG-66', 'EEG-67', 'T7', 'EEG-69', 'EEG-70', 'EEG-71', 'EEG-72', 'EEG-73', 'EEG-74', 'EEG-75', 'EEG-76', 'EEG-77', 'EEG-78', 'EEG-79', 'EEG-80', 'EEG-81', 'EEG-82', 'EEG-83', 'EEG-84', 'EEG-85', 'EEG-86', 'EEG-87', 'EEG-88', 'EEG-89', 'EEG-90', 'EEG-91', 'EEG-92', 'LM', 'EEG-94', 'P7', 'EEG-96', 'EEG-97', 'EEG-98', 'EEG-99', 'Pz', 'EEG-101', 'EEG-102', 'EEG-103', 'EEG-104', 'EEG-105', 'EEG-106', 'EEG-107', 'EEG-108', 'EEG-109', 'EEG-110', 'EEG-111', 'EEG-112', 'EEG-113', 'EEG-114', 'O1', 'EEG-116', 'EEG-117', 'EEG-118', 'EEG-119', 'EEG-120', 'EEG-121', 'EEG-122', 'EEG-123', 'EEG-124', 'Oz', 'EEG-126', 'EEG-127', 'EEG-128', 'EEG-129', 'EEG-130', 'EEG-131', 'EEG-132', 'EEG-133', 'EEG-134', 'EEG-135', 'EEG-136', 'EEG-137', 'EEG-138', 'EEG-139', 'EEG-140', 'EEG-141', 'EEG-142', 'EEG-143', 'EEG-144', 'EEG-145', 'EEG-146', 'EEG-147', 'EEG-148', 'O2', 'EEG-150', 'EEG-151', 'EEG-152', 'EEG-153', 'EEG-154', 'EEG-155', 'EEG-156', 'EEG-157', 'EEG-158', 'EEG-159', 'EEG-160', 'EEG-161', 'EEG-162', 'EEG-163', 'EEG-164', 'EEG-165', 'EEG-166', 'EEG-167', 'EEG-168', 'P8', 'EEG-170', 'EEG-171', 'EEG-172', 'EEG-173', 'EEG-174', 'EEG-175', 'EEG-176', 'EEG-177', 'EEG-178', 'EEG-179', 'EEG-180', 'EEG-181', 'C4', 'EEG-183', 'EEG-184', 'EEG-185', 'EEG-186', 'EEG-187', 'EEG-188', 'RM', 'EEG-190', 'EEG-191', 'EEG-192', 'EEG-193', 'EEG-194', 'EEG-195', 'EEG-196', 'EEG-197', 'EEG-198', 'EEG-199', 'EEG-200', 'T8', 'EEG-202', 'EEG-203', 'EEG-204', 'EEG-205', 'EEG-206', 'EEG-207', 'EEG-208', 'EEG-209', 'EEG-210', 'EEG-211', 'EEG-212', 'EEG-213', 'EEG-214', 'EEG-215', 'EEG-216', 'EEG-217', 'EEG-218', 'EEG-219', 'EEG-220', 'EEG-221', 'EEG-222', 'F4', 'EEG-224', 'EEG-225', 'EEG-226', 'EEG-227', 'EEG-228', 'EEG-229', 'EEG-230', 'EEG-231', 'EEG-232', 'EEG-233', 'EEG-234', 'EEG-235', 'EEG-236', 'EEG-237', 'EEG-238', 'EEG-239', 'EEG-240', 'EEG-241', 'EEG-242', 'EEG-243', 'EEG-244', 'EEG-245', 'EEG-246', 'EEG-247', 'EEG-248', 'EEG-249', 'EEG-250', 'EEG-251', 'EEG-252', 'EEG-253', 'EEG-254', 'EEG-255']
```

So I figured I just have to rename the 'EEG' channels into 'EEG-X', with 0 <= X <=255. There are some channels that are named explicitly (F8, Fz, NAS, ...) and that are in the same index in my `ch_names` and in the error message list. Hence the list comprehension you mentioned: I append an integer only the 'EEG' channels, not for the named channels. When doing that, and complying to the naming scheme indicated in the error message, I still encounter the same error message.

The `make_standard_montage('GSN-HydroCel-256').ch_names` indicates that the channels should be `['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', ...]`, without any explicit named channels (there is no F8, Fz or NAS in this list). When renaming the channels E1 to E256, I could apply the montage successfully.

There is an inconsistency between the ch_names in the 'GSN-HydroCel-256' montage and the ch_names mentioned in the error message. Those mentioned in the error message are closer to the names I found in the MAMEM datasets.
I guess message is not clear. I should say that "The required channels in
the montage are:" It indeed seems
to suggest the reverse... can you open a PR to improve the message?

>


Resolving patch:
diff --git a/mne/channels/montage.py b/mne/channels/montage.py
--- a/mne/channels/montage.py
+++ b/mne/channels/montage.py
@@ -1183,14 +1183,17 @@ def _backcompat_value(pos, ref_pos):
     missing = np.where([use not in ch_pos for use in info_names_use])[0]
     if len(missing):  # DigMontage is subset of info
         missing_names = [info_names[ii] for ii in missing]
+        pl = _pl(missing)
+        are_is = "are" if pl else "is"
         missing_coord_msg = (
-            'DigMontage is only a subset of info. There are '
-            f'{len(missing)} channel position{_pl(missing)} '
-            'not present in the DigMontage. The required channels are:\n\n'
-            f'{missing_names}.\n\nConsider using inst.set_channel_types '
-            'if these are not EEG channels, or use the on_missing '
-            'parameter if the channel positions are allowed to be unknown '
-            'in your analyses.'
+            f"DigMontage is only a subset of info. There {are_is} "
+            f"{len(missing)} channel position{pl} not present in the "
+            f"DigMontage. The channel{pl} missing from the montage {are_is}:"
+            f"\n\n{missing_names}.\n\nConsider using inst.rename_channels to "
+            "match the montage nomenclature, or inst.set_channel_types if "
+            f"{'these' if pl else 'this'} {are_is} not {'' if pl else 'an '}"
+            f"EEG channel{pl}, or use the on_missing parameter if the channel "
+            f"position{pl} {are_is} allowed to be unknown in your analyses."
         )
         _on_missing(on_missing, missing_coord_msg)
 


Test patch: