Repository: mne-tools/mne-python

Issue:
'No data channels found' with plot_psd() on misc channels
**Issue:**
Error of "No Data channels found" when attempting to **plot_psd()** on **misc** channels in a dataset which contains only **misc** channels. The dataset is created from raw numpy EEG data derived from a custom made device.

**Platform**
```
Platform:      Darwin-19.3.0-x86_64-i386-64bit
Python:        3.7.7 (default, Mar 10 2020, 15:43:33)  [Clang 11.0.0 (clang-1100.0.33.17)]
mne:           0.21.dev0
numpy:         1.18.2 {blas=openblas, lapack=openblas}
scipy:         1.4.1
matplotlib:    3.2.1 {backend=MacOSX}
```

**Steps:**
Create mne object from raw data
```
mne_data = create_mne_object(channels, data, samp_freq)
print(mne_data)
print(mne_data.info)
```

The output is shown below. 
```
<RawArray | 2 x 1024 (4.1 s), ~25 kB, data loaded>
<Info | 7 non-empty values
 bads: []
 ch_names: CH1, CH2
 chs: 2 MISC
 custom_ref_applied: False
 highpass: 0.0 Hz
 lowpass: 125.0 Hz
 meas_date: unspecified
 nchan: 2
 projs: []
 sfreq: 250.0 Hz
>
```
Time-domain data does plot correctly. However, when attempting to plot psd:
```
picks = mne.pick_types(mne_data.info, misc=True)
print(picks)
spect = mne_data.plot_psd(picks=picks)
```
Output:
```
[0 1]
RuntimeError: No data channels found
```

**Summary**
This issue seems similar to the bug [here](https://github.com/mne-tools/mne-python/issues/7154). Is there a workaround at this point? I have tried passing **picks=None** without success.


Discussion:
as you can see you have:

chs: 2 MISC


and MISC are not consider data channels. If you pass picks then I
think its fair to expect it to work.

if it does not please provide a full gist to replicate the pb. From
creation of data to plotting.


thanks

The following code replicates the problem:

```
import numpy as np
import mne

fs = 250
channels = ['CH1', 'CH2']
data = 1e-3*np.random.rand(2, 1024)
print(data.shape)

info = mne.create_info(channels, fs)
mne_data = mne.io.RawArray(data, info)

print(mne_data.info)
plt = mne_data.plot()
picks = mne.pick_types(mne_data.info, misc=True)
print(picks)
spect = mne_data.plot_psd(picks=picks)
```

thanks
I can replicate the pb.

@drammock what's your feeling about this?

I am enclined to fix the behavior. If picks is None then default to what we call data channels but if you pass picks then plot whatever is requested.
agreed, seems to me like if the user passes `picks` we should give them what they ask for.
When `picks = None`, I get:
`picks (NoneNone, treated as "data") yielded no channels, consider passing picks explicitly`
so either way it won't work.
yes we need to fix ...

>

Is there a temporary workaround for this in the meantime? How would I change it to a different type, e.g. "eeg"? (The concept of "data channels" vs eeg/meg etc, isn't entirely clear to me from the documentation). 
@gpeyton you can change the channel type with: 
https://mne.tools/dev/generated/mne.io.Raw.html#mne.io.Raw.set_channel_types
@drammock do you want to work on the fix? If not, I can tackle it this week

Resolving patch:
diff --git a/mne/io/pick.py b/mne/io/pick.py
--- a/mne/io/pick.py
+++ b/mne/io/pick.py
@@ -892,7 +892,7 @@ def _check_excludes_includes(chs, info=None, allow_bads=False):
     meg=True, eeg=True, csd=True, stim=False, eog=False, ecg=False, emg=False,
     misc=False, resp=False, chpi=False, exci=False, ias=False, syst=False,
     seeg=True, dipole=False, gof=False, bio=False, ecog=True, fnirs=True)
-_PICK_TYPES_KEYS = tuple(list(_PICK_TYPES_DATA_DICT.keys()) + ['ref_meg'])
+_PICK_TYPES_KEYS = tuple(list(_PICK_TYPES_DATA_DICT) + ['ref_meg'])
 _DATA_CH_TYPES_SPLIT = ('mag', 'grad', 'eeg', 'csd', 'seeg', 'ecog',
                         'hbo', 'hbr', 'fnirs_raw', 'fnirs_od')
 _DATA_CH_TYPES_ORDER_DEFAULT = ('mag', 'grad', 'eeg', 'csd', 'eog', 'ecg',
diff --git a/mne/viz/utils.py b/mne/viz/utils.py
--- a/mne/viz/utils.py
+++ b/mne/viz/utils.py
@@ -30,7 +30,8 @@
 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_data_channels, _DATA_CH_TYPES_SPLIT,
+                       _VALID_CHANNEL_TYPES, pick_types,
                        pick_info, _picks_by_type, pick_channels_cov,
                        _picks_to_idx, _contains_ch_type)
 from ..io.meas_info import create_info
@@ -3044,6 +3045,7 @@ def _set_psd_plot_params(info, proj, picks, ax, area_mode):
     """Set PSD plot params."""
     import matplotlib.pyplot as plt
     _check_option('area_mode', area_mode, [None, 'std', 'range'])
+    _user_picked = picks is not None
     picks = _picks_to_idx(info, picks)
 
     # XXX this could be refactored more with e.g., plot_evoked
@@ -3055,7 +3057,9 @@ def _set_psd_plot_params(info, proj, picks, ax, area_mode):
     titles_list = list()
     units_list = list()
     scalings_list = list()
-    for name in _DATA_CH_TYPES_SPLIT:
+    allowed_ch_types = (_VALID_CHANNEL_TYPES if _user_picked else
+                        _DATA_CH_TYPES_SPLIT)
+    for name in allowed_ch_types:
         kwargs = dict(meg=False, ref_meg=False, exclude=[])
         if name in ('mag', 'grad'):
             kwargs['meg'] = name


Test patch:
diff --git a/mne/viz/tests/test_raw.py b/mne/viz/tests/test_raw.py
--- a/mne/viz/tests/test_raw.py
+++ b/mne/viz/tests/test_raw.py
@@ -377,7 +377,8 @@ def test_plot_raw_psd():
     raw.plot_psd(tmax=None, picks=picks, ax=ax, average=True)
     plt.close('all')
     ax = plt.axes()
-    pytest.raises(ValueError, raw.plot_psd, ax=ax, average=True)
+    with pytest.raises(ValueError, match='2 axes must be supplied, got 1'):
+        raw.plot_psd(ax=ax, average=True)
     plt.close('all')
     ax = plt.subplots(2)[1]
     raw.plot_psd(tmax=None, ax=ax, average=True)
@@ -418,6 +419,7 @@ def test_plot_raw_psd():
     raw.set_annotations(Annotations([1, 5], [3, 3], ['test', 'test']))
     raw.plot_psd(reject_by_annotation=True)
     raw.plot_psd(reject_by_annotation=False)
+    plt.close('all')
 
     # test fmax value checking
     with pytest.raises(ValueError, match='not exceed one half the sampling'):
@@ -438,6 +440,15 @@ def test_plot_raw_psd():
                           verbose='error')
     fig = raw.plot_psd()
     assert len(fig.axes) == 10
+    plt.close('all')
+
+    # gh-7631
+    data = 1e-3 * np.random.rand(2, 100)
+    info = create_info(['CH1', 'CH2'], 100)
+    raw = RawArray(data, info)
+    picks = pick_types(raw.info, misc=True)
+    raw.plot_psd(picks=picks, spatial_colors=False)
+    plt.close('all')
 
 
 def test_plot_sensors():