Skip to content

Commit ff9179e

Browse files
FIX, DOC: Pipeline methods shouldn't accept just any instance of raw (lina-usc#213)
* FIX, DOC: Pipeline methods shouldn't accept just any instance of raw Following up from lina-usc#212. I realized that if one did do `my_pipeline.find_outlier_chs(my_raw), then under the hood this method would actually create an epochs instance from my_pipeline.raw ... this would lead to unexpected results if my_raw and my_pipeline.raw are not the same object of memory (i.e. they are different raw objects). Since in our codebase we never do pipeline.find_outlier_chs(raw), I dont think we should support this. Instead, we should either always expect an instanc of mne.Epochs OR We should change the method signature to be def find_outlier_chs(epochs=None) , where if it is None, the method creates epochs from pipeline.raw under the hood. * Apply suggestions from Christian O'Reilly code review - Change API form `inst` to `epochs | None` - if `None`, then make epochs from self.raw - No need check and raise type error now. Co-authored-by: Christian O'Reilly <[email protected]> * FIX: cruft * DOC: improve docstring a little * DOC, FIX: add example to docstring and explicitly call pick * TST: OK codecov here is your test :) * STY: 2 lines bt functions * API: make epochs=None the default find_outlier_chs(epochs=None) --------- Co-authored-by: Christian O'Reilly <[email protected]>
1 parent 2b53d93 commit ff9179e

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

pylossless/pipeline.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -770,18 +770,49 @@ def _flag_volt_std(self, flag_dim, threshold=5e-5, picks="eeg"):
770770
)
771771
self.flags[flag_dim].add_flag_cat("volt_std", above_threshold, epochs)
772772

773-
def find_outlier_chs(self, inst, picks="eeg"):
774-
"""Detect outlier Channels to leave out of rereference."""
773+
def find_outlier_chs(self, epochs=None, picks="eeg"):
774+
"""Detect outlier Channels to leave out of rereference.
775+
776+
Parameters
777+
----------
778+
epochs : mne.Epochs | None
779+
An instance of :class:`mne.Epochs`, or ``None``. If ``None``, then
780+
:attr:`pylossless.LosslessPipeline.raw` should be set, and this
781+
method will call :meth:`pylossless.LosslessPipeline.get_epochs`
782+
to create epochs to use for outlier detection.
783+
picks : str (default "eeg")
784+
Channels to include in the outlier detection process. You can pass any
785+
argument that is valid for the :meth:`~mne.Epochs.pick` method, but
786+
you should avoid passing a mix of channel types with differing units of
787+
measurement (e.g. EEG and MEG), as this would likely lead to incorrect
788+
outlier detection (e.g. all EEG channels would be flagged as outliers).
789+
790+
Returns
791+
-------
792+
list
793+
a list of channel names that are considered outliers.
794+
795+
Notes
796+
-----
797+
- This method is used to detect channels that are so noisy that they
798+
should be left out of the robust average rereference process.
799+
800+
Examples
801+
--------
802+
>>> import mne
803+
>>> import pylossless as ll
804+
>>> config = ll.Config().load_default()
805+
>>> pipeline = ll.LosslessPipeline(config=config)
806+
>>> fname = mne.datasets.sample.data_path() / "MEG/sample/sample_audvis_raw.fif"
807+
>>> raw = mne.io.read_raw(fname)
808+
>>> epochs = mne.make_fixed_length_epochs(raw, preload=True)
809+
>>> chs_to_leave_out = pipeline.find_outlier_chs(epochs=epochs)
810+
"""
775811
# TODO: Reuse _detect_outliers here.
776812
logger.info("🔍 Detecting channels to leave out of reference.")
777-
if isinstance(inst, mne.Epochs):
778-
epochs = inst
779-
elif isinstance(inst, mne.io.Raw):
780-
epochs = self.get_epochs(rereference=False, picks=picks)
781-
else:
782-
raise TypeError(
783-
"inst must be an MNE Raw or Epochs object," f" but got {type(inst)}."
784-
)
813+
if epochs is None:
814+
epochs = self.get_epochs(rereference=False)
815+
epochs = epochs.copy().pick(picks=picks)
785816
epochs_xr = epochs_to_xr(epochs, kind="ch")
786817

787818
# Determines comically bad channels,

pylossless/tests/test_pipeline.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ def test_find_breaks(logging):
7070
Path(config_fname).unlink() # delete config file
7171

7272

73+
def test_find_outliers():
74+
"""Test the find_outliers method for the case that epochs is None."""
75+
fname = mne.datasets.sample.data_path() / 'MEG' / 'sample' / 'sample_audvis_raw.fif'
76+
raw = mne.io.read_raw_fif(fname, preload=True)
77+
raw.apply_function(lambda x: x * 10, picks="EEG 001") # create an outlier
78+
config = ll.config.Config().load_default()
79+
pipeline = ll.LosslessPipeline(config=config)
80+
pipeline.raw = raw
81+
chs_to_leave_out = pipeline.find_outlier_chs()
82+
assert chs_to_leave_out == ['EEG 001']
83+
84+
7385
def test_deprecation():
7486
"""Test the config_name property added for deprecation."""
7587
config = ll.config.Config()

0 commit comments

Comments
 (0)