[med-svn] [Git][med-team/python-mne][master] 7 commits: New upstream version

Karsten Schöke (@karso) gitlab at salsa.debian.org
Thu Apr 23 13:51:28 BST 2026



Karsten Schöke pushed to branch master at Debian Med / python-mne


Commits:
b23f8c39 by Karsten Schöke at 2026-04-23T12:21:22+02:00
New upstream version

- - - - -
732ab43f by Karsten Schöke at 2026-04-23T12:21:24+02:00
New upstream version 1.12.1
- - - - -
8ca4cfdc by Karsten Schöke at 2026-04-23T12:24:36+02:00
Update upstream source from tag 'upstream/1.12.1'

Update to upstream version '1.12.1'
with Debian dir b1016fe33461aae4b5091708eb39087f4f0c0370
- - - - -
dfdc428d by Karsten Schöke at 2026-04-23T12:28:17+02:00
Use GitHub template in watch file instead of explicit Source/Matching-Pattern.

Changes-By: lintian-brush

- - - - -
a94640da by Karsten Schöke at 2026-04-23T14:13:03+02:00
Disable pytest debug messages

  as the salsa CI pipeline only allows 4MB of log files
  and then aborts the test.

- - - - -
5dd2106d by Karsten Schöke at 2026-04-23T14:23:50+02:00
insert allow-missing-metadata-in-sys_info.patch

- - - - -
b64635c1 by Karsten Schöke at 2026-04-23T14:50:09+02:00
prepare 1.12.1-1 release.

- - - - -


20 changed files:

- .circleci/config.yml
- .git_archival.txt
- README.rst
- debian/changelog
- + debian/patches/0001-allow-missing-metadata-in-sys_info.patch
- + debian/patches/series
- debian/rules
- debian/watch
- doc/changes/v1.12.rst
- doc/install/installers.rst
- doc/sphinxext/related_software.txt
- mne/epochs.py
- mne/gui/tests/test_coreg.py
- mne/io/base.py
- mne/viz/_figure.py
- mne/viz/epochs.py
- mne/viz/raw.py
- mne/viz/tests/test_raw.py
- mne/viz/utils.py
- pyproject.toml


Changes:

=====================================
.circleci/config.yml
=====================================
@@ -537,23 +537,23 @@ workflows:
                 - main
                 - /maint\/.*/
 
-  main:
+  stable:
     jobs:
       - build_docs:
           scheduled: "true"
-          name: build_docs_main
+          name: build_docs_stable
       - deploy:
-          name: deploy_main
+          name: deploy_stable
           requires:
-            - build_docs_main
+            - build_docs_stable
     triggers:
       - schedule:
-          # "At 6:00 AM GMT every day"
-          cron: "0 6 * * *"
+          # "At 4:00 AM GMT every day"
+          cron: "0 4 * * *"
           filters:
             branches:
               only:
-                - main
+                - /maint\/.*/
 
   monthly:
     jobs:


=====================================
.git_archival.txt
=====================================
@@ -1,3 +1,3 @@
-node: 77d0960277bf5347f2b3e515f61407fc32d71ea3
-node-date: 2026-04-07T19:05:30Z
-describe-name: v1.12.0
+node: 5a67897d193a00b63ba92f2b01f4a6eb098918db
+node-date: 2026-04-20T13:06:17-04:00
+describe-name: v1.12.1


=====================================
README.rst
=====================================
@@ -74,12 +74,12 @@ The minimum required dependencies to run MNE-Python are:
 
 - `Python <https://www.python.org>`__ ≥ 3.10
 - `NumPy <https://numpy.org>`__ ≥ 1.26
-- `SciPy <https://scipy.org>`__ ≥ 1.11
+- `SciPy <https://scipy.org>`__ ≥ 1.13
 - `Matplotlib <https://matplotlib.org>`__ ≥ 3.8
 - `Pooch <https://www.fatiando.org/pooch/latest/>`__ ≥ 1.5
-- `tqdm <https://tqdm.github.io>`__
-- `Jinja2 <https://palletsprojects.com/p/jinja/>`__
-- `decorator <https://github.com/micheles/decorator>`__
+- `tqdm <https://tqdm.github.io>`__ ≥ 4.66
+- `Jinja2 <https://palletsprojects.com/p/jinja/>`__ ≥ 3.1
+- `decorator <https://github.com/micheles/decorator>`__ ≥ 5.1
 - `lazy-loader <https://pypi.org/project/lazy_loader>`__ ≥ 0.3
 - `packaging <https://packaging.pypa.io/en/stable/>`__
 


