larsoner: Can you please touch the `tutorials/plot_visualize_evoked.py` file (make some small wording fix) so that CircleCI will build it? That way we can visually verify the fix.
GuillaumeFavelier: Ok, I'm on it.
GuillaumeFavelier: do I need to use `[circle full]` in the commit message?
larsoner: No, that causes CircleCI to build *all* examples. The default mode when building a PR is to only build examples changed in the given PR.
diff --git a/doc/whats_new.rst b/doc/whats_new.rst
index 1fc8a2446..0312eb299 100644
--- a/doc/whats_new.rst
+++ b/doc/whats_new.rst
@@ -69,6 +69,8 @@ Changelog
 
 - Add ``channel_wise`` argument to :func:`mne.io.Raw.apply_function` to allow applying a function on multiple channels at once by `Hubert Banville`_
 
+- Allow string argument in :meth:`mne.io.Raw.drop_channels` to remove a single channel by `Clemens Brunner`_
+
 Bug
 ~~~
 
diff --git a/mne/channels/channels.py b/mne/channels/channels.py
index decb3642c..3bdf035b4 100644
--- a/mne/channels/channels.py
+++ b/mne/channels/channels.py
@@ -763,12 +763,12 @@ class UpdateChannelsMixin(object):
         return self._pick_drop_channels(idx)
 
     def drop_channels(self, ch_names):
-        """Drop some channels.
+        """Drop channel(s).
 
         Parameters
         ----------
-        ch_names : list
-            List of the names of the channels to remove.
+        ch_names : list or str
+            List of channel name(s) or channel name to remove.
 
         Returns
         -------
@@ -785,23 +785,23 @@ class UpdateChannelsMixin(object):
         -----
         .. versionadded:: 0.9.0
         """
-        msg = ("'ch_names' should be a list of strings (the name[s] of the "
-               "channel to be dropped), not a {0}.")
-        if isinstance(ch_names, str):
-            raise ValueError(msg.format("string"))
+        if isinstance(ch_names, list):
+            if not all([isinstance(ch, str) for ch in ch_names]):
+                raise ValueError("'ch_names' must be a list of strings, got "
+                                 "{}.".format([type(ch) for ch in ch_names]))
+        elif isinstance(ch_names, str):
+            ch_names = [ch_names]
         else:
-            if not all([isinstance(ch_name, str)
-                        for ch_name in ch_names]):
-                raise ValueError(msg.format(type(ch_names[0])))
+            raise ValueError("'ch_names' must be a list or a string, got "
+                             "{}.".format(type(ch_names)))
 
-        missing = [ch_name for ch_name in ch_names
-                   if ch_name not in self.ch_names]
+        missing = [ch for ch in ch_names if ch not in self.ch_names]
         if len(missing) > 0:
             msg = "Channel(s) {0} not found, nothing dropped."
             raise ValueError(msg.format(", ".join(missing)))
 
-        bad_idx = [self.ch_names.index(ch_name) for ch_name in ch_names
-                   if ch_name in self.ch_names]
+        bad_idx = [self.ch_names.index(ch) for ch in ch_names
+                   if ch in self.ch_names]
         idx = np.setdiff1d(np.arange(len(self.ch_names)), bad_idx)
         return self._pick_drop_channels(idx)
 
diff --git a/mne/chpi.py b/mne/chpi.py
index dd6519f47..a5cdbcafb 100644
--- a/mne/chpi.py
+++ b/mne/chpi.py
@@ -178,13 +178,13 @@ def _calculate_head_pos_ctf(raw, gof_limit=0.98):
     -----
     CTF continuous head monitoring stores the x,y,z location (m) of each chpi
     coil as separate channels in the dataset.
-    HLC001[123]-\\* - nasion
-    HLC002[123]-\\* - lpa
-    HLC003[123]-\\* - rpa
+    HLC001[123]\\* - nasion
+    HLC002[123]\\* - lpa
+    HLC003[123]\\* - rpa
     """
     # Pick channels cooresponding to the cHPI positions
     hpi_picks = pick_channels_regexp(raw.info['ch_names'],
-                                     'HLC00[123][123]-.*')
+                                     'HLC00[123][123].*')
 
     # make sure we get 9 channels
     if len(hpi_picks) != 9:
