From a8c19188b9fd0c8444c1355fd6bb04bcd6f82d37 Mon Sep 17 00:00:00 2001 From: Sara Sedlar Date: Tue, 1 Aug 2023 19:59:49 +0200 Subject: [PATCH 01/16] n classes not 2 --- moabb/paradigms/motor_imagery.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 657a8e814..00ae48942 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -222,22 +222,24 @@ class FilterBankMotorImagery(FilterBank): requires all imagery sorts to be within the events list. """ - def __init__(self, n_classes=2, **kwargs): + def __init__(self, n_classes=None, **kwargs): "docstring" super().__init__(**kwargs) self.n_classes = n_classes if self.events is None: log.warning("Choosing from all possible events") - else: + elif self.n_classes is not None: assert n_classes <= len(self.events), "More classes than events specified" def is_valid(self, dataset): ret = True if not dataset.paradigm == "imagery": ret = False - if self.events is None: - if not len(dataset.event_id) >= self.n_classes: + elif self.n_classes is None and self.events is None: + pass + elif self.events is None: + if len(dataset.event_id) < self.n_classes: ret = False else: overlap = len(set(self.events) & set(dataset.event_id.keys())) @@ -250,8 +252,8 @@ def used_events(self, dataset): if self.events is None: for k, v in dataset.event_id.items(): out[k] = v - if len(out) == self.n_classes: - break + if self.n_classes is None: + self.n_classes = len(out) else: for event in self.events: if event in dataset.event_id.keys(): From 1a4b71be2ae9e57acaa5be0602a8fd3bbea8534a Mon Sep 17 00:00:00 2001 From: Sara Sedlar Date: Thu, 10 Aug 2023 00:25:04 +0200 Subject: [PATCH 02/16] Remove repeating --- moabb/paradigms/motor_imagery.py | 145 ++++++------------------------- 1 file changed, 25 insertions(+), 120 deletions(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 00ae48942..a17403f60 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -105,18 +105,19 @@ def scoring(self): return "accuracy" -class SinglePass(BaseMotorImagery): - """Single Bandpass filter motor Imagery. +class BandPass(BaseMotorImagery): + """Filter Motor Imagery signals. - Motor imagery paradigm with only one bandpass filter (default 8 to 32 Hz) + Motor imagery paradigm with one bandpass filter (default 8 to 32 Hz) + or with a filter bank. Parameters ---------- fmin: float (default 8) - cutoff frequency (Hz) for the high pass filter + cutoff frequency (Hz) for the high pass filter in single band pass filter fmax: float (default 32) - cutoff frequency (Hz) for the low pass filter + cutoff frequency (Hz) for the low pass filter in single band pass filter events: List of str | None (default None) event to use for epoching. If None, default to all events defined in @@ -149,25 +150,16 @@ class SinglePass(BaseMotorImagery): If not None, resample the eeg data with the sampling rate provided. """ - def __init__(self, fmin=8, fmax=32, **kwargs): - if "filters" in kwargs.keys(): - raise (ValueError("MotorImagery does not take argument filters")) - super().__init__(filters=[[fmin, fmax]], **kwargs) - - -class FilterBank(BaseMotorImagery): - """Filter Bank MI.""" + def __init__(self, filter_type="single_pass", fmin=8, fmax=32, **kwargs): + if filter_type == "single_pass": + if "filters" in kwargs.keys(): + raise (ValueError("MotorImagery does not take argument filters")) + super().__init__(filters=[[fmin, fmax]], **kwargs) + elif filter_type == "filter_bank": + super().__init__(**kwargs) - def __init__( - self, - filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), - **kwargs, - ): - """init.""" - super().__init__(filters=filters, **kwargs) - -class LeftRightImagery(SinglePass): +class LeftRightImagery(BandPass): """Motor Imagery for left hand/right hand classification. Metric is 'roc_auc' @@ -186,111 +178,17 @@ def scoring(self): return "roc_auc" -class FilterBankLeftRightImagery(FilterBank): +class FilterBankLeftRightImagery(LeftRightImagery): """Filter Bank Motor Imagery for left hand/right hand classification. Metric is 'roc_auc' """ - def __init__(self, **kwargs): - if "events" in kwargs.keys(): - raise (ValueError("LeftRightImagery dont accept events")) - super().__init__(events=["left_hand", "right_hand"], **kwargs) - - def used_events(self, dataset): - return {ev: dataset.event_id[ev] for ev in self.events} - - @property - def scoring(self): - return "roc_auc" - - -class FilterBankMotorImagery(FilterBank): - """Filter bank n-class motor imagery. - - Metric is 'roc-auc' if 2 classes and 'accuracy' if more - - Parameters - ----------- - - events: List of str - event labels used to filter datasets (e.g. if only motor imagery is - desired). - - n_classes: int, - number of classes each dataset must have. If events is given, - requires all imagery sorts to be within the events list. - """ - - def __init__(self, n_classes=None, **kwargs): - "docstring" - super().__init__(**kwargs) - self.n_classes = n_classes - - if self.events is None: - log.warning("Choosing from all possible events") - elif self.n_classes is not None: - assert n_classes <= len(self.events), "More classes than events specified" - - def is_valid(self, dataset): - ret = True - if not dataset.paradigm == "imagery": - ret = False - elif self.n_classes is None and self.events is None: - pass - elif self.events is None: - if len(dataset.event_id) < self.n_classes: - ret = False - else: - overlap = len(set(self.events) & set(dataset.event_id.keys())) - if not overlap >= self.n_classes: - ret = False - return ret - - def used_events(self, dataset): - out = {} - if self.events is None: - for k, v in dataset.event_id.items(): - out[k] = v - if self.n_classes is None: - self.n_classes = len(out) - else: - for event in self.events: - if event in dataset.event_id.keys(): - out[event] = dataset.event_id[event] - if len(out) == self.n_classes: - break - if len(out) < self.n_classes: - raise ( - ValueError( - f"Dataset {dataset.code} did not have enough " - f"events in {self.events} to run analysis" - ) - ) - return out - - @property - def datasets(self): - if self.tmax is None: - interval = None - else: - interval = self.tmax - self.tmin - return utils.dataset_search( - paradigm="imagery", - events=self.events, - interval=interval, - has_all_events=False, - ) - - @property - def scoring(self): - if self.n_classes == 2: - return "roc_auc" - else: - return "accuracy" + def __init__(self, filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), **kwargs): + super().__init__(filter_type="filter_bank", filters=filters, **kwargs) -class MotorImagery(SinglePass): +class MotorImagery(BandPass): """N-class motor imagery. Metric is 'roc-auc' if 2 classes and 'accuracy' if more @@ -405,6 +303,13 @@ def scoring(self): else: return "accuracy" +class FilterBankMotorImagery(MotorImagery): + """Filter bank n-class motor imagery. + + Metric is 'roc-auc' if 2 classes and 'accuracy' if more + """ + def __init__(self, filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), **kwargs): + super().__init__(filter_type="filter_bank", filters=filters, **kwargs) class FakeImageryParadigm(LeftRightImagery): """Fake Imagery for left hand/right hand classification.""" From ec41d89a5ef920c7cdc58a2c44b28b1da4d063af Mon Sep 17 00:00:00 2001 From: Sara Sedlar Date: Thu, 10 Aug 2023 12:54:37 +0200 Subject: [PATCH 03/16] Update what's new --- docs/source/whats_new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whats_new.rst b/docs/source/whats_new.rst index 1be4bcfe1..b4fb02986 100644 --- a/docs/source/whats_new.rst +++ b/docs/source/whats_new.rst @@ -61,7 +61,7 @@ Bugs - Fix :func:`moabb.paradigms.base.BaseParadigm` using attributes before defining them (PR :gh:`408`, issue :gh:`425` by `Pierre Guetschel`_) - Fix :func:`moabb.paradigms.FakeImageryParadigm`, :func:`moabb.paradigms.FakeP300Paradigm` and :func:`moabb.paradigms.FakeSSVEPParadigm` ``is_valid`` methods to only accept the correct datasets (PR :gh:`408` by `Pierre Guetschel`_) - Fix ``dataset_list`` construction, which could be empty due to bad import order (PR :gh:`449` by `Thomas Moreau`_). - +- Fixing dataset downloader from servers with non-http (PR :gh:`433` by `Sara Sedlar`_) API changes ~~~~~~~~~~~ From 6fd8c6d76abb92956a44d1f958fe6e24043ecbcc Mon Sep 17 00:00:00 2001 From: Sara Sedlar Date: Thu, 10 Aug 2023 13:04:40 +0200 Subject: [PATCH 04/16] wrong whats new --- docs/source/whats_new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whats_new.rst b/docs/source/whats_new.rst index b4fb02986..1be4bcfe1 100644 --- a/docs/source/whats_new.rst +++ b/docs/source/whats_new.rst @@ -61,7 +61,7 @@ Bugs - Fix :func:`moabb.paradigms.base.BaseParadigm` using attributes before defining them (PR :gh:`408`, issue :gh:`425` by `Pierre Guetschel`_) - Fix :func:`moabb.paradigms.FakeImageryParadigm`, :func:`moabb.paradigms.FakeP300Paradigm` and :func:`moabb.paradigms.FakeSSVEPParadigm` ``is_valid`` methods to only accept the correct datasets (PR :gh:`408` by `Pierre Guetschel`_) - Fix ``dataset_list`` construction, which could be empty due to bad import order (PR :gh:`449` by `Thomas Moreau`_). -- Fixing dataset downloader from servers with non-http (PR :gh:`433` by `Sara Sedlar`_) + API changes ~~~~~~~~~~~ From da955e817fa7f047c71f42a0287eacabdd310f2c Mon Sep 17 00:00:00 2001 From: Sara04 Date: Fri, 18 Aug 2023 17:18:36 +0200 Subject: [PATCH 05/16] Remove Band Pass class --- moabb/paradigms/motor_imagery.py | 113 ++++++++++--------------------- 1 file changed, 35 insertions(+), 78 deletions(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index a17403f60..584f2e9e6 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -105,70 +105,17 @@ def scoring(self): return "accuracy" -class BandPass(BaseMotorImagery): - """Filter Motor Imagery signals. +class LeftRightImagery(BaseMotorImagery): + """Motor Imagery for left hand/right hand classification.""" - Motor imagery paradigm with one bandpass filter (default 8 to 32 Hz) - or with a filter bank. - - Parameters - ---------- - fmin: float (default 8) - cutoff frequency (Hz) for the high pass filter in single band pass filter - - fmax: float (default 32) - cutoff frequency (Hz) for the low pass filter in single band pass filter - - events: List of str | None (default None) - event to use for epoching. If None, default to all events defined in - the dataset. - - tmin: float (default 0.0) - Start time (in second) of the epoch, relative to the dataset specific - task interval e.g. tmin = 1 would mean the epoch will start 1 second - after the beginning of the task as defined by the dataset. - - tmax: float | None, (default None) - End time (in second) of the epoch, relative to the beginning of the - dataset specific task interval. tmax = 5 would mean the epoch will end - 5 second after the beginning of the task as defined in the dataset. If - None, use the dataset value. - - baseline: None | tuple of length 2 - The time interval to consider as “baseline” when applying baseline - correction. If None, do not apply baseline correction. - If a tuple (a, b), the interval is between a and b (in seconds), - including the endpoints. - Correction is applied by computing the mean of the baseline period - and subtracting it from the data (see mne.Epochs) - - channels: list of str | None (default None) - list of channel to select. If None, use all EEG channels available in - the dataset. - - resample: float | None (default None) - If not None, resample the eeg data with the sampling rate provided. - """ - - def __init__(self, filter_type="single_pass", fmin=8, fmax=32, **kwargs): - if filter_type == "single_pass": - if "filters" in kwargs.keys(): - raise (ValueError("MotorImagery does not take argument filters")) - super().__init__(filters=[[fmin, fmax]], **kwargs) - elif filter_type == "filter_bank": - super().__init__(**kwargs) - - -class LeftRightImagery(BandPass): - """Motor Imagery for left hand/right hand classification. - - Metric is 'roc_auc' - """ - - def __init__(self, **kwargs): + def __init__(self, fmin=8, fmax=32, **kwargs): if "events" in kwargs.keys(): raise (ValueError("LeftRightImagery dont accept events")) - super().__init__(events=["left_hand", "right_hand"], **kwargs) + if "filters" in kwargs.keys(): + raise (ValueError("LeftRightImagery does not take argument filters")) + super().__init__( + filters=[[fmin, fmax]], events=["left_hand", "right_hand"], **kwargs + ) def used_events(self, dataset): return {ev: dataset.event_id[ev] for ev in self.events} @@ -179,16 +126,21 @@ def scoring(self): class FilterBankLeftRightImagery(LeftRightImagery): - """Filter Bank Motor Imagery for left hand/right hand classification. - - Metric is 'roc_auc' - """ + """Filter Bank Motor Imagery for left hand/right hand classification.""" - def __init__(self, filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), **kwargs): - super().__init__(filter_type="filter_bank", filters=filters, **kwargs) + def __init__( + self, + filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), + **kwargs, + ): + if "events" in kwargs.keys(): + raise (ValueError("LeftRightImagery dont accept events")) + super(LeftRightImagery, self).__init__( + filters=filters, events=["left_hand", "right_hand"], **kwargs + ) -class MotorImagery(BandPass): +class MotorImagery(BaseMotorImagery): """N-class motor imagery. Metric is 'roc-auc' if 2 classes and 'accuracy' if more @@ -237,10 +189,11 @@ class MotorImagery(BandPass): If not None, resample the eeg data with the sampling rate provided. """ - def __init__(self, n_classes=None, **kwargs): - super().__init__(**kwargs) + def __init__(self, fmin=8, fmax=32, n_classes=None, **kwargs): + if "filters" in kwargs.keys(): + raise (ValueError("MotorImagery does not take argument filters")) + super().__init__(filters=[[fmin, fmax]], **kwargs) self.n_classes = n_classes - if self.events is None: log.warning("Choosing from all possible events") elif self.n_classes is not None: @@ -253,11 +206,11 @@ def is_valid(self, dataset): elif self.n_classes is None and self.events is None: pass elif self.events is None: - if not len(dataset.event_id) >= self.n_classes: + if len(dataset.event_id) < self.n_classes: ret = False else: overlap = len(set(self.events) & set(dataset.event_id.keys())) - if self.n_classes is not None and not overlap >= self.n_classes: + if self.n_classes is not None and overlap < self.n_classes: ret = False return ret @@ -303,13 +256,17 @@ def scoring(self): else: return "accuracy" + class FilterBankMotorImagery(MotorImagery): - """Filter bank n-class motor imagery. + """Filter bank n-class motor imagery.""" + + def __init__( + self, + filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), + **kwargs, + ): + super(MotorImagery, self).__init__(filters=filters, **kwargs) - Metric is 'roc-auc' if 2 classes and 'accuracy' if more - """ - def __init__(self, filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), **kwargs): - super().__init__(filter_type="filter_bank", filters=filters, **kwargs) class FakeImageryParadigm(LeftRightImagery): """Fake Imagery for left hand/right hand classification.""" From 022a89176d2689623334a9558f91c841e149b102 Mon Sep 17 00:00:00 2001 From: Sara04 Date: Mon, 21 Aug 2023 11:54:02 +0200 Subject: [PATCH 06/16] Update is valid method --- moabb/paradigms/motor_imagery.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 584f2e9e6..64ce78ce2 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -23,16 +23,16 @@ class BaseMotorImagery(BaseParadigm): bank of bandpass filter to apply. events: List of str | None (default None) - event to use for epoching. If None, default to all events defined in + events to use for epoching. If None, default to all events defined in the dataset. tmin: float (default 0.0) - Start time (in second) of the epoch, relative to the dataset specific + Start time (in seconds) of the epoch, relative to the dataset specific task interval e.g. tmin = 1 would mean the epoch will start 1 second after the beginning of the task as defined by the dataset. tmax: float | None, (default None) - End time (in second) of the epoch, relative to the beginning of the + End time (in seconds) of the epoch, relative to the beginning of the dataset specific task interval. tmax = 5 would mean the epoch will end 5 second after the beginning of the task as defined in the dataset. If None, use the dataset value. @@ -74,9 +74,10 @@ def __init__( ) def is_valid(self, dataset): - ret = True - if not (dataset.paradigm == "imagery"): - ret = False + + ret = dataset.paradigm == "imagery" + if not ret: + return ret # check if dataset has required events if self.events: @@ -106,7 +107,7 @@ def scoring(self): class LeftRightImagery(BaseMotorImagery): - """Motor Imagery for left hand/right hand classification.""" + """Motor Imagery for left hand/right hand motor imagery classification.""" def __init__(self, fmin=8, fmax=32, **kwargs): if "events" in kwargs.keys(): @@ -200,18 +201,17 @@ def __init__(self, fmin=8, fmax=32, n_classes=None, **kwargs): assert n_classes <= len(self.events), "More classes than events specified" def is_valid(self, dataset): - ret = True - if not dataset.paradigm == "imagery": - ret = False - elif self.n_classes is None and self.events is None: - pass - elif self.events is None: - if len(dataset.event_id) < self.n_classes: - ret = False - else: + + ret = dataset.paradigm == "imagery" + if not ret: + return ret + + if self.events is None and self.n_classes: + ret = len(dataset.event_id) >= self.n_classes + elif self.events and self.n_classes: overlap = len(set(self.events) & set(dataset.event_id.keys())) - if self.n_classes is not None and overlap < self.n_classes: - ret = False + ret = overlap >= self.n_classes + return ret def used_events(self, dataset): From 0d226c886d1835eb14569a8ae802feda64df0d1d Mon Sep 17 00:00:00 2001 From: Sara04 Date: Mon, 21 Aug 2023 17:06:35 +0200 Subject: [PATCH 07/16] Add docstring inheritance --- moabb/paradigms/base.py | 10 +-- moabb/paradigms/motor_imagery.py | 103 +++++++------------------------ moabb/utils.py | 7 ++- 3 files changed, 34 insertions(+), 86 deletions(-) diff --git a/moabb/paradigms/base.py b/moabb/paradigms/base.py index 4a10aa35d..84c61ee51 100644 --- a/moabb/paradigms/base.py +++ b/moabb/paradigms/base.py @@ -20,17 +20,17 @@ get_resample_pipeline, ) +from moabb.utils import MoabbMetaClass log = logging.getLogger(__name__) -class BaseProcessing(metaclass=abc.ABCMeta): +class BaseProcessing(metaclass=MoabbMetaClass): """Base Processing. Please use one of the child classes - - Parameters + Attributes ---------- filters: list of list (defaults [[7, 35]]) @@ -374,11 +374,11 @@ def _get_events_pipeline(self, dataset): class BaseParadigm(BaseProcessing): """Base class for paradigms. - Parameters + Attributes ---------- events: List of str | None (default None) - event to use for epoching. If None, default to all events defined in + events to use for epoching. If None, default to all events defined in the dataset. """ diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 64ce78ce2..02e97eb08 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -7,50 +7,14 @@ from moabb.datasets.fake import FakeDataset from moabb.paradigms.base import BaseParadigm - log = logging.getLogger(__name__) class BaseMotorImagery(BaseParadigm): """Base Motor imagery paradigm. - Please use one of the child classes - - Parameters - ---------- - - filters: list of list (defaults [[7, 35]]) - bank of bandpass filter to apply. - - events: List of str | None (default None) - events to use for epoching. If None, default to all events defined in - the dataset. - - tmin: float (default 0.0) - Start time (in seconds) of the epoch, relative to the dataset specific - task interval e.g. tmin = 1 would mean the epoch will start 1 second - after the beginning of the task as defined by the dataset. - - tmax: float | None, (default None) - End time (in seconds) of the epoch, relative to the beginning of the - dataset specific task interval. tmax = 5 would mean the epoch will end - 5 second after the beginning of the task as defined in the dataset. If - None, use the dataset value. + Not to be instantiated. - baseline: None | tuple of length 2 - The time interval to consider as “baseline” when applying baseline - correction. If None, do not apply baseline correction. - If a tuple (a, b), the interval is between a and b (in seconds), - including the endpoints. - Correction is applied by computing the mean of the baseline period - and subtracting it from the data (see mne.Epochs) - - channels: list of str | None (default None) - list of channel to select. If None, use all EEG channels available in - the dataset. - - resample: float | None (default None) - If not None, resample the eeg data with the sampling rate provided. """ def __init__( @@ -107,7 +71,18 @@ def scoring(self): class LeftRightImagery(BaseMotorImagery): - """Motor Imagery for left hand/right hand motor imagery classification.""" + """Motor Imagery for left hand/right hand classification. + + Attributes + ----------- + + fmin: float (default 8) + cutoff frequency (Hz) for the high pass filter. + + fmax: float (default 32) + cutoff frequency (Hz) for the low pass filter. + + """ def __init__(self, fmin=8, fmax=32, **kwargs): if "events" in kwargs.keys(): @@ -127,7 +102,7 @@ def scoring(self): class FilterBankLeftRightImagery(LeftRightImagery): - """Filter Bank Motor Imagery for left hand/right hand classification.""" + """Filter Bank Motor Imagery for left/right hand classification.""" def __init__( self, @@ -142,52 +117,20 @@ def __init__( class MotorImagery(BaseMotorImagery): - """N-class motor imagery. + """N-class Motor Imagery. - Metric is 'roc-auc' if 2 classes and 'accuracy' if more - - Parameters + Attributes ----------- - events: List of str - event labels used to filter datasets (e.g. if only motor imagery is - desired). - - n_classes: int, - number of classes each dataset must have. If events is given, - requires all imagery sorts to be within the events list. - fmin: float (default 8) - cutoff frequency (Hz) for the high pass filter + cutoff frequency (Hz) for the high pass filter. fmax: float (default 32) - cutoff frequency (Hz) for the low pass filter - - tmin: float (default 0.0) - Start time (in second) of the epoch, relative to the dataset specific - task interval e.g. tmin = 1 would mean the epoch will start 1 second - after the beginning of the task as defined by the dataset. - - tmax: float | None, (default None) - End time (in second) of the epoch, relative to the beginning of the - dataset specific task interval. tmax = 5 would mean the epoch will end - 5 second after the beginning of the task as defined in the dataset. If - None, use the dataset value. - - baseline: None | tuple of length 2 - The time interval to consider as “baseline” when applying baseline - correction. If None, do not apply baseline correction. - If a tuple (a, b), the interval is between a and b (in seconds), - including the endpoints. - Correction is applied by computing the mean of the baseline period - and subtracting it from the data (see mne.Epochs) - - channels: list of str | None (default None) - list of channel to select. If None, use all EEG channels available in - the dataset. - - resample: float | None (default None) - If not None, resample the eeg data with the sampling rate provided. + cutoff frequency (Hz) for the low pass filter. + + n_classes: int (default number of available classes) + number of MotorImagery classes/events to select. + """ def __init__(self, fmin=8, fmax=32, n_classes=None, **kwargs): @@ -258,7 +201,7 @@ def scoring(self): class FilterBankMotorImagery(MotorImagery): - """Filter bank n-class motor imagery.""" + """Filter bank N-class motor imagery.""" def __init__( self, diff --git a/moabb/utils.py b/moabb/utils.py index a412af612..40ff6deac 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -1,4 +1,5 @@ """Util functions for moabb.""" +import abc import inspect import logging import os @@ -10,7 +11,7 @@ import numpy as np from mne import get_config, set_config from mne import set_log_level as sll - +from docstring_inheritance import NumpyDocstringInheritanceMeta log = logging.getLogger(__name__) @@ -208,3 +209,7 @@ def depreciated_func(*args, **kwargs): return func return factory + + +class MoabbMetaClass(abc.ABCMeta,NumpyDocstringInheritanceMeta): + pass From 3391ea4a42b79b9938d72e51349272848a598a0f Mon Sep 17 00:00:00 2001 From: Sara04 Date: Mon, 21 Aug 2023 17:46:11 +0200 Subject: [PATCH 08/16] update filterbank MI --- moabb/paradigms/motor_imagery.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 02e97eb08..895d01761 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -209,7 +209,11 @@ def __init__( **kwargs, ): super(MotorImagery, self).__init__(filters=filters, **kwargs) - + self.n_classes = n_classes + if self.events is None: + log.warning("Choosing from all possible events") + elif self.n_classes is not None: + assert n_classes <= len(self.events), "More classes than events specified" class FakeImageryParadigm(LeftRightImagery): """Fake Imagery for left hand/right hand classification.""" From 5f2c76861af23e87d0944019a325c23bdf4c8752 Mon Sep 17 00:00:00 2001 From: Sara04 Date: Mon, 21 Aug 2023 18:05:16 +0200 Subject: [PATCH 09/16] First check, after super init --- moabb/paradigms/motor_imagery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 895d01761..7c0dc27a6 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -136,12 +136,12 @@ class MotorImagery(BaseMotorImagery): def __init__(self, fmin=8, fmax=32, n_classes=None, **kwargs): if "filters" in kwargs.keys(): raise (ValueError("MotorImagery does not take argument filters")) - super().__init__(filters=[[fmin, fmax]], **kwargs) self.n_classes = n_classes if self.events is None: log.warning("Choosing from all possible events") elif self.n_classes is not None: assert n_classes <= len(self.events), "More classes than events specified" + super().__init__(filters=[[fmin, fmax]], **kwargs) def is_valid(self, dataset): @@ -208,12 +208,12 @@ def __init__( filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), **kwargs, ): - super(MotorImagery, self).__init__(filters=filters, **kwargs) self.n_classes = n_classes if self.events is None: log.warning("Choosing from all possible events") elif self.n_classes is not None: assert n_classes <= len(self.events), "More classes than events specified" + super(MotorImagery, self).__init__(filters=filters, **kwargs) class FakeImageryParadigm(LeftRightImagery): """Fake Imagery for left hand/right hand classification.""" From c38fad4542bd5cac57eb8a09b302bb852e43ac9d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 16:07:56 +0000 Subject: [PATCH 10/16] [pre-commit.ci] auto fixes from pre-commit.com hooks --- moabb/paradigms/base.py | 2 +- moabb/paradigms/motor_imagery.py | 4 ++-- moabb/utils.py | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/moabb/paradigms/base.py b/moabb/paradigms/base.py index 84c61ee51..90630d7f5 100644 --- a/moabb/paradigms/base.py +++ b/moabb/paradigms/base.py @@ -19,9 +19,9 @@ get_filter_pipeline, get_resample_pipeline, ) - from moabb.utils import MoabbMetaClass + log = logging.getLogger(__name__) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 7c0dc27a6..e5c43f1be 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -7,6 +7,7 @@ from moabb.datasets.fake import FakeDataset from moabb.paradigms.base import BaseParadigm + log = logging.getLogger(__name__) @@ -38,7 +39,6 @@ def __init__( ) def is_valid(self, dataset): - ret = dataset.paradigm == "imagery" if not ret: return ret @@ -144,7 +144,6 @@ def __init__(self, fmin=8, fmax=32, n_classes=None, **kwargs): super().__init__(filters=[[fmin, fmax]], **kwargs) def is_valid(self, dataset): - ret = dataset.paradigm == "imagery" if not ret: return ret @@ -215,6 +214,7 @@ def __init__( assert n_classes <= len(self.events), "More classes than events specified" super(MotorImagery, self).__init__(filters=filters, **kwargs) + class FakeImageryParadigm(LeftRightImagery): """Fake Imagery for left hand/right hand classification.""" diff --git a/moabb/utils.py b/moabb/utils.py index 40ff6deac..82a5f3cec 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -9,9 +9,10 @@ import sys import numpy as np +from docstring_inheritance import NumpyDocstringInheritanceMeta from mne import get_config, set_config from mne import set_log_level as sll -from docstring_inheritance import NumpyDocstringInheritanceMeta + log = logging.getLogger(__name__) @@ -211,5 +212,5 @@ def depreciated_func(*args, **kwargs): return factory -class MoabbMetaClass(abc.ABCMeta,NumpyDocstringInheritanceMeta): +class MoabbMetaClass(abc.ABCMeta, NumpyDocstringInheritanceMeta): pass From 54291e190726ba996fdab5409bd8eba379dc94ce Mon Sep 17 00:00:00 2001 From: Sara04 Date: Tue, 22 Aug 2023 12:03:07 +0200 Subject: [PATCH 11/16] Add n classes argument --- moabb/paradigms/motor_imagery.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 7c0dc27a6..6c20af1a1 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -201,11 +201,19 @@ def scoring(self): class FilterBankMotorImagery(MotorImagery): - """Filter bank N-class motor imagery.""" + """Filter bank N-class motor imagery. + + Attributes + ----------- + + n_classes: int (default number of available classes) + number of MotorImagery classes/events to select. + """ def __init__( self, filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), + n_classes=None, **kwargs, ): self.n_classes = n_classes From 54487a70a4eb46af2ecd3df2eb7aa9b940cb4cf8 Mon Sep 17 00:00:00 2001 From: Sara Sedlar Date: Thu, 19 Oct 2023 16:46:37 +0200 Subject: [PATCH 12/16] Update moabb/utils.py Change NumpyDocstringInheritanceMeta to NumpyDocstringInheritanceInitMeta class Co-authored-by: PierreGtch <25532709+PierreGtch@users.noreply.github.com> --- moabb/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moabb/utils.py b/moabb/utils.py index f2d7f4a39..020ea5355 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -10,7 +10,7 @@ from typing import TYPE_CHECKING import numpy as np -from docstring_inheritance import NumpyDocstringInheritanceMeta +from docstring_inheritance import NumpyDocstringInheritanceInitMeta from mne import get_config, set_config from mne import set_log_level as sll From ca6479bc6bc9512eb11be516f2017b2a76603d4f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 14:46:49 +0000 Subject: [PATCH 13/16] [pre-commit.ci] auto fixes from pre-commit.com hooks --- moabb/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/moabb/utils.py b/moabb/utils.py index 020ea5355..a0303260d 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -10,7 +10,6 @@ from typing import TYPE_CHECKING import numpy as np -from docstring_inheritance import NumpyDocstringInheritanceInitMeta from mne import get_config, set_config from mne import set_log_level as sll From 2c45a056992848834866bf0c1dbc4a43fc213485 Mon Sep 17 00:00:00 2001 From: Sara Sedlar Date: Thu, 19 Oct 2023 16:48:05 +0200 Subject: [PATCH 14/16] Update moabb/utils.py Change NumpyDocstringInheritanceMeta to NumpyDocstringInheritanceInitMeta class 2 Co-authored-by: PierreGtch <25532709+PierreGtch@users.noreply.github.com> --- moabb/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moabb/utils.py b/moabb/utils.py index a0303260d..e29a3529c 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -229,5 +229,5 @@ def depreciated_func(*args, **kwargs): return factory -class MoabbMetaClass(abc.ABCMeta, NumpyDocstringInheritanceMeta): +class MoabbMetaClass(abc.ABCMeta, NumpyDocstringInheritanceInitMeta): pass From 36178c57b201ba68889fbea98d85c9e24df569d3 Mon Sep 17 00:00:00 2001 From: Sara04 Date: Thu, 19 Oct 2023 17:29:38 +0200 Subject: [PATCH 15/16] Update numpy docstring class and change Attributes to Parameters --- moabb/paradigms/base.py | 4 ++-- moabb/paradigms/motor_imagery.py | 6 +++--- moabb/utils.py | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/moabb/paradigms/base.py b/moabb/paradigms/base.py index 652f2c102..a8f564312 100644 --- a/moabb/paradigms/base.py +++ b/moabb/paradigms/base.py @@ -33,7 +33,7 @@ class BaseProcessing(metaclass=MoabbMetaClass): Please use one of the child classes - Attributes + Parameters ---------- filters: list of list (defaults [[7, 35]]) @@ -474,7 +474,7 @@ def _get_events_pipeline(self, dataset): class BaseParadigm(BaseProcessing): """Base class for paradigms. - Attributes + Parameters ---------- events: List of str | None (default None) diff --git a/moabb/paradigms/motor_imagery.py b/moabb/paradigms/motor_imagery.py index 5c17d4e7c..117ff13bc 100644 --- a/moabb/paradigms/motor_imagery.py +++ b/moabb/paradigms/motor_imagery.py @@ -73,7 +73,7 @@ def scoring(self): class LeftRightImagery(BaseMotorImagery): """Motor Imagery for left hand/right hand classification. - Attributes + Parameters ----------- fmin: float (default 8) @@ -119,7 +119,7 @@ def __init__( class MotorImagery(BaseMotorImagery): """N-class Motor Imagery. - Attributes + Parameters ----------- fmin: float (default 8) @@ -202,7 +202,7 @@ def scoring(self): class FilterBankMotorImagery(MotorImagery): """Filter bank N-class motor imagery. - Attributes + Parameters ----------- n_classes: int (default number of available classes) diff --git a/moabb/utils.py b/moabb/utils.py index e29a3529c..ee300d187 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -10,6 +10,7 @@ from typing import TYPE_CHECKING import numpy as np +from docstring_inheritance import NumpyDocstringInheritanceInitMeta from mne import get_config, set_config from mne import set_log_level as sll From 55c5db6963f9fce848ed6d0fa2c6cb3ed1a65671 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 06:14:22 +0000 Subject: [PATCH 16/16] [pre-commit.ci] auto fixes from pre-commit.com hooks --- moabb/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/moabb/utils.py b/moabb/utils.py index 98a733217..d5f4fd260 100644 --- a/moabb/utils.py +++ b/moabb/utils.py @@ -1,4 +1,5 @@ """Util functions for moabb.""" + import abc import inspect import logging