Repository: mne-tools/mne-python

Issue:
Notch filter: picks < n_channels(67) got 67 -ERROR 
Hi!

- MNE version: 0.24.1
- operating system: Windows 10 Pro build number: 19041.1415


I had an issue using the mne.filter.notch_filter when I used it on my own data. The problem could be replicated.

```
from pathlib import Path

import mne



sample_dir = Path(mne.datasets.sample.data_path())

sample_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw.fif'



raw = mne.io.read_raw_fif(sample_fname, preload=True)

raw.crop(tmax=60)

raw.set_channel_types(mapping={'EEG 001': 'ecg'})



emg_channel_pick = mne.pick_types(raw.info, emg=True) 

sampling_rate = raw.info['sfreq']

freqs = 50.0 

raw_filtered = mne.filter.notch_filter(raw, sampling_rate, freqs, picks=emg_channel_pick)
```

I tried add picks in several ways, unfortunatelly none of them worked, and always got the same error. 


```
Traceback (most recent call last):
  File "smthing.py", line 99, in <module>
    raw_filtered = mne.filter.notch_filter(raw, sampling_rate, freqs, picks='ecg')
  File "<decorator-gen-105>", line 24, in notch_filter
  File "C:\Anaconda\lib\site-packages\mne\filter.py", line 1190, in notch_filter
    xf = filter_data(x, Fs, highs, lows, picks, filter_length, tb_2, tb_2,
  File "<decorator-gen-103>", line 24, in filter_data
  File "C:\Anaconda\lib\site-packages\mne\filter.py", line 815, in filter_data
    data = _check_filterable(data)
  File "C:\Anaconda\lib\site-packages\mne\filter.py", line 1374, in _check_filterable
    x = np.asanyarray(x)
  File "C:\Anaconda\lib\site-packages\numpy\core\_asarray.py", line 136, in asanyarray
    return array(a, dtype, copy=False, order=order, subok=True)
  File "C:\Anaconda\lib\site-packages\mne\io\base.py", line 807, in __getitem__
    return self._getitem(item)
  File "C:\Anaconda\lib\site-packages\mne\io\base.py", line 810, in _getitem
    sel, start, stop = self._parse_get_set_params(item)
  File "C:\Anaconda\lib\site-packages\mne\io\base.py", line 742, in _parse_get_set_params
    sel = _picks_to_idx(self.info, item[0])
  File "C:\Anaconda\lib\site-packages\mne\io\pick.py", line 1069, in _picks_to_idx
    raise ValueError('All picks must be < n_channels (%d), got %r'
ValueError: All picks must be < n_channels (67), got 67
```

Thank you for any help! 


Discussion:
`mne.filter.notch_filter` should only accept `np.ndarray` as the first argument, not `mne.io.Raw`. You should probably use `raw.notch_filter(...)` instead, e.g.:
```
raw_filtered = raw.copy().notch_filter(freqs, picks=emg_channel_pick)
```

Let's keep this issue open, though, because we should do better input validation in `mne.filter.*` functions.
Thank you for the very fast reply!

When i was looking for a notch filter i could't find the `raw.notch_filter(...)` option, and it wasn't clear for me that `mne.filter.notch_filter` was only for `np.ndarray`.  But now everything worsk as it should, thank you.

Resolving patch:
diff --git a/mne/filter.py b/mne/filter.py
--- a/mne/filter.py
+++ b/mne/filter.py
@@ -1158,6 +1158,7 @@ def notch_filter(x, Fs, freqs, filter_length='auto', notch_widths=None,
     & Hemant Bokil, Oxford University Press, New York, 2008. Please
     cite this in publications if method 'spectrum_fit' is used.
     """
+    x = _check_filterable(x, 'notch filtered', 'notch_filter')
     iir_params, method = _check_method(method, iir_params, ['spectrum_fit'])
 
     if freqs is not None:
@@ -1370,7 +1371,27 @@ def _mt_spectrum_remove(x, sfreq, line_freqs, notch_widths,
     return x - datafit, rm_freqs
 
 
-def _check_filterable(x, kind='filtered'):
+def _check_filterable(x, kind='filtered', alternative='filter'):
+    # Let's be fairly strict about this -- users can easily coerce to ndarray
+    # at their end, and we already should do it internally any time we are
+    # using these low-level functions. At the same time, let's
+    # help people who might accidentally use low-level functions that they
+    # shouldn't use by pushing them in the right direction
+    from .io.base import BaseRaw
+    from .epochs import BaseEpochs
+    from .evoked import Evoked
+    if isinstance(x, (BaseRaw, BaseEpochs, Evoked)):
+        try:
+            name = x.__class__.__name__
+        except Exception:
+            pass
+        else:
+            raise TypeError(
+                'This low-level function only operates on np.ndarray '
+                f'instances. To get a {kind} {name} instance, use a method '
+                f'like `inst_new = inst.copy().{alternative}(...)` '
+                'instead.')
+    _validate_type(x, (np.ndarray, list, tuple), f'Data to be {kind}')
     x = np.asanyarray(x)
     if x.dtype != np.float64:
         raise ValueError('Data to be %s must be real floating, got %s'
@@ -1438,7 +1459,7 @@ def resample(x, up=1., down=1., npad=100, axis=-1, window='boxcar', n_jobs=1,
         raise TypeError(err)
 
     # make sure our arithmetic will work
-    x = _check_filterable(x, 'resampled')
+    x = _check_filterable(x, 'resampled', 'resample')
     ratio, final_len = _resamp_ratio_len(up, down, x.shape[axis])
     del up, down
     if axis < 0:


Test patch:
diff --git a/mne/tests/test_filter.py b/mne/tests/test_filter.py
--- a/mne/tests/test_filter.py
+++ b/mne/tests/test_filter.py
@@ -538,7 +538,15 @@ def test_filter_auto():
     with pytest.raises(ValueError, match='Data to be filtered must be real'):
         filter_data(x.astype(np.float32), sfreq, None, 10)
     with pytest.raises(ValueError, match='Data to be filtered must be real'):
-        filter_data(1j, 1000., None, 40.)
+        filter_data([1j], 1000., None, 40.)
+    with pytest.raises(TypeError, match='instance of ndarray'):
+        filter_data('foo', 1000., None, 40.)
+    # gh-10258
+    raw = RawArray([[0.]], create_info(1, 1000., 'eeg'))
+    with pytest.raises(TypeError, match=r'.*copy\(\)\.filter\(\.\.\.\)` in.*'):
+        filter_data(raw, 1000., None, 40.)
+    with pytest.raises(TypeError, match=r'.*copy\(\)\.notch_filter\(\.\.\..*'):
+        notch_filter(raw, 1000., [60.])
 
 
 def test_cuda_fir():