Skip to content

Commit

Permalink
FIX : add_channels now resets picks (mne-tools#9246)
Browse files Browse the repository at this point in the history
* FIX : add_channels naw resets picks

* flake8

* suggestion from @larsoner

* pass on what's new

* more pass on what's new

* TST: Add test

* FIX: Tol

Co-authored-by: Eric Larson <[email protected]>
  • Loading branch information
agramfort and larsoner authored Apr 13, 2021
1 parent 02978df commit ed485f9
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
10 changes: 6 additions & 4 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -269,24 +269,26 @@ Bugs

- The RMS trace shown in the time viewer of `~mne.SourceEstimate` plots is now correctly labeled as ``RMS`` (was ``GFP`` before) (:gh:`8965` by `Richard Höchenberger`_)

- Fix bug with :func:`mne.SourceEstimate.plot` and related functions where the scalars were not interactively updated properly (:gh:`8985` by `Eric Larson`_)
- Fix bug with :meth:`mne.SourceEstimate.plot` and related functions where the scalars were not interactively updated properly (:gh:`8985` by `Eric Larson`_)

- Fix bug with mne.channels.find_ch_adjacency() returning wrong adjacency for Neuromag122-Data (:gh:`8891` by `Martin Schulz`_)

- Fix :func:`mne.read_dipole` yielding :class:`mne.Dipole` objects that could not be indexed (:gh:`8963` by `Marijn van Vliet`_)

- Fix bug when setting n_jobs > 1 in :func:`mne.Report.parse_folder` (:gh:`9109` by `Martin Schulz`_)
- Fix bug when setting n_jobs > 1 in :meth:`mne.Report.parse_folder` (:gh:`9109` by `Martin Schulz`_)

- Fix bug with :func:`mne.Evoked.plot_image` where an incorrect clim parameter did not raise any error (:gh:`9115` **by new contributor** |Matteo Anelli|_)
- Fix bug with :meth:`mne.Evoked.plot_image` where an incorrect clim parameter did not raise any error (:gh:`9115` **by new contributor** |Matteo Anelli|_)

- Fix bug with :func:`mne.io.Raw.pick` where incorrect fnirs types were returned (:gh:`9178` by `Robert Luke`_)
- Fix bug with ``mne.io.Raw.pick`` where incorrect fnirs types were returned (:gh:`9178` by `Robert Luke`_)

- Fix bug when passing both axes and picks to `mne.viz.plot_compare_evokeds` (:gh:`9252` by `Daniel McCloy`_)

- Improved string representation of `~mne.Epochs` containing multiple event types; improved (and more mathematically correct) ``evoked.comment`` in the `mne.combine_evoked` output; and better (and often more concise) legend labels in the figures created via `~mne.viz.plot_compare_evokeds` (:gh:`9027` by `Richard Höchenberger`_)

- :func:`mne.preprocessing.find_ecg_events` now correctly handles situation where no ECG activity could be detected, and correctly returns an empty array of ECG events (:gh:`9236` by `Richard Höchenberger`_)

- Fix bug with ``picks`` attribute for `~mne.Epochs` after calling :meth:`mne.Epochs.add_channels` (:gh:`9246` by `Alex Gramfort`_)

- `mne.preprocessing.compute_proj_eog` and `mne.preprocessing.compute_proj_ecg` now return empty lists if no EOG or ECG events, respectively, could be found. Previously, we'd return ``None`` in these situations, which does not match the documented behavior of returning a list of projectors (:gh:`9277` by `Richard Höchenberger`_)

API changes
Expand Down
8 changes: 8 additions & 0 deletions mne/channels/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
_pick_data_channels)
from ..io.tag import _rename_list
from ..io.write import DATE_NONE
from ..io.proj import setup_proj
from ..io._digitization import _get_data_as_dict_from_dig


Expand Down Expand Up @@ -1070,6 +1071,13 @@ def add_channels(self, add_list, force_update_info=False):
self._read_picks = [
np.concatenate([r, extra_idx]) for r in self._read_picks]
assert all(len(r) == self.info['nchan'] for r in self._read_picks)
elif isinstance(self, BaseEpochs):
self.picks = np.arange(self._data.shape[1])
if hasattr(self, '_projector'):
activate = False if self._do_delayed_proj else self.proj
self._projector, self.info = setup_proj(self.info, False,
activate=activate)

return self

@fill_doc
Expand Down
34 changes: 34 additions & 0 deletions mne/tests/test_epochs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,22 @@ def make_epochs(picks, proj):
pytest.raises(NotImplementedError, add_channels_epochs,
[epochs_meg2, epochs_eeg])

# use delayed projection, add channel, ensure projectors match
epochs_meg2 = make_epochs(picks=picks_meg, proj='delayed')
assert len(epochs_meg2.info['projs']) == 3
meg2_proj = epochs_meg2._projector
assert meg2_proj is not None
epochs_eeg = make_epochs(picks=picks_eeg, proj='delayed')
epochs_meg2.add_channels([epochs_eeg])
del epochs_eeg
assert len(epochs_meg2.info['projs']) == 3
new_proj = epochs_meg2._projector
n_meg, n_eeg = len(picks_meg), len(picks_eeg)
n_tot = n_meg + n_eeg
assert new_proj.shape == (n_tot,) * 2
assert_allclose(new_proj[:n_meg, :n_meg], meg2_proj, atol=1e-12)
assert_allclose(new_proj[n_meg:, n_meg:], np.eye(n_eeg), atol=1e-12)


def test_array_epochs(tmpdir):
"""Test creating epochs from array."""
Expand Down Expand Up @@ -3423,3 +3439,21 @@ def fun(data):
expected = epochs.get_data(picks).mean(axis=-1, keepdims=True)
assert np.all(out.get_data(picks) == expected)
assert_array_equal(out.get_data(non_picks), epochs.get_data(non_picks))


@testing.requires_testing_data
def test_add_channels_picks():
"""Check that add_channels properly deals with picks."""
raw = mne.io.read_raw_fif(raw_fname, verbose=False)
raw.pick([2, 3, 310]) # take some MEG and EEG
raw.info.normalize_proj()

events = mne.make_fixed_length_events(raw, id=3000, start=0)
epochs = mne.Epochs(raw, events, event_id=3000, tmin=0, tmax=1,
proj=True, baseline=None, reject=None, preload=True,
decim=1)

epochs_final = epochs.copy()
epochs_bis = epochs.copy().rename_channels(lambda ch: ch + '_bis')
epochs_final.add_channels([epochs_bis], force_update_info=True)
epochs_final.drop_channels(epochs.ch_names)

0 comments on commit ed485f9

Please sign in to comment.