Repository: mne-tools/mne-python

Issue:
Magnetometer positions look odd in PSD plot
#### Steps to reproduce
Let's first visualize the magnetometer channel positions via `Raw.plot_sensors()`:
```python
import mne
from mne.datasets import sample


data_path = sample.data_path()
fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
raw = mne.io.read_raw_fif(fname)
raw.plot_sensors(ch_type='mag')
```
This produces:
![sensors](https://user-images.githubusercontent.com/2046265/83051600-85bef900-a04e-11ea-9fe5-fbc2be43c365.png)

Looking good. Now let's plot PSDs of the data.

```python
raw.plot_psd()
```
Result cropped so it only shows the sensor positions (top to bottom: mag, grad, eeg):
![Figure_1 copy](https://user-images.githubusercontent.com/2046265/83051304-1ea14480-a04e-11ea-8017-51b1b17aa1e8.png)

The magnetometer sensor layout looks incorrect, and doesn't match the one produced by `plot_sensors()`. Am I missing something here?

cc @agramfort 


Discussion:
to me yes we have a bug.

any idea @larsoner ?

>

Agreed it's a bug, no idea the cause. Someone will have to dig into the viz code to figure out why this is happening...
this allows to clearly show the bug:

```
import mne
import os

sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = os.path.join(sample_data_folder, 'MEG', 'sample',
                                    'sample_audvis_raw.fif')
raw = mne.io.read_raw_fif(sample_data_raw_file, preload=True)
raw.plot_psd(picks=['grad'])
raw.plot_psd(picks=['mag'])
raw.plot_psd(picks=['meg'])
```
and the bad news is that the bug is in the 0.20 stable release :( :( 
I'll `git bisect` and see how hard it is to fix
thanks
Looks like it was 9e785061f325191b809ade41590887230c1378ec / #7486, cc @drammock -- I'll see if I can figure out what the problem is

Resolving patch:
diff --git a/mne/io/pick.py b/mne/io/pick.py
--- a/mne/io/pick.py
+++ b/mne/io/pick.py
@@ -1141,8 +1141,7 @@ def _get_channel_types(info, picks=None, unique=False, only_data_chs=False):
     """Get the data channel types in an info instance."""
     none = 'data' if only_data_chs else 'all'
     picks = _picks_to_idx(info, picks, none, (), allow_empty=False)
-    ch_types = [channel_type(info, idx) for idx in range(info['nchan'])
-                if idx in picks]
+    ch_types = [channel_type(info, pick) for pick in picks]
     if only_data_chs:
         ch_types = [ch_type for ch_type in ch_types
                     if ch_type in _DATA_CH_TYPES_SPLIT]


Test patch:
diff --git a/mne/io/tests/test_pick.py b/mne/io/tests/test_pick.py
--- a/mne/io/tests/test_pick.py
+++ b/mne/io/tests/test_pick.py
@@ -1,5 +1,4 @@
 from copy import deepcopy
-import inspect
 import os.path as op
 
 from numpy.testing import assert_array_equal, assert_equal
@@ -21,14 +20,14 @@
 from mne.datasets import testing
 from mne.utils import run_tests_if_main, catch_logging, assert_object_equal
 
-io_dir = op.join(op.dirname(inspect.getfile(inspect.currentframe())), '..')
 data_path = testing.data_path(download=False)
 fname_meeg = op.join(data_path, 'MEG', 'sample',
                      'sample_audvis_trunc-meg-eeg-oct-4-fwd.fif')
 fname_mc = op.join(data_path, 'SSS', 'test_move_anon_movecomp_raw_sss.fif')
 
-base_dir = op.join(op.dirname(__file__), 'data')
-ctf_fname = op.join(base_dir, 'test_ctf_raw.fif')
+io_dir = op.join(op.dirname(__file__), '..')
+ctf_fname = op.join(io_dir, 'tests', 'data', 'test_ctf_raw.fif')
+fif_fname = op.join(io_dir, 'tests', 'data', 'test_raw.fif')
 
 
 def _picks_by_type_old(info, meg_combined=False, ref_meg=False,
@@ -570,4 +569,23 @@ def test_pick_types_deprecation():
     assert list(pick_types(info2, eeg=True)) == [0, 1]
 
 
+@pytest.mark.parametrize('meg', [True, False, 'grad', 'mag'])
+@pytest.mark.parametrize('eeg', [True, False])
+@pytest.mark.parametrize('ordered', [True, False])
+def test_get_channel_types_equiv(meg, eeg, ordered):
+    """Test equivalence of get_channel_types."""
+    raw = read_raw_fif(fif_fname)
+    pick_types(raw.info, meg=meg, eeg=eeg)
+    picks = pick_types(raw.info, meg=meg, eeg=eeg)
+    if not ordered:
+        picks = np.random.RandomState(0).permutation(picks)
+    if not meg and not eeg:
+        with pytest.raises(ValueError, match='No appropriate channels'):
+            raw.get_channel_types(picks=picks)
+        return
+    types = np.array(raw.get_channel_types(picks=picks))
+    types_iter = np.array([channel_type(raw.info, idx) for idx in picks])
+    assert_array_equal(types, types_iter)
+
+
 run_tests_if_main()