=====================================
debian/changelog
=====================================
@@ -1,3 +1,14 @@
+python-mne (1.12.1-1) UNRELEASED; urgency=medium
+
+  * Team upload.
+  * New upstream version
+  * Use GitHub template in watch file instead of explicit
+    Source/Matching-Pattern.
+  * Disable pytest debug messages
+  * insert allow-missing-metadata-in-sys_info.patch
+
+ -- Karsten Schöke <karsten.schoeke at geobasis-bb.de>  Thu, 23 Apr 2026 12:24:57 +0200
+
 python-mne (1.12.0-1) unstable; urgency=medium
 
   * Team Upload.


=====================================
debian/patches/0001-allow-missing-metadata-in-sys_info.patch
=====================================
@@ -0,0 +1,38 @@
+From: =?utf-8?q?Karsten_Sch=C3=B6ke?= <karsten.schoeke at geobasis-bb.de>
+Date: Thu, 23 Apr 2026 14:20:47 +0200
+Subject: allow missing metadata in sys_info
+ The upstream test assumes that all installed Python packages provide
+ version metadata accessible via importlib.metadata. This assumption
+ does not hold in Debian environments, especially on non-amd64
+ architectures (e.g., arm64), where packages may be built differently
+ and lack dist-info metadata.
+
+ In such cases, MNE-Python correctly falls back to '?' for unknown
+ versions. This is expected behavior and should not cause test failures.
+
+Forwarded: not-needed
+---
+ mne/utils/tests/test_config.py | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/mne/utils/tests/test_config.py b/mne/utils/tests/test_config.py
+index d203af0..e108f0f 100644
+--- a/mne/utils/tests/test_config.py
++++ b/mne/utils/tests/test_config.py
+@@ -114,7 +114,15 @@ def test_sys_info_basic():
+     assert "numpy" in out
+     # replace all in-line whitespace with single space
+     out = "\n".join(" ".join(o.split()) for o in out.splitlines())
+-    assert "?" not in out
++    # Debian: allow '?' for optional dependencies lacking metadata
++    # but ensure core system information is present and valid
++    lines = out.splitlines()
++    core_lines = [l for l in lines if l.startswith("Platform") or l.startswith("Python")]
++    for line in core_lines:
++        assert "?" not in line
++    # Ensure we still got meaningful dependency output
++    assert "numpy" in out
++
+     if platform.system() == "Darwin":
+         assert "Platform macOS-" in out
+     elif platform.system() == "Linux":


=====================================
debian/patches/series
=====================================
@@ -0,0 +1 @@
+0001-allow-missing-metadata-in-sys_info.patch


=====================================
debian/rules
=====================================
@@ -24,8 +24,7 @@ ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
 		--auto-servernum \
 		--server-num=20 \
 		-s "$(SCREEN_CONFIG)" \
-		pytest -s -v mne \
-		-k "not test_parallel_func_n_jobs_none"
+		pytest mne -k "not test_parallel_func_n_jobs_none"
 endif
 
 execute_after_dh_fixperms:


=====================================
debian/watch
=====================================
@@ -1,9 +1,5 @@
 Version: 5
 
-Source: https://github.com/mne-tools/mne-python/tags
-Matching-Pattern: .*/v?@ANY_VERSION@@ARCHIVE_EXT@
-Repack-Suffix: +dfsg
-Debian-Version-Mangle: auto
-Compression: xz
-Filename-Mangle: s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE at -$1.tar.gz%
-
+Template: GitHub
+Owner: mne-tools
+Project: mne-python


=====================================
doc/changes/v1.12.rst
=====================================
@@ -1,3 +1,14 @@
+.. _changes_1_12_1:
+
+Version 1.12.1 (2026-04-20)
+===========================
+
+New features
+------------
+
+- Add ``annotation_colors`` parameter to :meth:`mne.io.Raw.plot` and :meth:`mne.Epochs.plot` to allow users to specify custom colors for annotations by passing a dict mapping annotation description strings to colors (for example, ``annotation_colors=dict(bad_segment="orange")``), by `Clemens Brunner`_. (`#13838 <https://github.com/mne-tools/mne-python/pull/13838>`__)
+
+
 .. _changes_1_12_0:
 
 Version 1.12.0 (2026-04-07)
