From 01c1a09eb6594b251158aa098960507774b088fe Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Fri, 30 Jan 2026 03:10:04 +0530 Subject: [PATCH 01/15] =?UTF-8?q?ENH:=20clearer=20error=20for=20mixed=2010?= =?UTF-8?q?=E2=80=9320=20EEG=20electrode=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mne/channels/layout.py | 36 ++++++++++++++++++++++++++----- mne/channels/tests/test_layout.py | 18 ++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/mne/channels/layout.py b/mne/channels/layout.py index 85b7913c1c6..d4e136b6ede 100644 --- a/mne/channels/layout.py +++ b/mne/channels/layout.py @@ -971,11 +971,37 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): for elec_i in squareform(dist < 1e-10).any(axis=0).nonzero()[0] ] - raise ValueError( - "The following electrodes have overlapping positions," - " which causes problems during visualization:\n" - + ", ".join(problematic_electrodes) - ) + duplicates_1020 = { + "T3": "T7", + "T4": "T8", + "T5": "P7", + "T6": "P8", + } + + names = set(problematic_electrodes) + duplicate_pairs = [ + (old, new) + for old, new in duplicates_1020.items() + if old in names and new in names + ] + + if duplicate_pairs: + raise ValueError( + "Duplicate EEG electrode positions detected due to mixed 10–20 " + "naming conventions.\n" + "You appear to have both old (T3/T4/T5/T6) and new (T7/T8/P7/P8) " + "electrode names present.\n\n" + "Please drop one set before plotting, for example:\n" + " inst.drop_channels(['T3', 'T4', 'T5', 'T6'])\n" + "or\n" + " inst.drop_channels(['T7', 'T8', 'P7', 'P8'])" + ) + else: + raise ValueError( + "The following electrodes have overlapping positions, which causes " + "problems during visualization:\n" + + ", ".join(problematic_electrodes) + ) if to_sphere: # translate to sphere origin, transform/flatten Z, translate back diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index ad44a6873a4..99c654b68c4 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -4,6 +4,7 @@ import copy from pathlib import Path +import mne import matplotlib.pyplot as plt import numpy as np @@ -185,6 +186,23 @@ def test_find_topomap_coords(): with pytest.raises(RuntimeError, match="No digitization points found"): _find_topomap_coords(info, picks, **kwargs) +def test_duplicate_1020_electrode_names_error(): + """Ensure mixed 10–20 EEG naming conventions raise a clear error.""" + montage = mne.channels.make_standard_montage("standard_1020") + data = np.random.randn(len(montage.ch_names)) + info = mne.create_info( + ch_names=montage.ch_names, + sfreq=1000, + ch_types="eeg", + ) + info.set_montage(montage) + + with pytest.raises( + ValueError, + match="10.?20", + ): + mne.viz.plot_topomap(data, pos=info) + def test_make_eeg_layout(tmp_path): """Test creation of EEG layout.""" From e2786b7e4c98ba575bd1c5a30c9c45b14dc9e33c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:49:35 +0000 Subject: [PATCH 02/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/channels/layout.py | 11 +++++------ mne/channels/tests/test_layout.py | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mne/channels/layout.py b/mne/channels/layout.py index d4e136b6ede..02995a281c1 100644 --- a/mne/channels/layout.py +++ b/mne/channels/layout.py @@ -972,10 +972,10 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): ] duplicates_1020 = { - "T3": "T7", - "T4": "T8", - "T5": "P7", - "T6": "P8", + "T3": "T7", + "T4": "T8", + "T5": "P7", + "T6": "P8", } names = set(problematic_electrodes) @@ -999,8 +999,7 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): else: raise ValueError( "The following electrodes have overlapping positions, which causes " - "problems during visualization:\n" - + ", ".join(problematic_electrodes) + "problems during visualization:\n" + ", ".join(problematic_electrodes) ) if to_sphere: diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index 99c654b68c4..8a1b32fdfed 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -4,7 +4,6 @@ import copy from pathlib import Path -import mne import matplotlib.pyplot as plt import numpy as np @@ -16,6 +15,7 @@ assert_equal, ) +import mne from mne import pick_info, pick_types from mne._fiff.constants import FIFF from mne._fiff.meas_info import _empty_info @@ -186,6 +186,7 @@ def test_find_topomap_coords(): with pytest.raises(RuntimeError, match="No digitization points found"): _find_topomap_coords(info, picks, **kwargs) + def test_duplicate_1020_electrode_names_error(): """Ensure mixed 10–20 EEG naming conventions raise a clear error.""" montage = mne.channels.make_standard_montage("standard_1020") From 44c708d1b010b53f40b06cea114fa991d5349061 Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Fri, 30 Jan 2026 03:23:22 +0530 Subject: [PATCH 03/15] =?UTF-8?q?ENH:=20add=20towncrier=20entry=20for=20mi?= =?UTF-8?q?xed=2010=E2=80=9320=20EEG=20naming=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/changes/dev/13447.enhance.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/changes/dev/13447.enhance.rst diff --git a/doc/changes/dev/13447.enhance.rst b/doc/changes/dev/13447.enhance.rst new file mode 100644 index 00000000000..4c97f24e39f --- /dev/null +++ b/doc/changes/dev/13447.enhance.rst @@ -0,0 +1,3 @@ +Improve the error message raised when mixed 10–20 EEG electrode naming +conventions (T3/T4/T5/T6 vs T7/T8/P7/P8) lead to overlapping sensor positions +during topomap plotting. From 3c3dd7816ffa3a9a83c56a1944cb50cbdaf15b78 Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Sat, 31 Jan 2026 00:42:28 +0530 Subject: [PATCH 04/15] DOC: fix towncrier entry and test regex --- doc/changes/dev/13447.newcontrib.rst | 5 +++++ doc/changes/names.inc | 1 + mne/channels/tests/test_layout.py | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 doc/changes/dev/13447.newcontrib.rst diff --git a/doc/changes/dev/13447.newcontrib.rst b/doc/changes/dev/13447.newcontrib.rst new file mode 100644 index 00000000000..79617d906a5 --- /dev/null +++ b/doc/changes/dev/13447.newcontrib.rst @@ -0,0 +1,5 @@ +:newcontrib: + +Improve the error message raised when mixed 10–20 EEG electrode naming +conventions (T3/T4/T5/T6 vs T7/T8/P7/P8) lead to overlapping sensor positions +during topomap plotting. diff --git a/doc/changes/names.inc b/doc/changes/names.inc index b684d067a1d..b395337a3e9 100644 --- a/doc/changes/names.inc +++ b/doc/changes/names.inc @@ -359,3 +359,4 @@ .. _Zhi Zhang: https://github.com/tczhangzhi/ .. _Ziyi ZENG: https://github.com/ZiyiTsang .. _Zvi Baratz: https://github.com/ZviBaratz +.. _Aasma Gupta: https://github.com/AasmaGupta diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index 8a1b32fdfed..0dccb049c56 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -200,7 +200,7 @@ def test_duplicate_1020_electrode_names_error(): with pytest.raises( ValueError, - match="10.?20", + match="mixed 10-20", ): mne.viz.plot_topomap(data, pos=info) From 7a422b827268acf3b0c5956ee655710138c8b892 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:15:42 +0000 Subject: [PATCH 05/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/changes/names.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/names.inc b/doc/changes/names.inc index b395337a3e9..33df89820ae 100644 --- a/doc/changes/names.inc +++ b/doc/changes/names.inc @@ -1,4 +1,5 @@ .. _Aaron Earle-Richardson: https://github.com/Aaronearlerichardson +.. _Aasma Gupta: https://github.com/AasmaGupta .. _Abram Hindle: https://softwareprocess.es .. _Adam Li: https://github.com/adam2392 .. _Adeline Fecker: https://github.com/adelinefecker @@ -359,4 +360,3 @@ .. _Zhi Zhang: https://github.com/tczhangzhi/ .. _Ziyi ZENG: https://github.com/ZiyiTsang .. _Zvi Baratz: https://github.com/ZviBaratz -.. _Aasma Gupta: https://github.com/AasmaGupta From ccb952752f55d54547da4f6e862ee6aecd8214b3 Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Sat, 31 Jan 2026 00:53:31 +0530 Subject: [PATCH 06/15] =?UTF-8?q?DOC:=20fix=20towncrier=20entry=20type=20f?= =?UTF-8?q?or=20mixed=2010=E2=80=9320=20EEG=20naming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/changes/dev/13447.enhance.rst | 3 --- doc/changes/dev/13447.newcontrib.rst | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 doc/changes/dev/13447.enhance.rst diff --git a/doc/changes/dev/13447.enhance.rst b/doc/changes/dev/13447.enhance.rst deleted file mode 100644 index 4c97f24e39f..00000000000 --- a/doc/changes/dev/13447.enhance.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve the error message raised when mixed 10–20 EEG electrode naming -conventions (T3/T4/T5/T6 vs T7/T8/P7/P8) lead to overlapping sensor positions -during topomap plotting. diff --git a/doc/changes/dev/13447.newcontrib.rst b/doc/changes/dev/13447.newcontrib.rst index 79617d906a5..c1d81c56626 100644 --- a/doc/changes/dev/13447.newcontrib.rst +++ b/doc/changes/dev/13447.newcontrib.rst @@ -1,5 +1 @@ -:newcontrib: - -Improve the error message raised when mixed 10–20 EEG electrode naming -conventions (T3/T4/T5/T6 vs T7/T8/P7/P8) lead to overlapping sensor positions -during topomap plotting. +Improve the error message raised by :func:`mne.viz.plot_topomap` (via :func:`mne.channels.layout._auto_topomap_coords`) when mixed 10–20 EEG electrode naming conventions are detected, by :newcontrib:`Aasma Gupta`. \ No newline at end of file From 6466c339daf285bfb2d2336ff6087e5bf76acad4 Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Sat, 31 Jan 2026 01:03:24 +0530 Subject: [PATCH 07/15] TEST: simplify for mixed 10-20 naming --- mne/channels/tests/test_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index 0dccb049c56..be5be9bfd67 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -200,7 +200,7 @@ def test_duplicate_1020_electrode_names_error(): with pytest.raises( ValueError, - match="mixed 10-20", + match="mixed 10-20 naming conventions", ): mne.viz.plot_topomap(data, pos=info) From 57091310cbb11ba1b836b5ba249088b335e3bfce Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Wed, 11 Feb 2026 00:30:41 +0530 Subject: [PATCH 08/15] =?UTF-8?q?ENH:=20recommend=20modern=2010=E2=80=9310?= =?UTF-8?q?=20electrode=20names=20and=20update=20test=20regex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mne/channels/layout.py | 14 +++++++------- mne/channels/tests/test_layout.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mne/channels/layout.py b/mne/channels/layout.py index 02995a281c1..fe7a1026a8e 100644 --- a/mne/channels/layout.py +++ b/mne/channels/layout.py @@ -987,15 +987,15 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): if duplicate_pairs: raise ValueError( - "Duplicate EEG electrode positions detected due to mixed 10–20 " + "Duplicate EEG electrode positions detected due to mixed 10-20 " "naming conventions.\n" - "You appear to have both old (T3/T4/T5/T6) and new (T7/T8/P7/P8) " - "electrode names present.\n\n" - "Please drop one set before plotting, for example:\n" - " inst.drop_channels(['T3', 'T4', 'T5', 'T6'])\n" - "or\n" - " inst.drop_channels(['T7', 'T8', 'P7', 'P8'])" + "You appear to have both legacy (T3/T4/T5/T6) and modern " + "(T7/T8/P7/P8) electrode names present. The modern convention " + "(T7/T8/P7/P8) is recommended.\n\n" + "Please drop the legacy channels before plotting, for example:\n" + " inst.drop_channels(['T3', 'T4', 'T5', 'T6'])" ) + else: raise ValueError( "The following electrodes have overlapping positions, which causes " diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index be5be9bfd67..377091cf513 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -200,7 +200,7 @@ def test_duplicate_1020_electrode_names_error(): with pytest.raises( ValueError, - match="mixed 10-20 naming conventions", + match=r"mixed 10.?20 naming conventions", ): mne.viz.plot_topomap(data, pos=info) From 99f130d504229bc9c4b11026e8ed42630b5f7b2a Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Wed, 11 Feb 2026 00:49:20 +0530 Subject: [PATCH 09/15] TEST: simplify regex match for duplicate 10-20 electrode error --- mne/channels/tests/test_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index 377091cf513..7a7c0358b31 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -200,7 +200,7 @@ def test_duplicate_1020_electrode_names_error(): with pytest.raises( ValueError, - match=r"mixed 10.?20 naming conventions", + match="Duplicate EEG electrode positions detected due to mixed 10-20", ): mne.viz.plot_topomap(data, pos=info) From 01bd7484d4418c87a237a678617007e752c7d59a Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Tue, 24 Feb 2026 12:07:25 +0530 Subject: [PATCH 10/15] Apply suggested changelog fix Co-authored-by: Eric Larson --- doc/changes/dev/13447.newcontrib.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/dev/13447.newcontrib.rst b/doc/changes/dev/13447.newcontrib.rst index c1d81c56626..50c47167211 100644 --- a/doc/changes/dev/13447.newcontrib.rst +++ b/doc/changes/dev/13447.newcontrib.rst @@ -1 +1 @@ -Improve the error message raised by :func:`mne.viz.plot_topomap` (via :func:`mne.channels.layout._auto_topomap_coords`) when mixed 10–20 EEG electrode naming conventions are detected, by :newcontrib:`Aasma Gupta`. \ No newline at end of file +Improve the error message raised by :func:`mne.viz.plot_topomap` when mixed 10–20 EEG electrode naming conventions are detected, by :newcontrib:`Aasma Gupta`. \ No newline at end of file From 083afbdf3b975280143bb7a0b17ca80238bea4c8 Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Tue, 24 Feb 2026 12:10:37 +0530 Subject: [PATCH 11/15] Applied changes to the error messages and other fixes. Co-authored-by: Scott Huberty <52462026+scott-huberty@users.noreply.github.com> --- mne/channels/layout.py | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/mne/channels/layout.py b/mne/channels/layout.py index fe7a1026a8e..37314ec0dc6 100644 --- a/mne/channels/layout.py +++ b/mne/channels/layout.py @@ -971,29 +971,21 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): for elec_i in squareform(dist < 1e-10).any(axis=0).nonzero()[0] ] - duplicates_1020 = { - "T3": "T7", - "T4": "T8", - "T5": "P7", - "T6": "P8", - } - + # Check for duplicate 10-20 channels that are aliases for the same position + LEGACY_TO_MODERN_1020 = {"T3": "T7", "T4": "T8", "T5": "P7", "T6": "P8"} names = set(problematic_electrodes) - duplicate_pairs = [ - (old, new) - for old, new in duplicates_1020.items() + conflicts = { + old: new + for old, new in LEGACY_TO_MODERN_1020.items() if old in names and new in names - ] - - if duplicate_pairs: + } + if conflicts: + overlap_info = ", ".join(f"{old}/{new}" for old, new in conflicts.items()) + drop_list = ', '.join(repr(old) for old in conflicts) raise ValueError( - "Duplicate EEG electrode positions detected due to mixed 10-20 " - "naming conventions.\n" - "You appear to have both legacy (T3/T4/T5/T6) and modern " - "(T7/T8/P7/P8) electrode names present. The modern convention " - "(T7/T8/P7/P8) is recommended.\n\n" - "Please drop the legacy channels before plotting, for example:\n" - " inst.drop_channels(['T3', 'T4', 'T5', 'T6'])" + "The following electrodes are aliases for the same physical location " + f"(10-20 vs 10-10): {overlap_info}\n. To fix this call " + f"`.drop_channels([{drop_list}])` on your Raw/Epochs/Evoked object." ) else: From 1135d3c52745cdf356c3ab137d2d1c0843f33763 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 06:40:56 +0000 Subject: [PATCH 12/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/channels/layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mne/channels/layout.py b/mne/channels/layout.py index 37314ec0dc6..0d5f614f60a 100644 --- a/mne/channels/layout.py +++ b/mne/channels/layout.py @@ -971,7 +971,7 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): for elec_i in squareform(dist < 1e-10).any(axis=0).nonzero()[0] ] - # Check for duplicate 10-20 channels that are aliases for the same position + # Check for duplicate 10-20 channels that are aliases for the same position LEGACY_TO_MODERN_1020 = {"T3": "T7", "T4": "T8", "T5": "P7", "T6": "P8"} names = set(problematic_electrodes) conflicts = { @@ -981,7 +981,7 @@ def _auto_topomap_coords(info, picks, ignore_overlap, to_sphere, sphere): } if conflicts: overlap_info = ", ".join(f"{old}/{new}" for old, new in conflicts.items()) - drop_list = ', '.join(repr(old) for old in conflicts) + drop_list = ", ".join(repr(old) for old in conflicts) raise ValueError( "The following electrodes are aliases for the same physical location " f"(10-20 vs 10-10): {overlap_info}\n. To fix this call " From 3d6335f07a4a9b045e69ceddb286ac83cd361afc Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Tue, 24 Feb 2026 12:26:46 +0530 Subject: [PATCH 13/15] trigger CI after CircleCI setup From 0542377a693fe9658e2bd9c0911ebc85cd734ff7 Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Wed, 25 Feb 2026 10:36:42 +0530 Subject: [PATCH 14/15] Update test to match revised duplicate electrode error message --- mne/channels/tests/test_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index 7a7c0358b31..7c818f63762 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -200,7 +200,7 @@ def test_duplicate_1020_electrode_names_error(): with pytest.raises( ValueError, - match="Duplicate EEG electrode positions detected due to mixed 10-20", + match="aliases for the same physical location", ): mne.viz.plot_topomap(data, pos=info) From 4e96c63707ead71bdc923856fe7b86c06ba0769a Mon Sep 17 00:00:00 2001 From: Aasma Gupta Date: Thu, 5 Mar 2026 04:30:06 +0530 Subject: [PATCH 15/15] Fix towncrier fragment type --- doc/changes/dev/{13447.newcontrib.rst => 13447.other.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/changes/dev/{13447.newcontrib.rst => 13447.other.rst} (100%) diff --git a/doc/changes/dev/13447.newcontrib.rst b/doc/changes/dev/13447.other.rst similarity index 100% rename from doc/changes/dev/13447.newcontrib.rst rename to doc/changes/dev/13447.other.rst