From 910090d8490351cd38a0664af4488b7693dba104 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 13:56:18 +0200 Subject: [PATCH 01/23] In some places, the virtual reality dataset code was wrong. --- moabb/datasets/braininvaders.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/moabb/datasets/braininvaders.py b/moabb/datasets/braininvaders.py index 42d01ee95..83d14995c 100644 --- a/moabb/datasets/braininvaders.py +++ b/moabb/datasets/braininvaders.py @@ -150,7 +150,7 @@ def _bi_get_subject_data(ds, subject): # noqa: C901 stim[idx_nontarget] = 1 X = np.concatenate([S, stim[None, :]]) sfreq = 512 - elif ds.code == "Virtual Reality dataset": + elif ds.code == "P300-VR": data = loadmat(os.path.join(file_path, os.listdir(file_path)[0]))["data"] chnames = [ @@ -187,7 +187,7 @@ def _bi_get_subject_data(ds, subject): # noqa: C901 verbose=False, ) - if not ds.code == "Virtual Reality dataset": + if not ds.code == "P300-VR": raw = mne.io.RawArray(data=X, info=info, verbose=False) raw.set_montage(make_standard_montage("standard_1020")) @@ -388,7 +388,7 @@ def _bi_data_path( # noqa: C901 ) for i in range(1, 5) ] - elif ds.code == "Virtual Reality dataset": + elif ds.code == "P300-VR": subject_paths = [] url = "{:s}subject_{:02d}_{:s}.mat".format( VIRTUALREALITY_URL, From c12940d3e8f7245b92f083010c8e56aaa178bef4 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 14:37:08 +0200 Subject: [PATCH 02/23] fix: PC data not downloading. fix: inversion 12 blocks of 5 repetitions --- moabb/datasets/braininvaders.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/moabb/datasets/braininvaders.py b/moabb/datasets/braininvaders.py index 83d14995c..4fd2cb77f 100644 --- a/moabb/datasets/braininvaders.py +++ b/moabb/datasets/braininvaders.py @@ -1,4 +1,5 @@ import glob +from logging import warn import os import os.path as osp import shutil @@ -390,13 +391,22 @@ def _bi_data_path( # noqa: C901 ] elif ds.code == "P300-VR": subject_paths = [] - url = "{:s}subject_{:02d}_{:s}.mat".format( - VIRTUALREALITY_URL, - subject, - "VR" if ds.virtual_reality else ds.personal_computer, - ) - file_path = dl.data_path(url, "VIRTUALREALITY") - subject_paths.append(file_path) + if ds.virtual_reality: + url = "{:s}subject_{:02d}_{:s}.mat".format( + VIRTUALREALITY_URL, + subject, + "VR" + ) + file_path = dl.data_path(url, "VIRTUALREALITY") + subject_paths.append(file_path) + elif ds.personal_computer: + url = "{:s}subject_{:02d}_{:s}.mat".format( + VIRTUALREALITY_URL, + subject, + "PC" + ) + file_path = dl.data_path(url, "VIRTUALREALITY") + subject_paths.append(file_path) return subject_paths @@ -868,6 +878,8 @@ def __init__(self, virtual_reality=False, screen_display=True): self.virtual_reality = virtual_reality self.personal_computer = screen_display + if(not self.virtual_reality and not self.personal_computer): + warn("[P300-VR dataset] virtual_reality and screen display are False. No data will be downloaded, unless you change these parameters after initialization.") def _get_single_subject_data(self, subject): """return data for a single subject""" @@ -880,7 +892,7 @@ def data_path( def get_block_repetition(self, paradigm, subjects, block_list, repetition_list): """Select data for all provided subjects, blocks and repetitions. - Each subject has 5 blocks of 12 repetitions. + Each subject has 12 blocks of 5 repetitions. The returned data is a dictionary with the folowing structure:: From cd96bead84dec2a93d57ade8c3755057b96a20d6 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 15:09:11 +0200 Subject: [PATCH 03/23] push example from Pedro --- examples/vr_pc_p300_different_epoch_size.py | 97 +++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/vr_pc_p300_different_epoch_size.py diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/vr_pc_p300_different_epoch_size.py new file mode 100644 index 000000000..b3adccc4a --- /dev/null +++ b/examples/vr_pc_p300_different_epoch_size.py @@ -0,0 +1,97 @@ +from moabb.datasets import VirtualReality + +import numpy as np +import pandas as pd + +from moabb.paradigms import P300 +from pyriemann.estimation import ERPCovariances +from pyriemann.classification import MDM + +from sklearn.preprocessing import LabelEncoder +from sklearn.metrics import roc_auc_score +from sklearn.model_selection import KFold +from sklearn.pipeline import make_pipeline + +from tqdm import tqdm + +""" +============================= +Classification of the trials +============================= + +This example shows how to extract the epochs from the P300-VR dataset of a given +subject and then classify them using Riemannian Geometry framework for BCI. +We compare the scores in the VR and PC conditions, using different epoch size. + +""" +# Authors: Pedro Rodrigues +# Modified by: Gregoire Cattan +# License: BSD (3-clause) + +import warnings +warnings.filterwarnings("ignore") + +# create dataset +dataset = VirtualReality() + +# To encode classes into 0 and 1. +le = LabelEncoder().fit(["Target", "NonTarget"]) + +# get the paradigm +paradigm = P300() + +# change this to include more subjects +nsubjects = 2 + +scores_epochs = [] +for tmax in [0.2, 1.0]: + + paradigm.tmax = tmax + + scores = [] + for subject in tqdm(dataset.subject_list[:nsubjects]): + scores_subject = [tmax, subject] + + for condition in ['VR', 'PC']: + + print(f"subject {subject}, {condition}, tmax {tmax}") + + # define the dataset instance + dataset.virtual_reality = (condition == 'VR') + dataset.personal_computer = (condition == 'PC') + + # cross validate with 3-folds validation. + kf = KFold(n_splits = 3) + + # There is 12 blocks of 5 repetitions. + repetitions = [1, 2] # Select the first two repetitions. + blocks = np.arange(1, 12+1) + + auc = [] + + for train_idx, test_idx in kf.split(np.arange(12)): + + # split in training and testing blocks + X_train, y_train, _ = dataset.get_block_repetition(paradigm, [subject], blocks[train_idx], repetitions) + + X_test, y_test, _ = dataset.get_block_repetition(paradigm, [subject], blocks[test_idx], repetitions) + + pipe = make_pipeline(ERPCovariances(estimator='lwf'), MDM()) + pipe.fit(X_train, y_train) + y_pred = pipe.predict(X_test) + + y_test = le.transform(y_test) + y_pred= le.transform(y_pred) + + auc.append(roc_auc_score(y_test, y_pred)) + + # stock scores + scores_subject.append(np.mean(auc)) + + scores.append(scores_subject) + + scores_epochs.append(scores) + +print(scores_epochs) +df = pd.DataFrame(np.array(scores_epochs), columns=['tmax', 'subject', 'VR', 'PC']) +print(df) \ No newline at end of file From da628d5ffc89d2ccc420e13b562b6264b03665b1 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 15:21:34 +0200 Subject: [PATCH 04/23] fix error with datframe initialization --- examples/vr_pc_p300_different_epoch_size.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/vr_pc_p300_different_epoch_size.py index b3adccc4a..bbaac74b1 100644 --- a/examples/vr_pc_p300_different_epoch_size.py +++ b/examples/vr_pc_p300_different_epoch_size.py @@ -43,12 +43,11 @@ # change this to include more subjects nsubjects = 2 -scores_epochs = [] +scores = [] for tmax in [0.2, 1.0]: paradigm.tmax = tmax - - scores = [] + for subject in tqdm(dataset.subject_list[:nsubjects]): scores_subject = [tmax, subject] @@ -90,8 +89,5 @@ scores.append(scores_subject) - scores_epochs.append(scores) - -print(scores_epochs) -df = pd.DataFrame(np.array(scores_epochs), columns=['tmax', 'subject', 'VR', 'PC']) +df = pd.DataFrame(scores, columns=['tmax', 'subject', 'VR', 'PC']) print(df) \ No newline at end of file From c083802e09ca2049ba8e4c8d0f018be12e4b8fa8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 13:28:43 +0000 Subject: [PATCH 05/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- examples/vr_pc_p300_different_epoch_size.py | 81 +++++++++++---------- moabb/datasets/braininvaders.py | 20 ++--- 2 files changed, 48 insertions(+), 53 deletions(-) diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/vr_pc_p300_different_epoch_size.py index bbaac74b1..085499ee3 100644 --- a/examples/vr_pc_p300_different_epoch_size.py +++ b/examples/vr_pc_p300_different_epoch_size.py @@ -1,26 +1,24 @@ -from moabb.datasets import VirtualReality - import numpy as np import pandas as pd - -from moabb.paradigms import P300 -from pyriemann.estimation import ERPCovariances from pyriemann.classification import MDM - -from sklearn.preprocessing import LabelEncoder +from pyriemann.estimation import ERPCovariances from sklearn.metrics import roc_auc_score from sklearn.model_selection import KFold from sklearn.pipeline import make_pipeline - +from sklearn.preprocessing import LabelEncoder from tqdm import tqdm +from moabb.datasets import VirtualReality +from moabb.paradigms import P300 + + """ ============================= Classification of the trials ============================= This example shows how to extract the epochs from the P300-VR dataset of a given -subject and then classify them using Riemannian Geometry framework for BCI. +subject and then classify them using Riemannian Geometry framework for BCI. We compare the scores in the VR and PC conditions, using different epoch size. """ @@ -29,6 +27,8 @@ # License: BSD (3-clause) import warnings + + warnings.filterwarnings("ignore") # create dataset @@ -45,49 +45,50 @@ scores = [] for tmax in [0.2, 1.0]: + paradigm.tmax = tmax - paradigm.tmax = tmax - - for subject in tqdm(dataset.subject_list[:nsubjects]): - scores_subject = [tmax, subject] + for subject in tqdm(dataset.subject_list[:nsubjects]): + scores_subject = [tmax, subject] - for condition in ['VR', 'PC']: + for condition in ["VR", "PC"]: + print(f"subject {subject}, {condition}, tmax {tmax}") - print(f"subject {subject}, {condition}, tmax {tmax}") - - # define the dataset instance - dataset.virtual_reality = (condition == 'VR') - dataset.personal_computer = (condition == 'PC') + # define the dataset instance + dataset.virtual_reality = condition == "VR" + dataset.personal_computer = condition == "PC" # cross validate with 3-folds validation. - kf = KFold(n_splits = 3) - + kf = KFold(n_splits=3) + # There is 12 blocks of 5 repetitions. - repetitions = [1, 2] # Select the first two repetitions. - blocks = np.arange(1, 12+1) - - auc = [] + repetitions = [1, 2] # Select the first two repetitions. + blocks = np.arange(1, 12 + 1) - for train_idx, test_idx in kf.split(np.arange(12)): + auc = [] - # split in training and testing blocks - X_train, y_train, _ = dataset.get_block_repetition(paradigm, [subject], blocks[train_idx], repetitions) + for train_idx, test_idx in kf.split(np.arange(12)): + # split in training and testing blocks + X_train, y_train, _ = dataset.get_block_repetition( + paradigm, [subject], blocks[train_idx], repetitions + ) - X_test, y_test, _ = dataset.get_block_repetition(paradigm, [subject], blocks[test_idx], repetitions) + X_test, y_test, _ = dataset.get_block_repetition( + paradigm, [subject], blocks[test_idx], repetitions + ) - pipe = make_pipeline(ERPCovariances(estimator='lwf'), MDM()) - pipe.fit(X_train, y_train) - y_pred = pipe.predict(X_test) + pipe = make_pipeline(ERPCovariances(estimator="lwf"), MDM()) + pipe.fit(X_train, y_train) + y_pred = pipe.predict(X_test) - y_test = le.transform(y_test) - y_pred= le.transform(y_pred) + y_test = le.transform(y_test) + y_pred = le.transform(y_pred) - auc.append(roc_auc_score(y_test, y_pred)) + auc.append(roc_auc_score(y_test, y_pred)) - # stock scores - scores_subject.append(np.mean(auc)) + # stock scores + scores_subject.append(np.mean(auc)) - scores.append(scores_subject) + scores.append(scores_subject) -df = pd.DataFrame(scores, columns=['tmax', 'subject', 'VR', 'PC']) -print(df) \ No newline at end of file +df = pd.DataFrame(scores, columns=["tmax", "subject", "VR", "PC"]) +print(df) diff --git a/moabb/datasets/braininvaders.py b/moabb/datasets/braininvaders.py index 4fd2cb77f..7e750b3be 100644 --- a/moabb/datasets/braininvaders.py +++ b/moabb/datasets/braininvaders.py @@ -1,10 +1,10 @@ import glob -from logging import warn import os import os.path as osp import shutil import zipfile as z from distutils.dir_util import copy_tree +from logging import warn import mne import numpy as np @@ -392,19 +392,11 @@ def _bi_data_path( # noqa: C901 elif ds.code == "P300-VR": subject_paths = [] if ds.virtual_reality: - url = "{:s}subject_{:02d}_{:s}.mat".format( - VIRTUALREALITY_URL, - subject, - "VR" - ) + url = "{:s}subject_{:02d}_{:s}.mat".format(VIRTUALREALITY_URL, subject, "VR") file_path = dl.data_path(url, "VIRTUALREALITY") subject_paths.append(file_path) elif ds.personal_computer: - url = "{:s}subject_{:02d}_{:s}.mat".format( - VIRTUALREALITY_URL, - subject, - "PC" - ) + url = "{:s}subject_{:02d}_{:s}.mat".format(VIRTUALREALITY_URL, subject, "PC") file_path = dl.data_path(url, "VIRTUALREALITY") subject_paths.append(file_path) @@ -878,8 +870,10 @@ def __init__(self, virtual_reality=False, screen_display=True): self.virtual_reality = virtual_reality self.personal_computer = screen_display - if(not self.virtual_reality and not self.personal_computer): - warn("[P300-VR dataset] virtual_reality and screen display are False. No data will be downloaded, unless you change these parameters after initialization.") + if not self.virtual_reality and not self.personal_computer: + warn( + "[P300-VR dataset] virtual_reality and screen display are False. No data will be downloaded, unless you change these parameters after initialization." + ) def _get_single_subject_data(self, subject): """return data for a single subject""" From 69d73ee4c57caf5c218f15ad552aba45e848fb42 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 15:32:40 +0200 Subject: [PATCH 06/23] add whats new --- docs/source/whats_new.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/whats_new.rst b/docs/source/whats_new.rst index 05bde11a5..8098a95cc 100644 --- a/docs/source/whats_new.rst +++ b/docs/source/whats_new.rst @@ -18,12 +18,13 @@ Develop branch Enhancements ~~~~~~~~~~~~ -- None +- Add example with VirtualReality BrainInvaders dataset (:gh:`393` by `Gregoire Cattan`_ and `Pedro L. C. Rodrigues`_) Bugs ~~~~ - Restore 3 subject from Cho2017 (:gh:`392` by `Igor Carrara`_ and `Sylvain Chevallier`_) +- Correct downloading with VirtualReality BrainInvaders dataset (:gh:`393` by `Gregoire Cattan`_) API changes ~~~~~~~~~~~ From 09f6ca23281c9e3c75d53fe84911dcfa8023fd35 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 15:42:16 +0200 Subject: [PATCH 07/23] add test --- moabb/tests/datasets.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index 5d84dca57..cd3b26112 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -5,7 +5,7 @@ from moabb.datasets import Shin2017A, Shin2017B, VirtualReality from moabb.datasets.fake import FakeDataset, FakeVirtualRealityDataset from moabb.paradigms import P300 - +import pytest _ = mne.set_log_level("CRITICAL") @@ -75,6 +75,10 @@ def __init__(self, *args, **kwargs): def test_canary(self): assert VirtualReality() is not None + + def test_warning_if_parameters_false(self): + with pytest.warns(): + VirtualReality(virtual_reality=False, screen_display=False) def test_get_block_repetition(self): ds = FakeVirtualRealityDataset() From e53c883ec962bbd42ae3200c52c054719816fbd1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 13:42:35 +0000 Subject: [PATCH 08/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- moabb/tests/datasets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index cd3b26112..a83a0b85d 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -1,11 +1,12 @@ import unittest import mne +import pytest from moabb.datasets import Shin2017A, Shin2017B, VirtualReality from moabb.datasets.fake import FakeDataset, FakeVirtualRealityDataset from moabb.paradigms import P300 -import pytest + _ = mne.set_log_level("CRITICAL") @@ -75,7 +76,7 @@ def __init__(self, *args, **kwargs): def test_canary(self): assert VirtualReality() is not None - + def test_warning_if_parameters_false(self): with pytest.warns(): VirtualReality(virtual_reality=False, screen_display=False) From a3ee57c86943e8ce1d6433e2bfa6d46934ec9c4c Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 15:50:29 +0200 Subject: [PATCH 09/23] fix pytest/unittest --- moabb/tests/datasets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index cd3b26112..ae3e5ab89 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -5,7 +5,6 @@ from moabb.datasets import Shin2017A, Shin2017B, VirtualReality from moabb.datasets.fake import FakeDataset, FakeVirtualRealityDataset from moabb.paradigms import P300 -import pytest _ = mne.set_log_level("CRITICAL") @@ -77,7 +76,7 @@ def test_canary(self): assert VirtualReality() is not None def test_warning_if_parameters_false(self): - with pytest.warns(): + with self.assertWarns(UserWarning): VirtualReality(virtual_reality=False, screen_display=False) def test_get_block_repetition(self): From a402bd3a71021011cd25747cadd0d4450191f74b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 13:52:50 +0000 Subject: [PATCH 10/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- moabb/tests/datasets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index 82e4eb25e..9c5704e2e 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -6,6 +6,7 @@ from moabb.datasets.fake import FakeDataset, FakeVirtualRealityDataset from moabb.paradigms import P300 + _ = mne.set_log_level("CRITICAL") From 3e9405d1afe1ad484567efc6dfd3a4fac9d3462c Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 15:58:18 +0200 Subject: [PATCH 11/23] replace logging by warnings library --- moabb/datasets/braininvaders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moabb/datasets/braininvaders.py b/moabb/datasets/braininvaders.py index 7e750b3be..7d459c0df 100644 --- a/moabb/datasets/braininvaders.py +++ b/moabb/datasets/braininvaders.py @@ -4,7 +4,7 @@ import shutil import zipfile as z from distutils.dir_util import copy_tree -from logging import warn +from warnings import warn import mne import numpy as np From 6695995f6a5bb197c57afb04c564b1adcb485c03 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 16:24:38 +0200 Subject: [PATCH 12/23] move docstring to the top --- examples/vr_pc_p300_different_epoch_size.py | 27 ++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/vr_pc_p300_different_epoch_size.py index 085499ee3..82fbf6462 100644 --- a/examples/vr_pc_p300_different_epoch_size.py +++ b/examples/vr_pc_p300_different_epoch_size.py @@ -1,17 +1,3 @@ -import numpy as np -import pandas as pd -from pyriemann.classification import MDM -from pyriemann.estimation import ERPCovariances -from sklearn.metrics import roc_auc_score -from sklearn.model_selection import KFold -from sklearn.pipeline import make_pipeline -from sklearn.preprocessing import LabelEncoder -from tqdm import tqdm - -from moabb.datasets import VirtualReality -from moabb.paradigms import P300 - - """ ============================= Classification of the trials @@ -26,6 +12,19 @@ # Modified by: Gregoire Cattan # License: BSD (3-clause) +import numpy as np +import pandas as pd +from pyriemann.classification import MDM +from pyriemann.estimation import ERPCovariances +from sklearn.metrics import roc_auc_score +from sklearn.model_selection import KFold +from sklearn.pipeline import make_pipeline +from sklearn.preprocessing import LabelEncoder +from tqdm import tqdm + +from moabb.datasets import VirtualReality +from moabb.paradigms import P300 + import warnings From 370c05ff2a6c8a5a711974416e3eec69ae3614d0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 16:18:44 +0000 Subject: [PATCH 13/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- examples/vr_pc_p300_different_epoch_size.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/vr_pc_p300_different_epoch_size.py index 82fbf6462..79dcdad7c 100644 --- a/examples/vr_pc_p300_different_epoch_size.py +++ b/examples/vr_pc_p300_different_epoch_size.py @@ -12,6 +12,8 @@ # Modified by: Gregoire Cattan # License: BSD (3-clause) +import warnings + import numpy as np import pandas as pd from pyriemann.classification import MDM @@ -25,8 +27,6 @@ from moabb.datasets import VirtualReality from moabb.paradigms import P300 -import warnings - warnings.filterwarnings("ignore") From 7e47a466bc2f656b0b579869ccae728565d72d0d Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 20:11:50 +0200 Subject: [PATCH 14/23] test completed --- moabb/datasets/braininvaders.py | 2 +- moabb/tests/datasets.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/moabb/datasets/braininvaders.py b/moabb/datasets/braininvaders.py index 7d459c0df..cfe32b67b 100644 --- a/moabb/datasets/braininvaders.py +++ b/moabb/datasets/braininvaders.py @@ -395,7 +395,7 @@ def _bi_data_path( # noqa: C901 url = "{:s}subject_{:02d}_{:s}.mat".format(VIRTUALREALITY_URL, subject, "VR") file_path = dl.data_path(url, "VIRTUALREALITY") subject_paths.append(file_path) - elif ds.personal_computer: + if ds.personal_computer: url = "{:s}subject_{:02d}_{:s}.mat".format(VIRTUALREALITY_URL, subject, "PC") file_path = dl.data_path(url, "VIRTUALREALITY") subject_paths.append(file_path) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index 9c5704e2e..d1b138d58 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -5,6 +5,7 @@ from moabb.datasets import Shin2017A, Shin2017B, VirtualReality from moabb.datasets.fake import FakeDataset, FakeVirtualRealityDataset from moabb.paradigms import P300 +from moabb.tests.util_braindecode import data _ = mne.set_log_level("CRITICAL") @@ -80,6 +81,13 @@ def test_warning_if_parameters_false(self): with self.assertWarns(UserWarning): VirtualReality(virtual_reality=False, screen_display=False) + def test_data_path(self): + ds = VirtualReality(virtual_reality=True, screen_display=True) + data_path = ds.data_path(1) + assert len(data_path) == 2 + assert 'subject_01_VR.mat' in data_path[0] + assert 'subject_01_VPC.mat' in data_path[1] + def test_get_block_repetition(self): ds = FakeVirtualRealityDataset() subject = 5 From 183d35428d78961b18525f333eb321a3bfa04ff8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 18:14:31 +0000 Subject: [PATCH 15/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- moabb/tests/datasets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index d1b138d58..c59366884 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -85,8 +85,8 @@ def test_data_path(self): ds = VirtualReality(virtual_reality=True, screen_display=True) data_path = ds.data_path(1) assert len(data_path) == 2 - assert 'subject_01_VR.mat' in data_path[0] - assert 'subject_01_VPC.mat' in data_path[1] + assert "subject_01_VR.mat" in data_path[0] + assert "subject_01_VPC.mat" in data_path[1] def test_get_block_repetition(self): ds = FakeVirtualRealityDataset() From ac1ed245399b25e58d263b3181646bb28ec9019e Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 20:20:22 +0200 Subject: [PATCH 16/23] leftover --- moabb/tests/datasets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index d1b138d58..99eecab1d 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -5,7 +5,6 @@ from moabb.datasets import Shin2017A, Shin2017B, VirtualReality from moabb.datasets.fake import FakeDataset, FakeVirtualRealityDataset from moabb.paradigms import P300 -from moabb.tests.util_braindecode import data _ = mne.set_log_level("CRITICAL") From 6b5dc5f8c554f9b4d3048e3b8cb09e6849eae83c Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Wed, 31 May 2023 20:28:28 +0200 Subject: [PATCH 17/23] typo >< --- moabb/tests/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moabb/tests/datasets.py b/moabb/tests/datasets.py index 28746ba86..daa66b40d 100644 --- a/moabb/tests/datasets.py +++ b/moabb/tests/datasets.py @@ -85,7 +85,7 @@ def test_data_path(self): data_path = ds.data_path(1) assert len(data_path) == 2 assert "subject_01_VR.mat" in data_path[0] - assert "subject_01_VPC.mat" in data_path[1] + assert "subject_01_PC.mat" in data_path[1] def test_get_block_repetition(self): ds = FakeVirtualRealityDataset() From 4d21fe4ffbe33d9b967bc350ca18aad6287bd429 Mon Sep 17 00:00:00 2001 From: gcattan Date: Thu, 1 Jun 2023 11:23:57 +0200 Subject: [PATCH 18/23] Update examples/vr_pc_p300_different_epoch_size.py Co-authored-by: Sylvain Chevallier --- examples/vr_pc_p300_different_epoch_size.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/vr_pc_p300_different_epoch_size.py index 79dcdad7c..1519e7a9e 100644 --- a/examples/vr_pc_p300_different_epoch_size.py +++ b/examples/vr_pc_p300_different_epoch_size.py @@ -1,6 +1,6 @@ """ ============================= -Classification of the trials +Changing epoch size in P300 VR dataset ============================= This example shows how to extract the epochs from the P300-VR dataset of a given From 367a98f189b9dee6bd273669ab26c77a3670561d Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Thu, 1 Jun 2023 11:25:00 +0200 Subject: [PATCH 19/23] rename into plot_vr_pc_p300_different_epoch_size.py --- ...rent_epoch_size.py => plot_vr_pc_p300_different_epoch_size.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{vr_pc_p300_different_epoch_size.py => plot_vr_pc_p300_different_epoch_size.py} (100%) diff --git a/examples/vr_pc_p300_different_epoch_size.py b/examples/plot_vr_pc_p300_different_epoch_size.py similarity index 100% rename from examples/vr_pc_p300_different_epoch_size.py rename to examples/plot_vr_pc_p300_different_epoch_size.py From 7d5644e18daaf40db9c7c2cf7fec21a5c2d42ea8 Mon Sep 17 00:00:00 2001 From: Gregoire Cattan Date: Fri, 2 Jun 2023 10:52:45 +0200 Subject: [PATCH 20/23] - Add figure plot - add comments --- examples/plot_vr_pc_p300_different_epoch_size.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/plot_vr_pc_p300_different_epoch_size.py b/examples/plot_vr_pc_p300_different_epoch_size.py index 1519e7a9e..b86ed516e 100644 --- a/examples/plot_vr_pc_p300_different_epoch_size.py +++ b/examples/plot_vr_pc_p300_different_epoch_size.py @@ -7,6 +7,8 @@ subject and then classify them using Riemannian Geometry framework for BCI. We compare the scores in the VR and PC conditions, using different epoch size. +This example demonstrates the use of `get_block_repetition`, which allows +to specify the experimental blocks and repetitions for analysis. """ # Authors: Pedro Rodrigues # Modified by: Gregoire Cattan @@ -65,8 +67,14 @@ auc = [] + # split in training and testing blocks, and fit/predict. + # This loop will run 3 times as we are using a 3-folds validation for train_idx, test_idx in kf.split(np.arange(12)): - # split in training and testing blocks + + # Note the use of the `get_block_repetition` method, + # to select the appropriate number of blocks and repetitions: + # - 8 blocks for training, 4 for testing + # - only the first two repetitions inside each blocks X_train, y_train, _ = dataset.get_block_repetition( paradigm, [subject], blocks[train_idx], repetitions ) @@ -90,4 +98,7 @@ scores.append(scores_subject) df = pd.DataFrame(scores, columns=["tmax", "subject", "VR", "PC"]) + print(df) + +df.groupby('tmax').mean().plot(y=['VR','PC'], title='Mean AUC as a function of the epoch size') From ea0f1fe9b27575d35b833b8cdebf652c8f70afc9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 08:53:44 +0000 Subject: [PATCH 21/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- examples/plot_vr_pc_p300_different_epoch_size.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/plot_vr_pc_p300_different_epoch_size.py b/examples/plot_vr_pc_p300_different_epoch_size.py index b86ed516e..0fe28906c 100644 --- a/examples/plot_vr_pc_p300_different_epoch_size.py +++ b/examples/plot_vr_pc_p300_different_epoch_size.py @@ -70,7 +70,6 @@ # split in training and testing blocks, and fit/predict. # This loop will run 3 times as we are using a 3-folds validation for train_idx, test_idx in kf.split(np.arange(12)): - # Note the use of the `get_block_repetition` method, # to select the appropriate number of blocks and repetitions: # - 8 blocks for training, 4 for testing @@ -101,4 +100,6 @@ print(df) -df.groupby('tmax').mean().plot(y=['VR','PC'], title='Mean AUC as a function of the epoch size') +df.groupby("tmax").mean().plot( + y=["VR", "PC"], title="Mean AUC as a function of the epoch size" +) From f360bf7071fe5e4b762004cd70ce9fd84cc8222b Mon Sep 17 00:00:00 2001 From: gcattan Date: Wed, 7 Jun 2023 21:12:10 +0200 Subject: [PATCH 22/23] Update plot_vr_pc_p300_different_epoch_size.py --- .../plot_vr_pc_p300_different_epoch_size.py | 76 +++++++++++++++---- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/examples/plot_vr_pc_p300_different_epoch_size.py b/examples/plot_vr_pc_p300_different_epoch_size.py index 0fe28906c..4bb179d0e 100644 --- a/examples/plot_vr_pc_p300_different_epoch_size.py +++ b/examples/plot_vr_pc_p300_different_epoch_size.py @@ -32,44 +32,76 @@ warnings.filterwarnings("ignore") -# create dataset -dataset = VirtualReality() - -# To encode classes into 0 and 1. -le = LabelEncoder().fit(["Target", "NonTarget"]) +############################################################################### +# Initialization +# --------------- +# +# 1) Create an instance of the dataset. +# 2) Create an instance of a P300 paradigm. +# By default filtering between 1-24 Hz +# with epochs of length 1s. +# In this example we will be modifying the length of the epochs, by +# changing the `tmax` attribute of the paradigm. +# 3) Encode categorical variable (Target/NonTarget) to numerical values. +# We will be using label encoding. -# get the paradigm +dataset = VirtualReality() paradigm = P300() +le = LabelEncoder().fit(["Target", "NonTarget"]) # change this to include more subjects nsubjects = 2 +############################################################################### +# Validation +# --------------- +# +# We will perform a 3-folds validation for each combination of +# tmax, subjects and experimental conditions (VR or PC). +# +# Not all the data will be used for this validation. +# The VirtualReality dataset contains the data from a randomized experiment. +# We will only be using the two first repetitions of the 12 experimental blocks. +# Data will be selected thanks to the `get_block_repetition` method. + +# Contains the score for all combination of tmax, subjects +# and experimental condition (VR or PC). scores = [] + +# Init 3-folds validation. +kf = KFold(n_splits=3) + +# Select the first two repetitions. +repetitions = [1, 2] + +# Generate all possible arrangement with the 12 blocks. +blocks = np.arange(1, 12 + 1) + +# run validation for each combination. for tmax in [0.2, 1.0]: paradigm.tmax = tmax for subject in tqdm(dataset.subject_list[:nsubjects]): + + # Note: here we are adding `tmax` to scores_subject, + # although `tmax` is defined outside the scope of this inner loop. + # The reason behind is to facilitate the conversion from array to dataframe at the end. scores_subject = [tmax, subject] for condition in ["VR", "PC"]: print(f"subject {subject}, {condition}, tmax {tmax}") - # define the dataset instance + # Rather than creating a new instance depending on the condition, + # let's change the attribute value to download the correct data. dataset.virtual_reality = condition == "VR" dataset.personal_computer = condition == "PC" - # cross validate with 3-folds validation. - kf = KFold(n_splits=3) - - # There is 12 blocks of 5 repetitions. - repetitions = [1, 2] # Select the first two repetitions. - blocks = np.arange(1, 12 + 1) - auc = [] - # split in training and testing blocks, and fit/predict. + # Split in training and testing blocks, and fit/predict. # This loop will run 3 times as we are using a 3-folds validation for train_idx, test_idx in kf.split(np.arange(12)): + # Note the use of the `get_block_repetition` method, # to select the appropriate number of blocks and repetitions: # - 8 blocks for training, 4 for testing @@ -82,13 +114,17 @@ paradigm, [subject], blocks[test_idx], repetitions ) + # We use riemannian geometry processing technics with MDM algorithm. pipe = make_pipeline(ERPCovariances(estimator="lwf"), MDM()) pipe.fit(X_train, y_train) y_pred = pipe.predict(X_test) + # y_test and y_pred contains categorical variable (Target/NonTarget). + # To use a metric, we need to convert target information to numerical values. y_test = le.transform(y_test) y_pred = le.transform(y_pred) + # We use the roc_auc_score, which is a reliable metric for multi-class problem. auc.append(roc_auc_score(y_test, y_pred)) # stock scores @@ -96,10 +132,18 @@ scores.append(scores_subject) +############################################################################### +# Display of the data +# --------------- +# +# Let's transform or array to a dataframe. +# We can then print it on the console, and +# plot the mean AUC as a function of the epoch length. + df = pd.DataFrame(scores, columns=["tmax", "subject", "VR", "PC"]) print(df) df.groupby("tmax").mean().plot( - y=["VR", "PC"], title="Mean AUC as a function of the epoch size" + y=["VR", "PC"], title="Mean AUC as a function of the epoch length" ) From 7007b1ba8dad9ad4812b7e929059a3b271291195 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 19:12:36 +0000 Subject: [PATCH 23/23] [pre-commit.ci] auto fixes from pre-commit.com hooks --- examples/plot_vr_pc_p300_different_epoch_size.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/plot_vr_pc_p300_different_epoch_size.py b/examples/plot_vr_pc_p300_different_epoch_size.py index 4bb179d0e..236f2bd84 100644 --- a/examples/plot_vr_pc_p300_different_epoch_size.py +++ b/examples/plot_vr_pc_p300_different_epoch_size.py @@ -58,7 +58,7 @@ # # We will perform a 3-folds validation for each combination of # tmax, subjects and experimental conditions (VR or PC). -# +# # Not all the data will be used for this validation. # The VirtualReality dataset contains the data from a randomized experiment. # We will only be using the two first repetitions of the 12 experimental blocks. @@ -82,7 +82,6 @@ paradigm.tmax = tmax for subject in tqdm(dataset.subject_list[:nsubjects]): - # Note: here we are adding `tmax` to scores_subject, # although `tmax` is defined outside the scope of this inner loop. # The reason behind is to facilitate the conversion from array to dataframe at the end. @@ -101,7 +100,6 @@ # Split in training and testing blocks, and fit/predict. # This loop will run 3 times as we are using a 3-folds validation for train_idx, test_idx in kf.split(np.arange(12)): - # Note the use of the `get_block_repetition` method, # to select the appropriate number of blocks and repetitions: # - 8 blocks for training, 4 for testing @@ -124,7 +122,7 @@ y_test = le.transform(y_test) y_pred = le.transform(y_pred) - # We use the roc_auc_score, which is a reliable metric for multi-class problem. + # We use the roc_auc_score, which is a reliable metric for multi-class problem. auc.append(roc_auc_score(y_test, y_pred)) # stock scores @@ -137,7 +135,7 @@ # --------------- # # Let's transform or array to a dataframe. -# We can then print it on the console, and +# We can then print it on the console, and # plot the mean AUC as a function of the epoch length. df = pd.DataFrame(scores, columns=["tmax", "subject", "VR", "PC"])