@@ -23,12 +34,12 @@ Bugfixes
 - Fix bug where :func:`mne.viz.plot_raw` would access incorrect matplotlib attributes, by :newcontrib:`Thomas Caswell`. (`#13606 <https://github.com/mne-tools/mne-python/pull/13606>`__)
 - Allow reading alternative nasion label ("Nz") in SNIRF files when parsing landmarkPos3D, by :newcontrib:`Aniket Singh Yadav`. (`#13672 <https://github.com/mne-tools/mne-python/pull/13672>`__)
 - Change default-pick 'data' for "eyegaze" to false, following existing documentation. by :newcontrib:`Benedikt Ehinger`. (`#13723 <https://github.com/mne-tools/mne-python/pull/13723>`__)
-  by :newcontrib:`Christoph Huber-Huber`. (`#13759 <https://github.com/mne-tools/mne-python/pull/13759>`__)
 - Fix bug in when reading EDF/GDF files where non-positive lowpass values were not handled correctly, now mapping them to the Nyquist frequency to prevent errors during plotting, by :newcontrib:`Hansuja Budhiraja`. (`#13769 <https://github.com/mne-tools/mne-python/pull/13769>`__)
 - Clearer error message when no ECG events are found in :func:`~mne.preprocessing.find_ecg_events`, by :newcontrib:`Hansuja Budhiraja`. (`#13771 <https://github.com/mne-tools/mne-python/pull/13771>`__)
 - Fix bug in 3D overlay compositing that could produce NaN RGBA values when the resulting alpha is zero, by `Pragnya Khandelwal`_. (`#13714 <https://github.com/mne-tools/mne-python/pull/13714>`__)
 - Make :meth:`~mne.io.Raw.interpolate_bads` method flexible (ignore, warn, raise) about how to handle interpolation of channels with invalid positions, by :newcontrib:`Himanshu Mahor`. (`#13518 <https://github.com/mne-tools/mne-python/pull/13518>`__)
 - Fix bug where outdated ``seghead.mgz`` files were reused in :func:`mne.bem.make_scalp_surfaces`. Add a new parameter ``reuse_seghead`` to control whether to reuse existing ``seghead.mgz`` files, by `Victor Ferat`_. (`#13024 <https://github.com/mne-tools/mne-python/pull/13024>`__)
+- When interpolating from axial to planar gradiometers, set info fields "chs", "ch_names", and "nchan", according to the interpolated data, reset info fields "device_info", "helium_info", "gantry_angle", "ctf_head_t", "dev_ctf_t", "bads", "projs", and "comps" to [] or None, and preserve all remaining info fields.   by :newcontrib:`Christoph Huber-Huber`. (`#13759 <https://github.com/mne-tools/mne-python/pull/13759>`__)
 - Clarified an internal forward-model invariant in ``mne.forward._lead_dots`` by asserting that ``rref`` is ``None`` on the current code path, by :newcontrib:`Pragnya Khandelwal`. (`#13764 <https://github.com/mne-tools/mne-python/pull/13764>`__)
 - Fix bug preventing :func:`mne.time_frequency.read_spectrum` from reading saved :class:`mne.time_frequency.Spectrum` objects created from :meth:`mne.time_frequency.EpochsSpectrum.average`, by `Thomas Binns`_. (`#13521 <https://github.com/mne-tools/mne-python/pull/13521>`__)
 - Fix bug where :func:`mne.chpi.refit_hpi` did not take ``gof_limit`` into account when fitting HPI order, by `Eric Larson`_ (`#13525 <https://github.com/mne-tools/mne-python/pull/13525>`__)
@@ -50,9 +61,6 @@ Bugfixes
 - Fix annotation removal logic in matplotlib based figures to correctly handle non-contiguous visible annotations, by `Johannes Herforth`_. (`#13703 <https://github.com/mne-tools/mne-python/pull/13703>`__)
 - Support mixed-type concatenation of :class:`mne.Annotations` and :class:`mne.HEDAnnotations`, preserving HED strings in ``extras["HED"]``, by `Bruno Aristimunha`_. (`#13736 <https://github.com/mne-tools/mne-python/pull/13736>`__)
 - Improved handling of dropped epochs in :func:`mne.viz.plot_ica_properties` and :meth:`mne.preprocessing.ICA.plot_properties`, allowing plots to be generated even with many bad annotations, by `Clemens Brunner`_. (`#13746 <https://github.com/mne-tools/mne-python/pull/13746>`__)