diff --git a/mne/io/reference.py b/mne/io/reference.py
index a31a4e02d..ba27a2b9c 100644
--- a/mne/io/reference.py
+++ b/mne/io/reference.py
@@ -522,7 +522,7 @@ def set_bipolar_reference(inst, anode, cathode, ch_name=None, ch_info=None,
 
     # Drop remaining channels.
     if drop_refs:
-        drop_channels = (set(anode) | set(cathode)) & set(inst.ch_names)
+        drop_channels = list((set(anode) | set(cathode)) & set(inst.ch_names))
         inst.drop_channels(drop_channels)
 
     return inst
diff --git a/mne/viz/_3d.py b/mne/viz/_3d.py
index ead66f867..d526d1d8b 100644
--- a/mne/viz/_3d.py
+++ b/mne/viz/_3d.py
@@ -390,7 +390,7 @@ def plot_evoked_field(evoked, surf_maps, time=None, time_label='t = %0.0f ms',
         # Now show our field pattern
         with warnings.catch_warnings(record=True):  # traits
             renderer.surface(surface=surf, vmin=-vlim, vmax=vlim,
-                             colormap=colormap)
+                             scalars=data, colormap=colormap)
 
         # And the field lines on top
         with warnings.catch_warnings(record=True):  # traits
diff --git a/mne/viz/backends/_pysurfer_mayavi.py b/mne/viz/backends/_pysurfer_mayavi.py
index 890e100ae..0ec845e17 100644
--- a/mne/viz/backends/_pysurfer_mayavi.py
+++ b/mne/viz/backends/_pysurfer_mayavi.py
@@ -152,8 +152,8 @@ class _Renderer(object):
             opacity=opacity, figure=self.fig)
         cont.module_manager.scalar_lut_manager.lut.table = colormap
 
