Repository: mne-tools/mne-python

Issue:
[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`

Discussion:
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.

Patch:
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')
 
 ###############################################################################


Test patch:
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()