-- When interpolating from axial to planar gradiometers, set info fields "chs", "ch_names", and "nchan", according to the interpolated data,
-  reset info fields "device_info", "helium_info", "gantry_angle", "ctf_head_t", "dev_ctf_t", "bads", "projs", and "comps" to [] or None, and
-  preserve all remaining info fields.
 - Avoid some unnecessary computations when ``n_jobs=None`` is equivalent to ``n_jobs=1``, by `Simon Kern`_. (`#13777 <https://github.com/mne-tools/mne-python/pull/13777>`__)
 - Fix clipped annotations and x-axis label in :meth:`mne.io.Raw.plot`, by `Clemens Brunner`_. (`#13787 <https://github.com/mne-tools/mne-python/pull/13787>`__)
 - Fix bug with reading large CNT files by adding ``recompute_n_samples`` to :func:`mne.io.read_raw_cnt` with stricter ``data_format`` handling by `Teon Brooks`_ and `Eric Larson`_. (`#13548 <https://github.com/mne-tools/mne-python/pull/13548>`__)
@@ -67,7 +75,7 @@ New features
 - Add support for multi-wavelength NIRS processing to :func:`mne.preprocessing.nirs.beer_lambert_law`, :func:`mne.preprocessing.nirs.scalp_coupling_index`, and SNIRF reader :func:`mne.io.read_raw_snirf`, by :newcontrib:`Tamas Fehervari`. (`#13408 <https://github.com/mne-tools/mne-python/pull/13408>`__)
 - Add an optional ``show_channel_names`` parameter to :meth:`mne.viz.plot_alignment` to overlay channel labels at sensor locations in the 3D alignment view, by :newcontrib:`Aman Srivastava`. (`#13570 <https://github.com/mne-tools/mne-python/pull/13570>`__)
 - Add support for reading BCI2000 ``.dat`` files via :func:`mne.io.read_raw_bci2k`, and an example :file:`examples/io/read_bci2k.py` for downloading and visualizing BCI2000 data, by :newcontrib:`Hansuja Budhiraja`. (`#13699 <https://github.com/mne-tools/mne-python/pull/13699>`__)
-- Add support for scalar or per-vertex ``alpha`` (shape ``(n_vertices,)``) in distributed overlays, including validation/errors for invalid shapes, tests, and a visualization example in ``examples/visualization/brain.py`` using :meth:`mne.viz.Brain.add_data`, by :newcontrib:`Pragnya Khandelwal`. (:gh:`13706`) (`#13706 <https://github.com/mne-tools/mne-python/pull/13706>`__)
+- Add support for scalar or per-vertex ``alpha`` (shape ``(n_vertices,)``) in distributed overlays, including validation/errors for invalid shapes, tests, and a visualization example in ``examples/visualization/brain.py`` using :meth:`mne.viz.Brain.add_data`, by :newcontrib:`Pragnya Khandelwal`. (`#13706 <https://github.com/mne-tools/mne-python/pull/13706>`__)
 - Added ``cmap`` parameter to ``Evoked.animate_topomap`` to allow user-specified colormaps., by :newcontrib:`Hansuja Budhiraja`. (`#13756 <https://github.com/mne-tools/mne-python/pull/13756>`__)
 - Allow per-channel color overrides in :func:`mne.viz.plot_raw` via channel name keys in the ``color`` dict, by :newcontrib:`Hansuja Budhiraja`. (`#13765 <https://github.com/mne-tools/mne-python/pull/13765>`__)
 - Add example showing how to interoperate with R using ``rpy2``, by  :newcontrib:`Aman Srivastava`. (`#13729 <https://github.com/mne-tools/mne-python/pull/13729>`__)
