Repository: mne-tools/mne-python

Issue:
VIZ: bug in plot_sensors(kind='3d')
#### Describe the bug
When plotting MEG and EEG sensors at the same time, the EEG and MEG sensors appear in the wrong position relative to one another.  Presumably this is an issue of which coordinate frame is chosen.  An example is [here](https://mne.tools/dev/auto_tutorials/epochs/plot_20_visualize_epochs.html#plotting-sensor-locations), where the EEG sensors are higher up than the MEG sensors (implying that the subject's head was embedded in the MEG helmet).

#### Steps to reproduce
See [the linked tutorial](https://mne.tools/dev/auto_tutorials/epochs/plot_20_visualize_epochs.html#plotting-sensor-locations).

@agramfort WDYT?  @larsoner suggested (offline) that if `ch_type='all'` then everything should get transformed to head coords, but if only plotting a single sensor type we can plot in whatever coord sys they're in.  If the overhead is not too bad, I might suggest always plotting in head coords, even if only one sensor type is chosen.  As an aside, it might also be good to label the 3d plot axes with a unit (meters).


Discussion:
+1 with what @larsoner suggested.

>

> If the overhead is not too bad

Transform overhead should be negligible.

> I might suggest always plotting in head coords, even if only one sensor type is chosen.

I was actually starting to think the same thing. So I would say to always use head coords for now, and if people want MEG sensors in MEG coords we can add `coord_frame` later -- or just tell them to use `plot_alignment` which already has these transform options built in.

>  As an aside, it might also be good to label the 3d plot axes with a unit (meters).

Agreed, feel free to add this at the same time as the coord frame changes

Resolving patch:
diff --git a/mne/viz/utils.py b/mne/viz/utils.py
--- a/mne/viz/utils.py
+++ b/mne/viz/utils.py
@@ -28,6 +28,7 @@
 from ..defaults import _handle_default
 from ..fixes import _get_status
 from ..io import show_fiff, Info
+from ..io.constants import FIFF
 from ..io.pick import (channel_type, channel_indices_by_type, pick_channels,
                        _pick_data_channels, _DATA_CH_TYPES_SPLIT, pick_types,
                        pick_info, _picks_by_type, pick_channels_cov,
@@ -41,6 +42,7 @@
 from ..selection import (read_selection, _SELECTIONS, _EEG_SELECTIONS,
                          _divide_to_regions)
 from ..annotations import _sync_onset
+from ..transforms import apply_trans
 
 
 _channel_type_prettyprint = {'eeg': "EEG channel", 'grad': "Gradiometer",
@@ -1600,7 +1602,9 @@ def plot_sensors(info, kind='topomap', ch_type=None, title=None,
     chs = [info['chs'][pick] for pick in picks]
     if not _check_ch_locs(chs):
         raise RuntimeError('No valid channel positions found')
-    pos = np.array([ch['loc'][:3] for ch in chs])
+    pos = np.array([apply_trans(info['dev_head_t'], ch['loc'][:3])
+                    if ch['coord_frame'] == FIFF.FIFFV_COORD_DEVICE else
+                    ch['loc'][:3] for ch in chs])
     ch_names = np.array([ch['ch_name'] for ch in chs])
     bads = [idx for idx, name in enumerate(ch_names) if name in info['bads']]
     if ch_groups is None:
@@ -1706,9 +1710,9 @@ def _plot_sensors(pos, info, picks, colors, bads, ch_names, title, show_names,
 
         ax.azim = 90
         ax.elev = 0
-        ax.xaxis.set_label_text('x')
-        ax.yaxis.set_label_text('y')
-        ax.zaxis.set_label_text('z')
+        ax.xaxis.set_label_text('x (m)')
+        ax.yaxis.set_label_text('y (m)')
+        ax.zaxis.set_label_text('z (m)')
     else:  # kind in 'select', 'topomap'
         ax.text(0, 0, '', zorder=1)
 
diff --git a/tutorials/epochs/plot_20_visualize_epochs.py b/tutorials/epochs/plot_20_visualize_epochs.py
--- a/tutorials/epochs/plot_20_visualize_epochs.py
+++ b/tutorials/epochs/plot_20_visualize_epochs.py
@@ -113,8 +113,8 @@
 # Plotting sensor locations
 # ^^^^^^^^^^^^^^^^^^^^^^^^^
 #
-# Just like :class:`~mne.io.Raw` objects, :class:`~mne.Epochs` objects keep
-# track of sensor locations, which can be visualized with the
+# Just like :class:`~mne.io.Raw` objects, :class:`~mne.Epochs` objects
+# keep track of sensor locations, which can be visualized with the
 # :meth:`~mne.Epochs.plot_sensors` method:
 
 epochs.plot_sensors(kind='3d', ch_type='all')


Test patch: