Skip to content
1 change: 1 addition & 0 deletions doc/changes/dev/14013.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :meth:`mne.Evoked.get_data` so that explicit ``picks`` (e.g. ``picks="eeg"``) exclude channels marked as bad by default, matching the existing behavior of :meth:`mne.Epochs.get_data`, and clarify the ``picks`` docstring to describe this conditional bad-channel behavior, by :newcontrib:`Eva Safi`.
1 change: 1 addition & 0 deletions doc/changes/names.inc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
.. _Erica Peterson: https://github.com/nordme
.. _Erkka Heinila: https://github.com/Teekuningas
.. _Etienne de Montalivet: https://github.com/etiennedemontalivet
.. _Eva Safi: https://github.com/evasafi
.. _Evan Hathaway: https://github.com/ephathaway
.. _Evgenii Kalenkovich: https://github.com/kalenkovich
.. _Evgeny Goldstein: https://github.com/evgenygoldstein
Expand Down
11 changes: 9 additions & 2 deletions mne/evoked.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def get_data(self, picks=None, units=None, tmin=None, tmax=None):

Parameters
----------
%(picks_all)s
%(picks_all_get_data)s
%(units)s
tmin : float | None
Start time of data to get in seconds.
Expand All @@ -252,7 +252,14 @@ def get_data(self, picks=None, units=None, tmin=None, tmax=None):
# Avoid circular import
from .io.base import _get_ch_factors

picks = _picks_to_idx(self.info, picks, "all", exclude=())
# When no picks are given, keep prior behavior of including bads.
# When explicit picks are given (e.g. picks="eeg"), exclude bads by
# default, matching the behavior of Epochs.get_data().
orig_picks = picks
if orig_picks is None:
picks = _picks_to_idx(self.info, picks, "all", exclude=())
else:
picks = _picks_to_idx(self.info, picks)

start, stop = self._handle_tmin_tmax(tmin, tmax)

Expand Down
16 changes: 16 additions & 0 deletions mne/tests/test_evoked.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ def test_get_data():
d2 = evoked.get_data(picks="eeg", units="V")
assert_array_equal(d1, d2)

# Regression test for gh-12577: explicit picks should exclude bad
# channels in Evoked.get_data(), matching Epochs.get_data().
evoked_bads = evoked.copy()
eeg_ch_names = [
ch
for ch, kind in zip(evoked_bads.ch_names, evoked_bads.get_channel_types())
if kind == "eeg"
]
evoked_bads.info["bads"] = [eeg_ch_names[0]]
n_eeg_with_bads = len(pick_types(evoked_bads.info, eeg=True, exclude=()))
n_eeg_without_bads = len(pick_types(evoked_bads.info, eeg=True, exclude="bads"))
assert n_eeg_without_bads < n_eeg_with_bads # sanity check the fixture
assert evoked_bads.get_data(picks="eeg").shape[0] == n_eeg_without_bads
# picks=None should still keep prior behavior (bads included)
assert evoked_bads.get_data().shape[0] == len(evoked_bads.ch_names)

# Convert to µV
d3 = evoked.get_data(picks="eeg", units="µV")
assert_array_equal(d1 * 1e6, d3)
Expand Down
6 changes: 6 additions & 0 deletions mne/utils/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3547,6 +3547,12 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
docdict["picks_all_data_noref"] = _reflow_param_docstring(
f"{picks_base} all data channels {noref}"
)
docdict["picks_all_get_data"] = _reflow_param_docstring(
f"{picks_base} all channels, and bad channels are included by default "
f"when picks is None. If picks are given as channel type(s) (e.g., "
f"``'eeg'``), bad channels of those types are excluded by default. "
f"{reminder}"
)
docdict["picks_all_notypes"] = _reflow_param_docstring(
f"{picks_base_notypes} all channels. {reminder}"
)
Expand Down
Loading