@@ -83,7 +91,7 @@ Other changes
 - Created a quality control report tutorial :ref:`tut-qc-report`, by :newcontrib:`varshaa-1616`. (`#13532 <https://github.com/mne-tools/mne-python/pull/13532>`__)
 - Improved docs for :func:`mne.io.read_raw_nirx`, by :newcontrib:`Natneal B`. (`#13541 <https://github.com/mne-tools/mne-python/pull/13541>`__)
 - Refactor f-strings in ``mne/tests/test_import_nesting.py``, by :newcontrib:`Shruti Bhale`. (`#13551 <https://github.com/mne-tools/mne-python/pull/13551>`__)
-- Remove legacy Python-version compatibility checks in ``mne.utils.misc._empty_hash`` now that ``usedforsecurity=False`` is always supported, by :newcontrib:`Varun Kasyap Pentamaraju` (:gh:`13566`). (`#13566 <https://github.com/mne-tools/mne-python/pull/13566>`__)
+- Remove legacy Python-version compatibility checks in ``mne.utils.misc._empty_hash`` now that ``usedforsecurity=False`` is always supported, by :newcontrib:`Varun Kasyap Pentamaraju`. (`#13566 <https://github.com/mne-tools/mne-python/pull/13566>`__)
 - Add optional low-variance ("hat") regularization to :func:`mne.stats.f_oneway` via new ``sigma`` and ``method`` parameters, by :newcontrib:`Aniket Singh Yadav`. (`#13698 <https://github.com/mne-tools/mne-python/pull/13698>`__)
 - Improve documentation of return values to clarify that methods typically return the original instance type for chaining purposes, by :newcontrib:`Aniket Singh Yadav`. (`#13674 <https://github.com/mne-tools/mne-python/pull/13674>`__)
 - Examples Using <some-method> section quirk fix in documentation, by :newcontrib:`Himanshu Mahor`. (`#13596 <https://github.com/mne-tools/mne-python/pull/13596>`__)


=====================================
doc/install/installers.rst
=====================================
@@ -17,7 +17,7 @@ Platform-specific installers
         :class-content: text-center
         :name: install-linux
 
-        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.11.0/MNE-Python-1.11.0_0-Linux.sh
+        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.12.0-post1/MNE-Python-1.12.0_1-Linux.sh
             :ref-type: ref
             :color: primary
             :shadow:
@@ -25,20 +25,20 @@ Platform-specific installers
 
             |cloud-arrow-down| |ensp| Download for Linux
 
-        **Supported platforms:** Ubuntu 18.04 (Bionic Beaver) and newer
+        **Supported platforms:** Ubuntu 20.04 (Focal Fossa) and newer
 
         Run the installer in a terminal via:
 
         .. code-block:: console
 
-            $ sh ./MNE-Python-1.11.0_0-Linux.sh
+            $ sh ./MNE-Python-1.12.0_1-Linux.sh
 
 
     .. tab-item:: macOS (Intel)
         :class-content: text-center
         :name: install-macos-intel
 
-        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.11.0/MNE-Python-1.11.0_0-macOS_Intel.pkg
+        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.12.0-post1/MNE-Python-1.12.0_1-macOS_Intel.pkg
             :ref-type: ref
             :color: primary
             :shadow:
@@ -54,7 +54,7 @@ Platform-specific installers
         :class-content: text-center
         :name: install-macos-apple
 
-        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.11.0/MNE-Python-1.11.0_0-macOS_M1.pkg
+        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.12.0-post1/MNE-Python-1.12.0_1-macOS_M1.pkg
             :ref-type: ref
             :color: primary
             :shadow:
@@ -70,7 +70,7 @@ Platform-specific installers
         :class-content: text-center
         :name: install-windows
 
-        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.11.0/MNE-Python-1.11.0_0-Windows.exe
+        .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.12.0-post1/MNE-Python-1.12.0_1-Windows.exe
             :ref-type: ref
             :color: primary
             :shadow:
@@ -128,6 +128,14 @@ bundles to the ``Applications`` folder on macOS.
    particularly long on Apple Silicon-based computers. Subsequent runs should
    usually be much faster.
 
+The installer sets up a standard ``conda`` environment. If you want to activate the
+environment manually (e.g., in headless setups) you can do as you would for any other
+conda environment:
+
+.. code-block:: bash
+
+    $ source /path-to-installation-dir/bin/activate
+
 Uninstallation
 ^^^^^^^^^^^^^^
 
@@ -156,7 +164,7 @@ To remove the MNE-Python distribution provided by our installers above:
            .. code-block:: bash
 
                $ which python