-    def surface(self, surface, color=(0.7, 0.7, 0.7), opacity=1.0,
-                vmin=None, vmax=None, colormap=None,
+    def surface(self, surface, color=None, opacity=1.0,
+                vmin=None, vmax=None, colormap=None, scalars=None,
                 backface_culling=False):
         """Add a surface in the scene.
 
@@ -177,7 +177,7 @@ class _Renderer(object):
             If True, enable backface culling on the surface.
         """
         # Make a solid surface
-        mesh = _create_mesh_surf(surface, self.fig)
+        mesh = _create_mesh_surf(surface, self.fig, scalars=scalars)
         surface = self.mlab.pipeline.surface(
             mesh, color=color, opacity=opacity, vmin=vmin, vmax=vmax,
             figure=self.fig)
diff --git a/tutorials/plot_visualize_evoked.py b/tutorials/plot_visualize_evoked.py
index 8b16c59f2..31199f0dd 100644
--- a/tutorials/plot_visualize_evoked.py
+++ b/tutorials/plot_visualize_evoked.py
@@ -73,7 +73,7 @@ times = np.arange(0.05, 0.151, 0.05)
 evoked_r_aud.plot_topomap(times=times, ch_type='mag', time_unit='s')
 
 ###############################################################################
-# Or we can automatically select the peaks.
+# Or we can select automatically the peaks.
 evoked_r_aud.plot_topomap(times='peaks', ch_type='mag', time_unit='s')
 
 ###############################################################################

[VIZ] Rendering bug in plot_evoked_field()
#### Describe the bug
Rendering bug introduced by the migration to the renderer backend.

Current result:
![image](https://user-images.githubusercontent.com/18143289/53101126-6f5fee80-3529-11e9-991a-f40d0ed5dfe7.png)

Correct result:
![image](https://user-images.githubusercontent.com/18143289/53101083-5f480f00-3529-11e9-9f06-8d3fa48504c8.png)

#### Steps and/or code to reproduce
Follow the example  : *Visualize Evoked data*
`$ ipython --matplotlib --gui=qt tutorials/plot_visualize_evoked.py`
diff --git a/mne/channels/tests/test_channels.py b/mne/channels/tests/test_channels.py
index be52b071a..74a55593d 100644
--- a/mne/channels/tests/test_channels.py
+++ b/mne/channels/tests/test_channels.py
@@ -293,4 +293,13 @@ def test_find_ch_connectivity():
     pytest.raises(ValueError, find_ch_connectivity, raw.info, 'eog')
 
 
+def test_drop_channels():
+    """Test if dropping channels works with various arguments."""
+    raw = read_raw_fif(raw_fname, preload=True).crop(0, 0.1)
+    raw.drop_channels(["MEG 0111"])  # list argument
+    raw.drop_channels("MEG 0112")  # str argument
+    pytest.raises(ValueError, raw.drop_channels, ["MEG 0111", 5])
+    pytest.raises(ValueError, raw.drop_channels, 5)  # must be list or str
+
+
 run_tests_if_main()

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
apptools==5.3.0
babel==2.17.0
certifi==2025.1.31
charset-normalizer==3.4.1
contourpy==1.3.0
coverage==7.8.0
cycler==0.12.1
deepdiff==8.4.2
dipy==1.10.0
docutils==0.21.2
envisage==7.0.3
exceptiongroup==1.2.2
execnet==2.1.1
flake8==7.2.0
fonttools==4.56.0
h5py==3.13.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
importlib_resources==6.5.2
iniconfig==2.1.0
Jinja2==3.1.6
joblib==1.4.2
kiwisolver==1.4.7
lxml==5.3.1
MarkupSafe==3.0.2
matplotlib==3.9.4
mayavi==4.8.2
mccabe==0.7.0
-e git+https://github.com/mne-tools/mne-python.git@5537ba206f101bd2c191a6a63d9575b858f74dd3#egg=mne
neo==0.14.0
nibabel==5.3.2
nilearn==0.11.1
numexpr==2.10.2
numpy==2.0.2
numpydoc==1.8.0
orderly-set==5.3.0
packaging==24.2
pandas==2.2.3
patsy==1.0.1
pillow==11.1.0
pluggy==1.5.0
psutil==7.0.0
pycodestyle==2.13.0
pydocstyle==6.3.0
pyface==8.0.0
pyflakes==3.3.1
Pygments==2.19.1
pyparsing==3.2.3
PyQt5==5.15.11
PyQt5-Qt5==5.15.16
PyQt5_sip==12.17.0
pysurfer @ https://api.github.com/repos/nipy/PySurfer/zipball/master#sha256=3832922dcfbe6612b1fe8c0618b82e9212d3a64964fbbad174e1c75a8c230808
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.0.0
pytest-faulthandler==2.0.1
pytest-mock==3.14.0
pytest-sugar==1.0.0
pytest-timeout==2.3.1
pytest-xdist==3.6.1
python-dateutil==2.9.0.post0
python-picard==0.8
pytz==2025.2
quantities==0.16.1
requests==2.32.3
scikit-learn==1.6.1
scipy==1.13.1
setuptools-scm==8.2.0
sip==6.10.0
six==1.17.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
statsmodels==0.14.4
tabulate==0.9.0
termcolor==2.5.0
threadpoolctl==3.6.0
tomli==2.2.1
tqdm==4.67.1
traits==7.0.2
traitsui==8.0.0
trx-python==0.3
typing_extensions==4.13.0
tzdata==2025.2
urllib3==2.3.0
vtk==9.4.2
xlrd==2.0.1
zipp==3.21.0

name: mne-python
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - apptools==5.3.0
      - babel==2.17.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - contourpy==1.3.0
      - coverage==7.8.0
      - cycler==0.12.1
      - deepdiff==8.4.2
      - dipy==1.10.0
      - docutils==0.21.2
      - envisage==7.0.3
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - flake8==7.2.0
      - fonttools==4.56.0
      - h5py==3.13.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - importlib-resources==6.5.2
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - joblib==1.4.2
      - kiwisolver==1.4.7
      - lxml==5.3.1
      - markupsafe==3.0.2
      - matplotlib==3.9.4
      - mayavi==4.8.2
      - mccabe==0.7.0
      - neo==0.14.0
      - nibabel==5.3.2
      - nilearn==0.11.1
      - numexpr==2.10.2
      - numpy==2.0.2
      - numpydoc==1.8.0
      - orderly-set==5.3.0
      - packaging==24.2
      - pandas==2.2.3
      - patsy==1.0.1
      - pillow==11.1.0
      - pluggy==1.5.0
      - psutil==7.0.0
      - pycodestyle==2.13.0
      - pydocstyle==6.3.0
      - pyface==8.0.0
      - pyflakes==3.3.1
      - pygments==2.19.1
      - pyparsing==3.2.3
      - pyqt5==5.15.11
      - pyqt5-qt5==5.15.16
      - pyqt5-sip==12.17.0
      - pysurfer==0.12.dev0
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - pytest-faulthandler==2.0.1
      - pytest-mock==3.14.0
      - pytest-sugar==1.0.0
      - pytest-timeout==2.3.1
      - pytest-xdist==3.6.1
      - python-dateutil==2.9.0.post0
      - python-picard==0.8
      - pytz==2025.2
      - quantities==0.16.1
      - requests==2.32.3
      - scikit-learn==1.6.1
      - scipy==1.13.1
      - setuptools-scm==8.2.0
      - sip==6.10.0
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - statsmodels==0.14.4
      - tabulate==0.9.0
      - termcolor==2.5.0
      - threadpoolctl==3.6.0
      - tomli==2.2.1
      - tqdm==4.67.1
      - traits==7.0.2
      - traitsui==8.0.0
      - trx-python==0.3
      - typing-extensions==4.13.0
      - tzdata==2025.2
      - urllib3==2.3.0
      - vtk==9.4.2
      - xlrd==2.0.1
      - zipp==3.21.0
prefix: /opt/conda/envs/mne-python

mne/channels/tests/test_channels.py::test_drop_channels
mne/channels/tests/test_channels.py::test_reorder_channels mne/channels/tests/test_channels.py::test_read_ch_connectivity mne/channels/tests/test_channels.py::test_get_set_sensor_positions
mne/channels/tests/test_channels.py::test_rename_channels mne/channels/tests/test_channels.py::test_set_channel_types
mne/channels/channels.py mne/viz/backends/_pysurfer_mayavi.py doc/whats_new.rst mne/viz/_3d.py mne/io/reference.py mne/chpi.py tutorials/plot_visualize_evoked.py
mne/channels/channels.py mne/viz/backends/_pysurfer_mayavi.py doc/whats_new.rst mne/viz/_3d.py mne/io/reference.py mne/chpi.py tutorials/plot_visualize_evoked.py