-               /home/username/mne-python/1.11.0_0/bin/python
+               /home/username/mne-python/1.12.0_1/bin/python
                $ rm -Rf /home/$USER/mne-python
                $ rm /home/$USER/.local/share/applications/mne-python-*.desktop
 
@@ -170,7 +178,7 @@ To remove the MNE-Python distribution provided by our installers above:
            .. code-block:: bash
 
                $ which python
-               /Users/username/Applications/MNE-Python/1.11.0_0/.mne-python/bin/python
+               /Users/username/Applications/MNE-Python/1.12.0_1/.mne-python/bin/python
                $ rm -Rf /Users/$USER/Applications/MNE-Python  # if user-specific
                $ rm -Rf /Applications/MNE-Python              # if system-wide
 


=====================================
doc/sphinxext/related_software.txt
=====================================
@@ -1,5 +1,5 @@
-# cross-domain-saliency-maps requirements are onerous (torch and tensorflow)
-# so we don't add it here, and install it separately in circleci_dependencies.sh
+# related software with onerous dependencies (e.g., torch and tensorflow)
+# should be added to related_software_nodeps.txt
 alphaCSC
 autoreject
 bycycle
@@ -34,6 +34,7 @@ pycrostates
 pyprep
 pyriemann
 python-picard
+rsatoolbox
 sesameeg
 sleepecg
 tensorpac


=====================================
mne/epochs.py
=====================================
@@ -1321,6 +1321,7 @@ class BaseEpochs(
         theme=None,
         overview_mode=None,
         splash=True,
+        annotation_colors=None,
     ):
         return plot_epochs(
             self,
@@ -1347,6 +1348,7 @@ class BaseEpochs(
             theme=theme,
             overview_mode=overview_mode,
             splash=splash,
+            annotation_colors=annotation_colors,
         )
 
     @copy_function_doc_to_method_doc(plot_topo_image_epochs)


=====================================
mne/gui/tests/test_coreg.py
=====================================
@@ -34,7 +34,12 @@ nirsport2_raw_path = (
 snirf_nirsport2_raw_path = (
     data_path / "SNIRF" / "NIRx" / "NIRSport2" / "1.0.3" / "2021-05-05_001.snirf"
 )
-
+# PyVista <-> NumPy 2.4 dev (https://github.com/pyvista/pyvista/issues/8484)
+pytestmark = [
+    pytest.mark.filterwarnings(
+        "ignore:Setting the dtype on a NumPy array.*:DeprecationWarning"
+    ),
+]
 
 pytest.importorskip("nibabel")
 


=====================================
mne/io/base.py
=====================================
@@ -1964,6 +1964,7 @@ class BaseRaw(
         bad_color="lightgray",
         event_color="cyan",
         *,
+        annotation_colors=None,
         annotation_regex=".*",
         scalings=None,
         remove_dc=True,
@@ -2004,6 +2005,7 @@ class BaseRaw(
             color,
             bad_color,
             event_color,
+            annotation_colors=annotation_colors,
             annotation_regex=annotation_regex,
             scalings=scalings,
             remove_dc=remove_dc,


=====================================
mne/viz/_figure.py
=====================================
@@ -167,16 +167,24 @@ class BrowserBase(ABC):
 
     def _setup_annotation_colors(self):
         """Set up colors for annotations; init some annotation vars."""
+        from matplotlib.colors import to_hex
+
         segment_colors = getattr(self.mne, "annotation_segment_colors", dict())
         labels = self._get_annotation_labels()
+        user_colors = {
+            k: to_hex(v)
+            for k, v in (getattr(self.mne, "annotation_colors", None) or {}).items()
+        }
         red = "#ff0000"
         colors = _get_color_list(remove=("#fa8174", "#d62728", "#ff0000"))
         color_cycle = cycle(colors)
         for key, color in segment_colors.items():
-            if color != red and key in labels:
+            if color != red and key in labels and key not in user_colors:
                 next(color_cycle)
         for idx, key in enumerate(labels):
-            if key.lower().startswith("bad") or key.lower().startswith("edge"):
+            if key in user_colors:
+                segment_colors[key] = user_colors[key]
+            elif key.lower().startswith("bad") or key.lower().startswith("edge"):
                 segment_colors[key] = red
             elif key in segment_colors:
                 continue


=====================================
mne/viz/epochs.py
=====================================
@@ -29,6 +29,7 @@ from .utils import (
     _handle_precompute,
     _make_combine_callable,
     _make_event_color_dict,
+    _normalize_annotation_colors,
     _set_title_multiple_electrodes,
     _set_window_title,
     _setup_cmap,
@@ -763,6 +764,7 @@ def plot_epochs(
     theme=None,
     overview_mode=None,
     splash=True,
+    annotation_colors=None,
 ):
     """Visualize epochs.
 
@@ -865,6 +867,14 @@ def plot_epochs(
     %(splash)s
 
         .. versionadded:: 1.6
+    annotation_colors : dict | None
+        A dictionary mapping annotation description strings to colors. Use this to
+        override the default color assigned to specific annotation types (e.g.,
+        ``dict(bad_segment='orange')``). Colors can be any valid Matplotlib color
+        specification. Keys that do not match any annotation description in the data
+        will trigger a warning. If ``None`` (default), automatic colors are used.
+
+        .. versionadded:: 1.12.1
 
     Returns
     -------
@@ -1014,6 +1024,13 @@ def plot_epochs(
         raise TypeError(f"title must be None or a string, got a {type(title)}")
 
     precompute = _handle_precompute(precompute)
+
+    # handle annotation_colors
+    if annotation_colors is not None:
+        annotation_colors = _normalize_annotation_colors(
+            annotation_colors, epochs.annotations
+        )
+
     params = dict(
         inst=epochs,
         info=info,
@@ -1058,6 +1075,7 @@ def plot_epochs(
         ch_color_dict=color,
         epoch_color_bad=(1, 0, 0),
         epoch_colors=epoch_colors,
+        annotation_colors=annotation_colors,
         # display
         butterfly=butterfly,
         clipping=None,


=====================================
mne/viz/raw.py
=====================================
@@ -11,7 +11,13 @@ import numpy as np
 from .._fiff.pick import _picks_to_idx, pick_channels, pick_types
 from ..defaults import _handle_default
 from ..filter import create_filter
-from ..utils import _check_option, _get_stim_channel, _validate_type, legacy, verbose
+from ..utils import (
+    _check_option,
+    _get_stim_channel,
+    _validate_type,
+    legacy,
+    verbose,
+)
 from ..utils.spectrum import _split_psd_kwargs
 from .utils import (
     _check_cov,
@@ -20,6 +26,7 @@ from .utils import (
     _handle_decim,
     _handle_precompute,
     _make_event_color_dict,
+    _normalize_annotation_colors,
     _shorten_path_from_middle,
 )
 
@@ -38,6 +45,7 @@ def plot_raw(
     bad_color="lightgray",
     event_color="cyan",
     *,
+    annotation_colors=None,
     annotation_regex=".*",
     scalings=None,
     remove_dc=True,
@@ -104,6 +112,14 @@ def plot_raw(
         Color to make bad channels.
     %(event_color)s
         Defaults to ``'cyan'``.
+    annotation_colors : dict | None
+        A dictionary mapping annotation description strings to colors. Use this to
+        override the default color assigned to specific annotation types (e.g.,
+        ``dict(bad_segment='orange')``). Colors can be any valid Matplotlib color
+        specification. Keys that do not match any annotation description in the data
+        will trigger a warning. If ``None`` (default), automatic colors are used.
+
+        .. versionadded:: 1.13
     annotation_regex : str
         A regex pattern applied to each annotation's label.
         Matching labels remain visible, non-matching labels are hidden.
@@ -335,6 +351,12 @@ def plot_raw(
     if order.size == 0:
         raise RuntimeError("No channels found to plot")
 
+    # handle annotation_colors
+    if annotation_colors is not None:
+        annotation_colors = _normalize_annotation_colors(
+            annotation_colors, raw.annotations
+        )
+
     # handle event colors
     event_color_dict = _make_event_color_dict(event_color, events, event_id)
 
@@ -399,6 +421,7 @@ def plot_raw(
         # colors
         ch_color_bad=bad_color,
         ch_color_dict=color,
+        annotation_colors=annotation_colors,
         # display
         butterfly=butterfly,
         clipping=clipping,


=====================================
mne/viz/tests/test_raw.py
=====================================
@@ -865,6 +865,44 @@ def test_plot_annotations(raw, browser_backend):
         assert "A" in raw.annotations.description
 
 
+def test_annotation_colors(raw, browser_backend):
+    """Test that annotation_colors overrides default colors."""
+    from matplotlib.colors import to_hex
+
+    with raw.info._unlock():
+        raw.info["lowpass"] = 10.0
+
+    raw.set_annotations(
+        Annotations(
+            onset=[1, 3, 5],
+            duration=[1, 1, 1],
+            description=["BAD_test", "BAD_other", "stimulus"],
+        )
+    )
+
+    # User-provided colors override defaults (including bad* → red rule).
+    # BAD_other has no override and should remain red.
+    fig = raw.plot(
+        annotation_colors={"BAD_test": "orange", "stimulus": "#00ff00"},
+    )
+    colors = fig.mne.annotation_segment_colors
+    assert colors["BAD_test"] == to_hex("orange"), (
+        "User color for BAD_test should override red default"
+    )
+    assert colors["stimulus"] == "#00ff00"
+    assert colors["BAD_other"] == "#ff0000", (
+        "BAD_other has no user override and should remain red"
+    )
+
+    # Unknown label key triggers a warning
+    with pytest.warns(RuntimeWarning, match="do not match"):
+        fig = raw.plot(annotation_colors={"nonexistent_label": "blue"})
+
+    # Invalid color value raises ValueError
+    with pytest.raises(ValueError, match="not a valid matplotlib color"):
+        raw.plot(annotation_colors={"BAD_test": "not_a_color"}, show=False)
+
+
 @pytest.mark.parametrize("active_annot_idx", (0, 1, 2))
 def test_overlapping_annotation_deletion(raw, browser_backend, active_annot_idx):
     """Test deletion of annotations via right-click."""


=====================================
mne/viz/utils.py
=====================================
@@ -2866,3 +2866,34 @@ def _get_plot_ch_type(inst, ch_type, allow_ref_meg=False):
                 f"No plottable channel types found. Allowed types are: {allowed_types}"
             )
     return ch_type
+
+
+def _normalize_annotation_colors(annotation_colors, annotations):
+    """Normalize annotation_colors and check that keys match annotation descriptions.
+
+    Parameters
+    ----------
+    annotation_colors : dict[str, color]
+        The annotation colors to normalize (``color`` can be any valid Matplotlib color
+        specification).
+    annotations : mne.Annotations
+        The Annotations object to check against.
+    """
+    from matplotlib.colors import to_hex
+
+    _validate_type(annotation_colors, dict, "annotation_colors")
+    normalized = {}
+    for k, v in annotation_colors.items():
+        try:
+            normalized[k] = to_hex(v)
+        except ValueError:
+            raise ValueError(
+                f"annotation_colors[{k!r}] is not a valid matplotlib color: {v!r}"
+            ) from None
+    unknown = set(normalized) - set(annotations.description)
+    if unknown:
+        warn(
+            "The following annotation_colors keys do not match any annotation "
+            f"description in the data: {sorted(unknown)}"
+        )
+    return normalized


=====================================
pyproject.toml
=====================================
@@ -110,7 +110,6 @@ dependencies = [
   "tqdm >= 4.66",
 ]
 description = "MNE-Python project for MEG and EEG data analysis."
-dynamic = ["version"]
 keywords = [
   "brain",
   "ECoG",
@@ -130,6 +129,7 @@ requires-python = ">= 3.10"
 # command in `.github/workflows/spec_zero.yaml` (astral-sh/uv/#16333), and also the
 # `python` version for the `kind: old` matrix entry in `.github/workflows/tests.yaml`
 scripts = {mne = "mne.commands.utils:main"}
+version = "1.12.1"
 
 [project.optional-dependencies]
 # Leave this one here for backward-compat



View it on GitLab: https://salsa.debian.org/med-team/python-mne/-/compare/e172e5c94789c23ab92cff1778c01a353d742e0a...b64635c19715bb30355de6d26490c6d894e03041

-- 
View it on GitLab: https://salsa.debian.org/med-team/python-mne/-/compare/e172e5c94789c23ab92cff1778c01a353d742e0a...b64635c19715bb30355de6d26490c6d894e03041
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260423/beb05378/attachment-0001.htm>


More information about the debian-med-commit mailing list